Examples

Parts, and the code that made them

Every part below was built with the blacksmith and written out by it. The code on the left is the whole program, in the language of your choice; the files on the right are what it wrote, to open in your own CAD or in the viewer. The STEP is the kernel's own, exact; the meshes are the reader's tessellation of it at its default tolerance.

from cadaclysm_blacksmith import Axis, Profile, Selector, Workplane

plate = Workplane.xy().extrude(Profile.rect(120, 80), 14).solid()
boss = (Workplane.from_solid(plate)
        .faces(Selector.max(Axis.Z)).workplane()
        .extrude(Profile.circle(22), 26).solid())
part = plate.join(boss)

bore = Workplane.xy().extrude(Profile.circle(11), 60).solid().translate(0, 0, -10)
part = part.cut(bore)

# The plate's four vertical corners: the lines along Z between two planes
# (the boss has vertical seams too, but those lie on its cylinder).
corners = [e for e in part.edges
           if e.is_line and abs(e.direction[2]) > 0.99
           and all(part.face_kind(f) == "plane" for f in e.faces)]
part = part.fillet(corners, 12)
part.step("plate.stp")
using Cadaclysm.Blacksmith;

using var plate = Workplane.Xy().Extrude(Profile.Rect(120, 80), 14).Solid();
using var boss = Workplane.FromSolid(plate)
    .Faces(Selector.Max(Axis.Z)).OnFace()
    .Extrude(Profile.Circle(22), 26).Solid();
using var joined = plate.Join(boss);

using var bore = Workplane.Xy().Extrude(Profile.Circle(11), 60).Solid().Translate(0, 0, -10);
using var bored = joined.Cut(bore);

// The plate's four vertical corners: the lines along Z between two planes
// (the boss has vertical seams too, but those lie on its cylinder).
var corners = bored.Edges.Where(e => e.IsLine && Math.Abs(e.Direction![2]) > 0.99
                                     && e.Faces.All(f => bored.FaceKind(f) == "plane"));
using var part = bored.Fillet(corners, 12);
part.Step("plate.stp");
package main

import (
	"log"
	"math"

	"github.com/rdeioris/cadaclysm-sdk/go/blacksmith"
)

func must[T any](v T, err error) T {
	if err != nil {
		log.Fatal(err)
	}
	return v
}

func main() {
	plate := must(blacksmith.XY().Extrude(must(blacksmith.Rect(120, 80)), 14).Solid())
	defer plate.Close()
	boss := must(blacksmith.FromSolid(plate).
		Faces(blacksmith.Max(blacksmith.AxisZ)).OnFace().
		Extrude(must(blacksmith.Circle(22)), 26).Solid())
	defer boss.Close()
	joined := must(plate.Join(boss, blacksmith.DefaultTolerance))
	defer joined.Close()

	bore := must(must(blacksmith.XY().Extrude(must(blacksmith.Circle(11)), 60).Solid()).Translate(0, 0, -10))
	defer bore.Close()
	bored := must(joined.Cut(bore, blacksmith.DefaultTolerance))
	defer bored.Close()

	// The plate's four vertical corners: the lines along Z between two planes
	// (the boss has vertical seams too, but those lie on its cylinder).
	var corners []int
	for _, e := range must(bored.Edges()) {
		d, ok := e.Direction()
		if !ok || math.Abs(d[2]) <= 0.99 {
			continue
		}
		planes := true
		for _, f := range e.Faces {
			planes = planes && must(bored.FaceKind(f)) == "plane"
		}
		if planes {
			corners = append(corners, e.Index)
		}
	}
	part := must(bored.Fillet(corners, 12, blacksmith.FilletTolerance))
	defer part.Close()
	if err := part.Step("plate.stp", "", "mm"); err != nil {
		log.Fatal(err)
	}
}
import java.util.Arrays;

public class Plate {
    public static void main(String[] args) {
        try (var plate = Blacksmith.Workplane.xy().extrude(Blacksmith.Profile.rect(120, 80), 14).solid();
             var boss = Blacksmith.Workplane.fromSolid(plate)
                     .faces(Blacksmith.Selector.max(Blacksmith.Axis.Z)).onFace()
                     .extrude(Blacksmith.Profile.circle(22), 26).solid();
             var joined = plate.join(boss);
             var bore = Blacksmith.Workplane.xy().extrude(Blacksmith.Profile.circle(11), 60).solid().translate(0, 0, -10);
             var bored = joined.cut(bore)) {
            // The plate's four vertical corners: the lines along Z between two planes
            // (the boss has vertical seams too, but those lie on its cylinder).
            var corners = bored.edges().stream()
                    .filter(e -> e.isLine() && Math.abs(e.direction()[2]) > 0.99)
                    .filter(e -> Arrays.stream(e.faces()).allMatch(f -> bored.faceKind(f).equals("plane")))
                    .toList();
            try (var part = bored.fillet(corners, 12)) {
                part.step("plate.stp");
            }
        }
    }
}
const { Axis, Profile, Selector, Workplane } = require('cadaclysm/blacksmith');

const plate = Workplane.xy().extrude(Profile.rect(120, 80), 14).solid();
const boss = Workplane.fromSolid(plate)
  .faces(Selector.max(Axis.Z)).workplane()
  .extrude(Profile.circle(22), 26).solid();
let part = plate.join(boss);

const bore = Workplane.xy().extrude(Profile.circle(11), 60).solid().translate(0, 0, -10);
part = part.cut(bore);

// The plate's four vertical corners: the lines along Z between two planes
// (the boss has vertical seams too, but those lie on its cylinder).
const corners = part.edges().filter((e) => e.isLine && Math.abs(e.direction[2]) > 0.99
  && e.faces.every((f) => part.faceKind(f) === 'plane'));
part = part.fillet(corners, 12);
part.step('plate.stp');
use cadaclysm_sdk::blacksmith::{Axis, Profile, Selector, Unit, Workplane, DEFAULT_TOLERANCE, FILLET_TOLERANCE};

fn main() -> cadaclysm_sdk::Result<()> {
    let plate = Workplane::xy().extrude(&Profile::rect(120.0, 80.0)?, 14.0)?.solid()?;
    let boss = Workplane::from_solid(&plate)
        .faces(&Selector::Max(Axis::Z))?
        .on_face()?
        .extrude(&Profile::circle(22.0)?, 26.0)?
        .solid()?;
    let joined = plate.join(&boss, DEFAULT_TOLERANCE)?;

    let bore = Workplane::xy().extrude(&Profile::circle(11.0)?, 60.0)?.solid()?.translate(0.0, 0.0, -10.0)?;
    let bored = joined.cut(&bore, DEFAULT_TOLERANCE)?;

    // The plate's four vertical corners: the lines along Z between two planes
    // (the boss has vertical seams too, but those lie on its cylinder).
    let mut corners = Vec::new();
    for edge in bored.edges()? {
        let vertical = edge.direction().is_some_and(|d| d[2].abs() > 0.99);
        let mut planes = true;
        for &face in &edge.faces {
            planes = planes && bored.face_kind(face)? == "plane";
        }
        if vertical && planes {
            corners.push(edge.index);
        }
    }
    let part = bored.fillet(&corners, 12.0, FILLET_TOLERANCE)?;
    part.step("plate.stp", None, Unit::Millimetre)
}
import Blacksmith

let plate = try Workplane.xy().extrude(Profile.rect(120, 80), 14).solid()
let boss = try Workplane.fromSolid(plate)
    .faces(.max(.z)).workplane()
    .extrude(Profile.circle(22), 26).solid()
var part = try plate.join(boss)

let bore = try Workplane.xy().extrude(Profile.circle(11), 60).solid().translate(0, 0, -10)
part = try part.cut(bore)

// The plate's four vertical corners: the lines along Z between two planes
// (the boss has vertical seams too, but those lie on its cylinder).
let corners = try part.edges.filter { e in
    guard let d = e.direction, abs(d.z) > 0.99 else { return false }
    return try e.faces.allSatisfy { try part.faceKind($0) == "plane" }
}
part = try part.fillet(corners, 12)
try part.step("plate.stp")
local bs = require("cadaclysm_blacksmith")
local Axis, Profile, Selector, Workplane = bs.Axis, bs.Profile, bs.Selector, bs.Workplane

local plate = Workplane.xy():extrude(Profile.rect(120, 80), 14):solid()
local boss = Workplane.from_solid(plate)
  :faces(Selector.max(Axis.Z)):workplane()
  :extrude(Profile.circle(22), 26):solid()
local part = plate:join(boss)

local bore = Workplane.xy():extrude(Profile.circle(11), 60):solid():translate(0, 0, -10)
part = part:cut(bore)

-- The plate's four vertical corners: the lines along Z between two planes
-- (the boss has vertical seams too, but those lie on its cylinder).
local function between_planes(edge)
  for _, f in ipairs(edge.faces) do
    if part:face_kind(f) ~= "plane" then return false end
  end
  return true
end
local corners = {}
for _, e in ipairs(part.edges) do
  if e.is_line and math.abs(e.direction[3]) > 0.99 and between_planes(e) then
    corners[#corners + 1] = e
  end
end
part = part:fillet(corners, 12)
part:step("plate.stp")
A plate with a boss and a bore, its corners filleted Plate with a boss

Join, cut, fillet

A 120 × 80 × 14 plate, a boss joined on its top face, an 11 mm bore cut through both, the four vertical corners rounded at 12. Every face is a plane or a cylinder, the corner fillets included; the STEP says so.

from cadaclysm_blacksmith import Solid

box = Solid.cuboid(20, 20, 20)
part = box.fillet(box.edges, 2)
part.step("box-fillet-all.stp")
using Cadaclysm.Blacksmith;

using var box = Solid.Cuboid(20, 20, 20);
using var part = box.Fillet(box.Edges, 2);
part.Step("box-fillet-all.stp");
package main

import (
	"log"

	"github.com/rdeioris/cadaclysm-sdk/go/blacksmith"
)

func must[T any](v T, err error) T {
	if err != nil {
		log.Fatal(err)
	}
	return v
}

func main() {
	box := must(blacksmith.Cuboid(20, 20, 20))
	defer box.Close()
	edges := blacksmith.EdgeIndices(must(box.Edges()))
	part := must(box.Fillet(edges, 2, blacksmith.FilletTolerance))
	defer part.Close()
	if err := part.Step("box-fillet-all.stp", "", "mm"); err != nil {
		log.Fatal(err)
	}
}
public class BoxFilletAll {
    public static void main(String[] args) {
        try (var box = Blacksmith.Solid.cuboid(20, 20, 20);
             var part = box.fillet(box.edges(), 2)) {
            part.step("box-fillet-all.stp");
        }
    }
}
const { Solid } = require('cadaclysm/blacksmith');

const box = Solid.cuboid(20, 20, 20);
const part = box.fillet(box.edges(), 2);
part.step('box-fillet-all.stp');
use cadaclysm_sdk::blacksmith::{Solid, Unit, FILLET_TOLERANCE};

fn main() -> cadaclysm_sdk::Result<()> {
    let block = Solid::cuboid(20.0, 20.0, 20.0)?;
    let edges: Vec<u32> = block.edges()?.iter().map(|e| e.index).collect();
    let part = block.fillet(&edges, 2.0, FILLET_TOLERANCE)?;
    part.step("box-fillet-all.stp", None, Unit::Millimetre)
}
import Blacksmith

let box = try Solid.cuboid(20, 20, 20)
let part = try box.fillet(box.edges, 2)
try part.step("box-fillet-all.stp")
local Solid = require("cadaclysm_blacksmith").Solid

local box = Solid.cuboid(20, 20, 20)
local part = box:fillet(box.edges, 2)
part:step("box-fillet-all.stp")
A cube with every edge rounded Rounded box

Fillet every edge

A 20 mm cube with its twelve edges rounded at 2 in one call, which is the whole of the program. The twelve bands are cylinders and the eight corners where three of them meet are patches of a sphere.

from cadaclysm_blacksmith import Solid

box = Solid.cuboid(20, 20, 20)
part = box.chamfer(box.edges, 2)
part.step("box-chamfer-all.stp")
using Cadaclysm.Blacksmith;

using var box = Solid.Cuboid(20, 20, 20);
using var part = box.Chamfer(box.Edges, 2);
part.Step("box-chamfer-all.stp");
package main

import (
	"log"

	"github.com/rdeioris/cadaclysm-sdk/go/blacksmith"
)

func must[T any](v T, err error) T {
	if err != nil {
		log.Fatal(err)
	}
	return v
}

func main() {
	box := must(blacksmith.Cuboid(20, 20, 20))
	defer box.Close()
	edges := blacksmith.EdgeIndices(must(box.Edges()))
	part := must(box.Chamfer(edges, 2, blacksmith.FilletTolerance))
	defer part.Close()
	if err := part.Step("box-chamfer-all.stp", "", "mm"); err != nil {
		log.Fatal(err)
	}
}
public class BoxChamferAll {
    public static void main(String[] args) {
        try (var box = Blacksmith.Solid.cuboid(20, 20, 20);
             var part = box.chamfer(box.edges(), 2)) {
            part.step("box-chamfer-all.stp");
        }
    }
}
const { Solid } = require('cadaclysm/blacksmith');

const box = Solid.cuboid(20, 20, 20);
const part = box.chamfer(box.edges(), 2);
part.step('box-chamfer-all.stp');
use cadaclysm_sdk::blacksmith::{Solid, Unit, FILLET_TOLERANCE};

fn main() -> cadaclysm_sdk::Result<()> {
    let block = Solid::cuboid(20.0, 20.0, 20.0)?;
    let edges: Vec<u32> = block.edges()?.iter().map(|e| e.index).collect();
    let part = block.chamfer(&edges, 2.0, FILLET_TOLERANCE)?;
    part.step("box-chamfer-all.stp", None, Unit::Millimetre)
}
import Blacksmith

let box = try Solid.cuboid(20, 20, 20)
let part = try box.chamfer(box.edges, 2)
try part.step("box-chamfer-all.stp")
local Solid = require("cadaclysm_blacksmith").Solid

local box = Solid.cuboid(20, 20, 20)
local part = box:chamfer(box.edges, 2)
part:step("box-chamfer-all.stp")
A cube with every edge chamfered Bevelled box

Chamfer every edge

The same cube with every edge cut back 2 along both its faces. Twelve bevels and eight triangular corners, twenty-six faces in all and every one of them a plane.

from cadaclysm_blacksmith import Profile, Solid, Workplane

plate = Solid.cuboid(60, 40, 4).translate(30, 20, 2)

# Six by four holes of radius 2.5, each a short cylinder cut through the plate.
for i in range(6):
    for j in range(4):
        hole = Workplane.xy().extrude(Profile.circle(2.5), 6).solid()
        plate = plate.cut(hole.translate(7 + 9.2 * i, 7 + 8.7 * j, -1))

plate.step("plate-holes.stp")
using Cadaclysm.Blacksmith;

var plate = Solid.Cuboid(60, 40, 4).Translate(30, 20, 2);

// Six by four holes of radius 2.5, each a short cylinder cut through the plate.
for (var i = 0; i < 6; i++)
    for (var j = 0; j < 4; j++)
    {
        using var hole = Workplane.Xy().Extrude(Profile.Circle(2.5), 6).Solid();
        plate = plate.Cut(hole.Translate(7 + 9.2 * i, 7 + 8.7 * j, -1));
    }

plate.Step("plate-holes.stp");
package main

import (
	"log"

	"github.com/rdeioris/cadaclysm-sdk/go/blacksmith"
)

func must[T any](v T, err error) T {
	if err != nil {
		log.Fatal(err)
	}
	return v
}

func main() {
	plate := must(must(blacksmith.Cuboid(60, 40, 4)).Translate(30, 20, 2))

	// Six by four holes of radius 2.5, each a short cylinder cut through the plate.
	for i := 0; i < 6; i++ {
		for j := 0; j < 4; j++ {
			hole := must(blacksmith.XY().Extrude(must(blacksmith.Circle(2.5)), 6).Solid())
			moved := must(hole.Translate(7+9.2*float64(i), 7+8.7*float64(j), -1))
			plate = must(plate.Cut(moved, blacksmith.DefaultTolerance))
			hole.Close()
			moved.Close()
		}
	}

	if err := plate.Step("plate-holes.stp", "", "mm"); err != nil {
		log.Fatal(err)
	}
}
public class PlateHoles {
    public static void main(String[] args) {
        var plate = Blacksmith.Solid.cuboid(60, 40, 4).translate(30, 20, 2);

        // Six by four holes of radius 2.5, each a short cylinder cut through the plate.
        for (int i = 0; i < 6; i++) {
            for (int j = 0; j < 4; j++) {
                try (var hole = Blacksmith.Workplane.xy().extrude(Blacksmith.Profile.circle(2.5), 6).solid()) {
                    plate = plate.cut(hole.translate(7 + 9.2 * i, 7 + 8.7 * j, -1));
                }
            }
        }

        plate.step("plate-holes.stp");
    }
}
const { Profile, Solid, Workplane } = require('cadaclysm/blacksmith');

let plate = Solid.cuboid(60, 40, 4).translate(30, 20, 2);

// Six by four holes of radius 2.5, each a short cylinder cut through the plate.
for (let i = 0; i < 6; i++) {
  for (let j = 0; j < 4; j++) {
    const hole = Workplane.xy().extrude(Profile.circle(2.5), 6).solid();
    plate = plate.cut(hole.translate(7 + 9.2 * i, 7 + 8.7 * j, -1));
  }
}

plate.step('plate-holes.stp');
use cadaclysm_sdk::blacksmith::{Profile, Solid, Unit, Workplane, DEFAULT_TOLERANCE};

fn main() -> cadaclysm_sdk::Result<()> {
    let mut plate = Solid::cuboid(60.0, 40.0, 4.0)?.translate(30.0, 20.0, 2.0)?;

    // Six by four holes of radius 2.5, each a short cylinder cut through the plate.
    for i in 0..6 {
        for j in 0..4 {
            let hole = Workplane::xy().extrude(&Profile::circle(2.5)?, 6.0)?.solid()?;
            let moved = hole.translate(7.0 + 9.2 * f64::from(i), 7.0 + 8.7 * f64::from(j), -1.0)?;
            plate = plate.cut(&moved, DEFAULT_TOLERANCE)?;
        }
    }

    plate.step("plate-holes.stp", None, Unit::Millimetre)
}
import Blacksmith

var plate = try Solid.cuboid(60, 40, 4).translate(30, 20, 2)

// Six by four holes of radius 2.5, each a short cylinder cut through the plate.
for i in 0..<6 {
    for j in 0..<4 {
        let hole = try Workplane.xy().extrude(Profile.circle(2.5), 6).solid()
        plate = try plate.cut(hole.translate(7 + 9.2 * Double(i), 7 + 8.7 * Double(j), -1))
    }
}

try plate.step("plate-holes.stp")
local bs = require("cadaclysm_blacksmith")
local Profile, Solid, Workplane = bs.Profile, bs.Solid, bs.Workplane

local plate = Solid.cuboid(60, 40, 4):translate(30, 20, 2)

-- Six by four holes of radius 2.5, each a short cylinder cut through the plate.
for i = 0, 5 do
  for j = 0, 3 do
    local hole = Workplane.xy():extrude(Profile.circle(2.5), 6):solid()
    plate = plate:cut(hole:translate(7 + 9.2 * i, 7 + 8.7 * j, -1))
  end
end

plate:step("plate-holes.stp")
A flat plate with a grid of round holes Perforated plate

Cut, twenty-four times

A 60 × 40 × 4 plate with a grid of six by four holes, each a short cylinder cut in its turn from an ordinary Python loop. The solid stays closed through every cut, and the STEP carries each hole as two half-cylinders between the plate's faces.

from cadaclysm_blacksmith import Solid

box = Solid.cuboid(30, 30, 30)
hollow = box.shell(3)

# A window through the front wall, to see the void the shell left.
window = Solid.cuboid(10, 8, 10).translate(0, -15, 0)
part = hollow.cut(window)
part.step("hollow-box-window.stp")
using Cadaclysm.Blacksmith;

using var box = Solid.Cuboid(30, 30, 30);
using var hollow = box.Shell(3);

// A window through the front wall, to see the void the shell left.
using var window = Solid.Cuboid(10, 8, 10).Translate(0, -15, 0);
using var part = hollow.Cut(window);
part.Step("hollow-box-window.stp");
package main

import (
	"log"

	"github.com/rdeioris/cadaclysm-sdk/go/blacksmith"
)

func must[T any](v T, err error) T {
	if err != nil {
		log.Fatal(err)
	}
	return v
}

func main() {
	box := must(blacksmith.Cuboid(30, 30, 30))
	defer box.Close()
	hollow := must(box.Shell(3, nil, blacksmith.FilletTolerance))
	defer hollow.Close()

	// A window through the front wall, to see the void the shell left.
	window := must(must(blacksmith.Cuboid(10, 8, 10)).Translate(0, -15, 0))
	defer window.Close()
	part := must(hollow.Cut(window, blacksmith.DefaultTolerance))
	defer part.Close()
	if err := part.Step("hollow-box-window.stp", "", "mm"); err != nil {
		log.Fatal(err)
	}
}
public class HollowBoxWindow {
    public static void main(String[] args) {
        try (var box = Blacksmith.Solid.cuboid(30, 30, 30);
             var hollow = box.shell(3);
             // A window through the front wall, to see the void the shell left.
             var window = Blacksmith.Solid.cuboid(10, 8, 10).translate(0, -15, 0);
             var part = hollow.cut(window)) {
            part.step("hollow-box-window.stp");
        }
    }
}
const { Solid } = require('cadaclysm/blacksmith');

const box = Solid.cuboid(30, 30, 30);
const hollow = box.shell(3);

// A window through the front wall, to see the void the shell left.
const window = Solid.cuboid(10, 8, 10).translate(0, -15, 0);
const part = hollow.cut(window);
part.step('hollow-box-window.stp');
use cadaclysm_sdk::blacksmith::{Solid, Unit, DEFAULT_TOLERANCE, FILLET_TOLERANCE};

fn main() -> cadaclysm_sdk::Result<()> {
    let block = Solid::cuboid(30.0, 30.0, 30.0)?;
    let hollow = block.shell(3.0, &[], FILLET_TOLERANCE)?;

    // A window through the front wall, to see the void the shell left.
    let window = Solid::cuboid(10.0, 8.0, 10.0)?.translate(0.0, -15.0, 0.0)?;
    let part = hollow.cut(&window, DEFAULT_TOLERANCE)?;
    part.step("hollow-box-window.stp", None, Unit::Millimetre)
}
import Blacksmith

let box = try Solid.cuboid(30, 30, 30)
let hollow = try box.shell(3)

// A window through the front wall, to see the void the shell left.
let window = try Solid.cuboid(10, 8, 10).translate(0, -15, 0)
let part = try hollow.cut(window)
try part.step("hollow-box-window.stp")
local Solid = require("cadaclysm_blacksmith").Solid

local box = Solid.cuboid(30, 30, 30)
local hollow = box:shell(3)

-- A window through the front wall, to see the void the shell left.
local window = Solid.cuboid(10, 8, 10):translate(0, -15, 0)
local part = hollow:cut(window)
part:step("hollow-box-window.stp")
A hollow cube with a square window in one wall Hollow box

Shell, then cut

A 30 mm cube shelled to 3 mm walls, which leaves a closed void inside, and a window cut through the front wall to open it. The inner faces are the outer ones offset inwards; the window's four faces run between the two.

import math
from cadaclysm_blacksmith import Profile, Solid

# The bottle's side, a degree-3 spline in the x/z half-plane (x the radius),
# closed along the axis so the ends are capped flat.
side = [(7.238, 1.498), (9.221, 3.368), (10.868, 15.965), (7.306, 22.771),
        (1.909, 24.951), (3.059, 33.424), (3.591, 33.377), (4.0, 34.0)]
knots = [0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 6, 6, 6]
profile = (Profile.path((6, 0)).nurbs_to(side, knots, 3)
           .line_to(0, 34).line_to(0, 0).line_to(6, 0).end())

bottle = Solid.revolve(profile, ((0, 0, 0), (0, 0, 1)), 2 * math.pi)
bottle.step("revolve-bottle.stp")
using Cadaclysm.Blacksmith;

// The bottle's side, a degree-3 spline in the x/z half-plane (x the radius),
// closed along the axis so the ends are capped flat.
var side = new[] { (7.238, 1.498), (9.221, 3.368), (10.868, 15.965), (7.306, 22.771),
                   (1.909, 24.951), (3.059, 33.424), (3.591, 33.377), (4.0, 34.0) };
var knots = new double[] { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 6, 6, 6 };
using var profile = Profile.Path((6, 0)).NurbsTo(side, knots, 3)
    .LineTo(0, 34).LineTo(0, 0).LineTo(6, 0).End();

using var bottle = Solid.Revolve(profile, new double[] { 0, 0, 0, 0, 0, 1 }, 2 * Math.PI);
bottle.Step("revolve-bottle.stp");
package main

import (
	"log"
	"math"

	"github.com/rdeioris/cadaclysm-sdk/go/blacksmith"
)

func must[T any](v T, err error) T {
	if err != nil {
		log.Fatal(err)
	}
	return v
}

func main() {
	// The bottle's side, a degree-3 spline in the x/z half-plane (x the radius),
	// closed along the axis so the ends are capped flat.
	side := [][2]float64{{7.238, 1.498}, {9.221, 3.368}, {10.868, 15.965}, {7.306, 22.771},
		{1.909, 24.951}, {3.059, 33.424}, {3.591, 33.377}, {4.0, 34.0}}
	knots := []float64{0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 6, 6, 6}
	profile := must(blacksmith.NewPath(6, 0).NurbsTo(side, knots, 3, nil).
		LineTo(0, 34).LineTo(0, 0).LineTo(6, 0).End())
	defer profile.Close()

	bottle := must(blacksmith.Revolve(profile, [6]float64{0, 0, 0, 0, 0, 1}, 2*math.Pi))
	defer bottle.Close()
	if err := bottle.Step("revolve-bottle.stp", "", "mm"); err != nil {
		log.Fatal(err)
	}
}
public class RevolveBottle {
    public static void main(String[] args) {
        // The bottle's side, a degree-3 spline in the x/z half-plane (x the radius),
        // closed along the axis so the ends are capped flat.
        double[][] side = {{7.238, 1.498}, {9.221, 3.368}, {10.868, 15.965}, {7.306, 22.771},
                           {1.909, 24.951}, {3.059, 33.424}, {3.591, 33.377}, {4.0, 34.0}};
        double[] knots = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 6, 6, 6};
        try (var profile = Blacksmith.Profile.path(new double[]{6, 0}).nurbsTo(side, knots, 3)
                     .lineTo(0, 34).lineTo(0, 0).lineTo(6, 0).end();
             var bottle = Blacksmith.Solid.revolve(profile, new double[]{0, 0, 0, 0, 0, 1}, 2 * Math.PI)) {
            bottle.step("revolve-bottle.stp");
        }
    }
}
const { Profile, Solid } = require('cadaclysm/blacksmith');

// The bottle's side, a degree-3 spline in the x/z half-plane (x the radius),
// closed along the axis so the ends are capped flat.
const side = [[7.238, 1.498], [9.221, 3.368], [10.868, 15.965], [7.306, 22.771],
              [1.909, 24.951], [3.059, 33.424], [3.591, 33.377], [4.0, 34.0]];
const knots = [0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 6, 6, 6];
const profile = Profile.path([6, 0]).nurbsTo(side, knots, 3)
  .lineTo(0, 34).lineTo(0, 0).lineTo(6, 0).end();

const bottle = Solid.revolve(profile, [[0, 0, 0], [0, 0, 1]], 2 * Math.PI);
bottle.step('revolve-bottle.stp');
use std::f64::consts::PI;

use cadaclysm_sdk::blacksmith::{Path, Solid, Unit};

fn main() -> cadaclysm_sdk::Result<()> {
    // The bottle's side, a degree-3 spline in the x/z half-plane (x the radius),
    // closed along the axis so the ends are capped flat.
    let side = [[7.238, 1.498], [9.221, 3.368], [10.868, 15.965], [7.306, 22.771],
                [1.909, 24.951], [3.059, 33.424], [3.591, 33.377], [4.0, 34.0]];
    let knots = [0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 6.0, 6.0, 6.0];
    let profile = Path::begin([6.0, 0.0])?
        .nurbs_to(&side, &knots, 3, None)?
        .line_to(0.0, 34.0)?
        .line_to(0.0, 0.0)?
        .line_to(6.0, 0.0)?
        .end()?;

    let bottle = Solid::revolve(&profile, &[[0.0, 0.0, 0.0], [0.0, 0.0, 1.0]], 2.0 * PI)?;
    bottle.step("revolve-bottle.stp", None, Unit::Millimetre)
}
import Blacksmith

// The bottle's side, a degree-3 spline in the x/z half-plane (x the radius),
// closed along the axis so the ends are capped flat.
let side: [SIMD2<Double>] = [[7.238, 1.498], [9.221, 3.368], [10.868, 15.965], [7.306, 22.771],
                             [1.909, 24.951], [3.059, 33.424], [3.591, 33.377], [4.0, 34.0]]
let knots: [Double] = [0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 6, 6, 6]
let profile = try Profile.path([6, 0]).nurbsTo(side, knots, 3)
    .lineTo(0, 34).lineTo(0, 0).lineTo(6, 0).end()

let bottle = try Solid.revolve(profile, ([0, 0, 0], [0, 0, 1]), 2 * .pi)
try bottle.step("revolve-bottle.stp")
local bs = require("cadaclysm_blacksmith")
local Profile, Solid = bs.Profile, bs.Solid

-- The bottle's side, a degree-3 spline in the x/z half-plane (x the radius),
-- closed along the axis so the ends are capped flat.
local side = { { 7.238, 1.498 }, { 9.221, 3.368 }, { 10.868, 15.965 }, { 7.306, 22.771 },
               { 1.909, 24.951 }, { 3.059, 33.424 }, { 3.591, 33.377 }, { 4.0, 34.0 } }
local knots = { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 6, 6, 6 }
local profile = Profile.path({ 6, 0 }):nurbs_to(side, knots, 3)
  :line_to(0, 34):line_to(0, 0):line_to(6, 0):end_()   -- `end` is a Lua keyword

local bottle = Solid.revolve(profile, { { 0, 0, 0 }, { 0, 0, 1 } }, 2 * math.pi)
bottle:step("revolve-bottle.stp")
A bottle, turned from a spline profile Bottle

Revolve a spline

A bottle's side drawn as one degree-3 spline in the x/z half-plane, closed to the axis with three lines, and turned a full circle about Z. The side is one surface of revolution and the two caps are discs.

from cadaclysm_blacksmith import Profile, Workplane

# A closed degree-3 spline: the control points after the start, the start last.
points = [(3.427, -2.292), (12.491, -5.040), (23.139, 3.080), (14.951, 16.721),
          (1.057, 14.037), (-0.434, 4.100), (0, 0)]
knots = [0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5]
profile = Profile.path((0, 0)).nurbs_to(points, knots, 3).end()

prism = Workplane.xy().extrude(profile, 15).solid()
prism.step("spline-prism.stp")
using Cadaclysm.Blacksmith;

// A closed degree-3 spline: the control points after the start, the start last.
var points = new[] { (3.427, -2.292), (12.491, -5.040), (23.139, 3.080), (14.951, 16.721),
                     (1.057, 14.037), (-0.434, 4.100), (0.0, 0.0) };
var knots = new double[] { 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5 };
using var profile = Profile.Path((0, 0)).NurbsTo(points, knots, 3).End();

using var prism = Workplane.Xy().Extrude(profile, 15).Solid();
prism.Step("spline-prism.stp");
package main

import (
	"log"

	"github.com/rdeioris/cadaclysm-sdk/go/blacksmith"
)

func must[T any](v T, err error) T {
	if err != nil {
		log.Fatal(err)
	}
	return v
}

func main() {
	// A closed degree-3 spline: the control points after the start, the start last.
	points := [][2]float64{{3.427, -2.292}, {12.491, -5.040}, {23.139, 3.080}, {14.951, 16.721},
		{1.057, 14.037}, {-0.434, 4.100}, {0, 0}}
	knots := []float64{0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5}
	profile := must(blacksmith.NewPath(0, 0).NurbsTo(points, knots, 3, nil).End())
	defer profile.Close()

	prism := must(blacksmith.XY().Extrude(profile, 15).Solid())
	defer prism.Close()
	if err := prism.Step("spline-prism.stp", "", "mm"); err != nil {
		log.Fatal(err)
	}
}
public class SplinePrism {
    public static void main(String[] args) {
        // A closed degree-3 spline: the control points after the start, the start last.
        double[][] points = {{3.427, -2.292}, {12.491, -5.040}, {23.139, 3.080}, {14.951, 16.721},
                             {1.057, 14.037}, {-0.434, 4.100}, {0, 0}};
        double[] knots = {0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5};
        try (var profile = Blacksmith.Profile.path(new double[]{0, 0}).nurbsTo(points, knots, 3).end();
             var prism = Blacksmith.Workplane.xy().extrude(profile, 15).solid()) {
            prism.step("spline-prism.stp");
        }
    }
}
const { Profile, Workplane } = require('cadaclysm/blacksmith');

// A closed degree-3 spline: the control points after the start, the start last.
const points = [[3.427, -2.292], [12.491, -5.040], [23.139, 3.080], [14.951, 16.721],
                [1.057, 14.037], [-0.434, 4.100], [0, 0]];
const knots = [0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5];
const profile = Profile.path([0, 0]).nurbsTo(points, knots, 3).end();

const prism = Workplane.xy().extrude(profile, 15).solid();
prism.step('spline-prism.stp');
use cadaclysm_sdk::blacksmith::{Path, Unit, Workplane};

fn main() -> cadaclysm_sdk::Result<()> {
    // A closed degree-3 spline: the control points after the start, the start last.
    let points = [[3.427, -2.292], [12.491, -5.040], [23.139, 3.080], [14.951, 16.721],
                  [1.057, 14.037], [-0.434, 4.100], [0.0, 0.0]];
    let knots = [0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 5.0, 5.0, 5.0];
    let profile = Path::begin([0.0, 0.0])?.nurbs_to(&points, &knots, 3, None)?.end()?;

    let prism = Workplane::xy().extrude(&profile, 15.0)?.solid()?;
    prism.step("spline-prism.stp", None, Unit::Millimetre)
}
import Blacksmith

// A closed degree-3 spline: the control points after the start, the start last.
let points: [SIMD2<Double>] = [[3.427, -2.292], [12.491, -5.040], [23.139, 3.080], [14.951, 16.721],
                               [1.057, 14.037], [-0.434, 4.100], [0, 0]]
let knots: [Double] = [0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5]
let profile = try Profile.path([0, 0]).nurbsTo(points, knots, 3).end()

let prism = try Workplane.xy().extrude(profile, 15).solid()
try prism.step("spline-prism.stp")
local bs = require("cadaclysm_blacksmith")
local Profile, Workplane = bs.Profile, bs.Workplane

-- A closed degree-3 spline: the control points after the start, the start last.
local points = { { 3.427, -2.292 }, { 12.491, -5.040 }, { 23.139, 3.080 }, { 14.951, 16.721 },
                 { 1.057, 14.037 }, { -0.434, 4.100 }, { 0, 0 } }
local knots = { 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5 }
local profile = Profile.path({ 0, 0 }):nurbs_to(points, knots, 3):end_()

local prism = Workplane.xy():extrude(profile, 15):solid()
prism:step("spline-prism.stp")
A prism whose outline is a closed spline Spline prism

Extrude a spline

A closed degree-3 spline drawn on the XY plane and pulled up 15. Three faces: the spline's wall, exact in the STEP as the surface it is, and the two flat caps.

import math
from cadaclysm_blacksmith import Profile, Solid, SweepPath

# A full turn about Z, starting on the x axis at radius 10.
path = SweepPath.at((10, 0, 0)).arc((0, 0, 0), (0, 0, 1), 2 * math.pi)

# The profile sits at the path's start, its plane normal to the path (along +Y).
start = ((10, 0, 0), (0, 0, 1), (1, 0, 0), (0, 1, 0))
ring = Solid.sweep(Profile.circle(2), start, path)
ring.step("sweep-ring.stp")
using Cadaclysm.Blacksmith;

// A full turn about Z, starting on the x axis at radius 10.
using var path = SweepPath.At((10, 0, 0)).Arc((0, 0, 0), (0, 0, 1), 2 * Math.PI);

// The profile sits at the path's start, its plane normal to the path (along +Y).
var start = new double[] { 10, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0 };
using var ring = Solid.Sweep(Profile.Circle(2), start, path);
ring.Step("sweep-ring.stp");
package main

import (
	"log"
	"math"

	"github.com/rdeioris/cadaclysm-sdk/go/blacksmith"
)

func must[T any](v T, err error) T {
	if err != nil {
		log.Fatal(err)
	}
	return v
}

func main() {
	// A full turn about Z, starting on the x axis at radius 10.
	path := blacksmith.NewSweepPath(10, 0, 0).Arc([3]float64{0, 0, 0}, [3]float64{0, 0, 1}, 2*math.Pi)
	defer path.Close()

	// The profile sits at the path's start, its plane normal to the path (along +Y).
	start := blacksmith.Frame{10, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0}
	ring := must(blacksmith.Sweep(must(blacksmith.Circle(2)), start, path))
	defer ring.Close()
	if err := ring.Step("sweep-ring.stp", "", "mm"); err != nil {
		log.Fatal(err)
	}
}
public class SweepRing {
    public static void main(String[] args) {
        // A full turn about Z, starting on the x axis at radius 10.
        try (var path = Blacksmith.SweepPath.at(new double[]{10, 0, 0})
                     .arc(new double[]{0, 0, 0}, new double[]{0, 0, 1}, 2 * Math.PI);
             var profile = Blacksmith.Profile.circle(2)) {
            // The profile sits at the path's start, its plane normal to the path (along +Y).
            double[] start = {10, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0};
            try (var ring = Blacksmith.Solid.sweep(profile, start, path)) {
                ring.step("sweep-ring.stp");
            }
        }
    }
}
const { Profile, Solid, SweepPath } = require('cadaclysm/blacksmith');

// A full turn about Z, starting on the x axis at radius 10.
const path = SweepPath.at([10, 0, 0]).arc([0, 0, 0], [0, 0, 1], 2 * Math.PI);

// The profile sits at the path's start, its plane normal to the path (along +Y).
const start = [[10, 0, 0], [0, 0, 1], [1, 0, 0], [0, 1, 0]];
const ring = Solid.sweep(Profile.circle(2), start, path);
ring.step('sweep-ring.stp');
use std::f64::consts::PI;

use cadaclysm_sdk::blacksmith::{Frame, Profile, Solid, SweepPath, Unit};

fn main() -> cadaclysm_sdk::Result<()> {
    // A full turn about Z, starting on the x axis at radius 10.
    let path = SweepPath::at([10.0, 0.0, 0.0])?.arc([0.0, 0.0, 0.0], [0.0, 0.0, 1.0], 2.0 * PI)?;

    // The profile sits at the path's start, its plane normal to the path (along +Y).
    let start = Frame::new([10.0, 0.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0])?;
    let ring = Solid::sweep(&Profile::circle(2.0)?, &start, &path)?;
    ring.step("sweep-ring.stp", None, Unit::Millimetre)
}
import Blacksmith

// A full turn about Z, starting on the x axis at radius 10.
let path = try SweepPath.at([10, 0, 0]).arc([0, 0, 0], [0, 0, 1], 2 * .pi)

// The profile sits at the path's start, its plane normal to the path (along +Y).
let start = try Frame([10, 0, 0], [0, 0, 1], [1, 0, 0], [0, 1, 0])
let ring = try Solid.sweep(Profile.circle(2), start, path)
try ring.step("sweep-ring.stp")
local bs = require("cadaclysm_blacksmith")
local Profile, Solid, SweepPath = bs.Profile, bs.Solid, bs.SweepPath

-- A full turn about Z, starting on the x axis at radius 10.
local path = SweepPath.at({ 10, 0, 0 }):arc({ 0, 0, 0 }, { 0, 0, 1 }, 2 * math.pi)

-- The profile sits at the path's start, its plane normal to the path (along +Y).
local start = { { 10, 0, 0 }, { 0, 0, 1 }, { 1, 0, 0 }, { 0, 1, 0 } }
local ring = Solid.sweep(Profile.circle(2), start, path)
ring:step("sweep-ring.stp")
A ring swept from a circle along a circular path Swept ring

Sweep along an arc

A circle of radius 2 carried once round a circle of radius 10, the profile held normal to the path all the way. A torus, in other words, but arrived at by a sweep, whose path may equally be lines and arcs joined end to end.

from cadaclysm_blacksmith import Axis, Profile, Selector, Solid, Workplane

base = Solid.cuboid(30, 30, 5)
pillar = (Workplane.from_solid(base)
          .faces(Selector.max(Axis.Z)).workplane()
          .extrude(Profile.circle(6), 12).solid())
part = base.join(pillar)

# The joint: the one round edge at the top of the base.
top = base.bounds[1][2]
joint = [e for e in part.edges
         if not e.is_line and abs(e.segments[0][0][2] - top) < 1e-6]
part = part.fillet(joint, 2)
part.step("pillar-fillet.stp")
using Cadaclysm.Blacksmith;

using var slab = Solid.Cuboid(30, 30, 5);
using var pillar = Workplane.FromSolid(slab)
    .Faces(Selector.Max(Axis.Z)).OnFace()
    .Extrude(Profile.Circle(6), 12).Solid();
using var joined = slab.Join(pillar);

// The joint: the one round edge at the top of the base.
var top = slab.Bounds.Max[2];
var joint = joined.Edges.Where(e => !e.IsLine && Math.Abs(e.Segments[0].A[2] - top) < 1e-6);
using var part = joined.Fillet(joint, 2);
part.Step("pillar-fillet.stp");
package main

import (
	"log"
	"math"

	"github.com/rdeioris/cadaclysm-sdk/go/blacksmith"
)

func must[T any](v T, err error) T {
	if err != nil {
		log.Fatal(err)
	}
	return v
}

func main() {
	base := must(blacksmith.Cuboid(30, 30, 5))
	defer base.Close()
	pillar := must(blacksmith.FromSolid(base).
		Faces(blacksmith.Max(blacksmith.AxisZ)).OnFace().
		Extrude(must(blacksmith.Circle(6)), 12).Solid())
	defer pillar.Close()
	joined := must(base.Join(pillar, blacksmith.DefaultTolerance))
	defer joined.Close()

	// The joint: the one round edge at the top of the base.
	top := must(base.Bounds()).Max[2]
	var joint []int
	for _, e := range must(joined.Edges()) {
		if !e.IsLine() && math.Abs(e.Segments[0][0][2]-top) < 1e-6 {
			joint = append(joint, e.Index)
		}
	}
	part := must(joined.Fillet(joint, 2, blacksmith.FilletTolerance))
	defer part.Close()
	if err := part.Step("pillar-fillet.stp", "", "mm"); err != nil {
		log.Fatal(err)
	}
}
public class PillarFillet {
    public static void main(String[] args) {
        try (var base = Blacksmith.Solid.cuboid(30, 30, 5);
             var pillar = Blacksmith.Workplane.fromSolid(base)
                     .faces(Blacksmith.Selector.max(Blacksmith.Axis.Z)).onFace()
                     .extrude(Blacksmith.Profile.circle(6), 12).solid();
             var joined = base.join(pillar)) {
            // The joint: the one round edge at the top of the base.
            double top = base.bounds().max()[2];
            var joint = joined.edges().stream()
                    .filter(e -> !e.isLine() && Math.abs(e.segments()[0].a()[2] - top) < 1e-6)
                    .toList();
            try (var part = joined.fillet(joint, 2)) {
                part.step("pillar-fillet.stp");
            }
        }
    }
}
const { Axis, Profile, Selector, Solid, Workplane } = require('cadaclysm/blacksmith');

const base = Solid.cuboid(30, 30, 5);
const pillar = Workplane.fromSolid(base)
  .faces(Selector.max(Axis.Z)).workplane()
  .extrude(Profile.circle(6), 12).solid();
let part = base.join(pillar);

// The joint: the one round edge at the top of the base.
const top = base.bounds[1][2];
const joint = part.edges().filter((e) => !e.isLine && Math.abs(e.segments[0][0][2] - top) < 1e-6);
part = part.fillet(joint, 2);
part.step('pillar-fillet.stp');
use cadaclysm_sdk::blacksmith::{Axis, Profile, Selector, Solid, Unit, Workplane, DEFAULT_TOLERANCE, FILLET_TOLERANCE};

fn main() -> cadaclysm_sdk::Result<()> {
    let base = Solid::cuboid(30.0, 30.0, 5.0)?;
    let pillar = Workplane::from_solid(&base)
        .faces(&Selector::Max(Axis::Z))?
        .on_face()?
        .extrude(&Profile::circle(6.0)?, 12.0)?
        .solid()?;
    let joined = base.join(&pillar, DEFAULT_TOLERANCE)?;

    // The joint: the one round edge at the top of the base.
    let top = base.bounds()?.1[2];
    let joint: Vec<u32> = joined
        .edges()?
        .iter()
        .filter(|e| !e.is_line() && (e.segments[0][0][2] - top).abs() < 1e-6)
        .map(|e| e.index)
        .collect();
    let part = joined.fillet(&joint, 2.0, FILLET_TOLERANCE)?;
    part.step("pillar-fillet.stp", None, Unit::Millimetre)
}
import Blacksmith

let base = try Solid.cuboid(30, 30, 5)
let pillar = try Workplane.fromSolid(base)
    .faces(.max(.z)).workplane()
    .extrude(Profile.circle(6), 12).solid()
var part = try base.join(pillar)

// The joint: the one round edge at the top of the base.
let top = try base.bounds.max.z
let joint = try part.edges.filter { !$0.isLine && abs($0.segments[0].start.z - top) < 1e-6 }
part = try part.fillet(joint, 2)
try part.step("pillar-fillet.stp")
local bs = require("cadaclysm_blacksmith")
local Axis, Profile, Selector, Solid, Workplane = bs.Axis, bs.Profile, bs.Selector, bs.Solid, bs.Workplane

local base = Solid.cuboid(30, 30, 5)
local pillar = Workplane.from_solid(base)
  :faces(Selector.max(Axis.Z)):workplane()
  :extrude(Profile.circle(6), 12):solid()
local part = base:join(pillar)

-- The joint: the one round edge at the top of the base.
local top = base.bounds[2][3]
local joint = {}
for _, e in ipairs(part.edges) do
  if not e.is_line and math.abs(e.segments[1][1][3] - top) < 1e-6 then
    joint[#joint + 1] = e
  end
end
part = part:fillet(joint, 2)
part:step("pillar-fillet.stp")
A cylindrical pillar on a square base, the joint filleted Pillar on a base

Join, then fillet the joint

A round pillar raised from the top face of a 30 × 30 × 5 base and joined to it, then the circle where they meet rounded at 2. The fillet is a torus band, tangent to the base's plane on one side and to the pillar's cylinder on the other.