Skip to main content

Modeling basics

CadFlow models exact boundary-representation geometry through an explicit Model session. Most parts follow the same sequence:

primitive or profile → feature → boolean → transform → inspect → export

Units and coordinates

The modern frontend accepts plain numeric values and requires the caller to use one consistent unit system. Millimetres are conventional in the repository examples:

WIDTH_MM = 80.0
DEPTH_MM = 50.0
THICKNESS_MM = 8.0

The world frame is right-handed with +Z as the default construction axis. A box starts at the origin and extends in positive X, Y, and Z. A cylinder uses +Z unless it is rotated.

Keep one unit system

CadFlow does not silently convert raw numeric arguments in Model. If a workflow uses millimetres, keep geometry, tolerances, deflections, and validation thresholds in millimetres as well.

Create primitives

with cad.Model() as model:
block = model.box(width=80, depth=50, height=8)
pin = model.cylinder(radius=6, height=20)
ball = model.sphere(radius=10)
taper = model.cone(radius1=12, radius2=6, height=25)

Primitives return Shape handles in the same model session.

Build profiles and features

Turn a closed wire into a face, then extrude it:

with cad.Model() as model:
outline = model.polyline(
((0, 0, 0), (40, 0, 0), (40, 25, 0), (0, 25, 0)),
closed=True,
)
face = model.face(outline)
body = model.extrude(face, 0, 0, 6)

Other feature operations include:

  • revolve(profile, degrees, axis, origin)
  • loft(profiles, solid=True, ruled=False)
  • sweep(profile, path, solid=True, frenet=False)
  • fillet(shape, radius, edges=[...])
  • chamfer(shape, distance, edges=[...])
  • shell(shape, thickness, faces=[...])

For non-planar work, bezier_surface, fit_surface, ruled_surface, filling_surface, and gordon_surface remain native operations.

Combine and remove material

Booleans operate on shapes owned by the same model:

with cad.Model() as model:
base = model.box(80, 50, 8)
boss = model.translate(model.cylinder(14, 14), 40, 25, 6)
body = model.union(base, boss)

bore = model.translate(model.cylinder(5, 20), 40, 25, 4)
body = model.cut(body, bore)

assert body.validate().ok
assert body.topology["solids"] == 1

union, cut, and intersect perform exact OCCT booleans in the full backend. Check that the operation changed the intended metric when correctness matters:

before = body.volume
result = model.cut(body, tool)
if result.volume >= before:
raise RuntimeError("cut did not remove material")

Transform shapes

Transforms return new shapes; they do not mutate the input:

moved = model.translate(shape, x=10, y=0, z=5)
turned = model.rotate(moved, degrees=90, axis=(0, 1, 0))
paired = model.mirror(turned, normal=(1, 0, 0))
scaled = model.scale(paired, factor=0.5, center=(0, 0, 0))

This functional style makes intermediate geometry inspectable and keeps feature construction replayable.

Select topology deliberately

The native frontend exposes deterministic zero-based face handles with model.faces(shape) and indexed selection for fillet, chamfer, and shell. Query topology before relying on an index:

print(body.topology)
report = model.preflight("fillet", body, 2.0, edges=[0, 3])
if report.ok:
rounded = model.fillet(body, 2.0, edges=[0, 3])
else:
print(report.to_dict())

Index selection is appropriate inside a controlled feature history. For durable references across edits and replay, use the compatibility layer's semantic tags and selectors.