Table of Contents

Modeling

Every modeling algorithm is a builder: input in the constructor (or through Add and Set...), Build(), the result from Shape().

stateDiagram-v2
    direction LR
    [*] --> Configured: new Builder(input)
    Configured --> Configured: Add(...), Set...(...)
    Configured --> Done: Build() succeeds
    Configured --> Failed: Build() fails
    Done --> [*]: Shape(), Modified(), Generated()
    Failed --> [*]: IsDone() false, Error() says why

Shape() builds first if needed; on a failed builder it throws StdFail_NotDone. Check IsDone() where failure is possible, see Errors.

Primitives

var z = new gp_Ax2(new gp_Pnt(0, 0, 0), new gp_Dir(0, 0, 1));

var box = new BRepPrimAPI_MakeBox(new gp_Pnt(-5, -5, 0), 10, 10, 10)
  .Shape();                                                    // corner, then sizes
var cylinder = new BRepPrimAPI_MakeCylinder(z, 5, 20).Shape(); // axis, radius, height
var cone = new BRepPrimAPI_MakeCone(z, 5, 2, 10).Shape();      // two radii, height
var sphere = new BRepPrimAPI_MakeSphere(new gp_Pnt(0, 0, 0), 5).Shape();
var torus = new BRepPrimAPI_MakeTorus(z, 10, 2).Shape();      // two radii
var wedge = new BRepPrimAPI_MakeWedge(10, 10, 10, 5).Shape(); // a box with a narrower top

BRepPrimAPI_MakeBox also names its faces (TopFace(), BottomFace(), FrontFace(), BackFace(), LeftFace(), RightFace()), handy for picking a face to fillet, shell or cut.

Sweeps

Builder Sweeps Result from a face
BRepPrimAPI_MakePrism along a vector (or infinitely along a direction) a solid
BRepPrimAPI_MakeRevol about an axis, a full turn or an angle a solid
BRepOffsetAPI_MakePipe along a wire a solid
BRepOffsetAPI_MakePipeShell wires along a wire, with control of the profile's orientation (SetMode) a shell, MakeSolid() closes it
BRepOffsetAPI_ThruSections through a series of wires (a loft) a solid or a shell

Sweeping a vertex gives an edge, an edge a face, a wire a shell, a face a solid.

// a profile: a 10 x 4 rectangle in the XZ plane, 20 away from the Z axis
var profile = new BRepBuilderAPI_MakeFace(new BRepBuilderAPI_MakePolygon(
                                              new gp_Pnt(20, 0, 0), new gp_Pnt(30, 0, 0),
                                              new gp_Pnt(30, 0, 4), new gp_Pnt(20, 0, 4), true)
                                            .Wire()).Face();

// extruded along a vector, and revolved a full turn about Z (a ring)
var bar = new BRepPrimAPI_MakePrism(profile, new gp_Vec(0, 50, 0)).Shape();
var ring =
  new BRepPrimAPI_MakeRevol(profile, new gp_Ax1(new gp_Pnt(0, 0, 0), new gp_Dir(0, 0, 1)))
    .Shape();

// swept along a path: an arc through three points
var arc = new GC_MakeArcOfCircle(new gp_Pnt(25, 0, 2), new gp_Pnt(45, 20, 2),
                                 new gp_Pnt(65, 0, 2)).Value();
var spine = new BRepBuilderAPI_MakeWire(new BRepBuilderAPI_MakeEdge(arc).Edge()).Wire();
var circle = new BRepBuilderAPI_MakeWire(new BRepBuilderAPI_MakeEdge(
                                           new GC_MakeCircle(
                                             new gp_Ax2(new gp_Pnt(25, 0, 2),
                                                        new gp_Dir(0, 1, 0)),
                                             1.5).Value()).Edge()).Wire();
var pipe = new BRepOffsetAPI_MakePipe(spine, new BRepBuilderAPI_MakeFace(circle).Face())
  .Shape();

// lofted through sections: a square that turns into a circle
var loft = new BRepOffsetAPI_ThruSections(true); // true: a solid
loft.AddWire(new BRepBuilderAPI_MakePolygon(new gp_Pnt(-5, -5, 0), new gp_Pnt(5, -5, 0),
                                            new gp_Pnt(5, 5, 0), new gp_Pnt(-5, 5, 0), true)
               .Wire());
loft.AddWire(new BRepBuilderAPI_MakeWire(new BRepBuilderAPI_MakeEdge(
                                           new GC_MakeCircle(
                                             new gp_Ax2(new gp_Pnt(0, 0, 20),
                                                        new gp_Dir(0, 0, 1)),
                                             4).Value()).Edge()).Wire());
var transition = loft.Shape();

Booleans

var fused = new BRepAlgoAPI_Fuse(box, sphere).Shape();    // box ∪ sphere
var common = new BRepAlgoAPI_Common(box, sphere).Shape(); // box ∩ sphere
var cut = new BRepAlgoAPI_Cut(box, sphere).Shape();       // box − sphere: the eight corners

// Section gives the intersection curves as edges
var section = new BRepAlgoAPI_Section(box, sphere).Shape();
Builder Result
BRepAlgoAPI_Fuse the union
BRepAlgoAPI_Common the intersection
BRepAlgoAPI_Cut the first less the second
BRepAlgoAPI_Section the intersection edges
BRepAlgoAPI_Splitter the arguments split by the tools, all pieces kept

With many tools, one operation is faster and more robust than a chain of them. The empty constructor takes lists and options:

// several tools at once: one cut drills all four holes
var plate = new BRepPrimAPI_MakeBox(100, 60, 10).Shape();

var arguments = new TopTools_ListOfShape();
arguments.Append(plate);
var tools = new TopTools_ListOfShape();
foreach (var (x, y) in new[] { (10, 10), (90, 10), (10, 50), (90, 50) })
{
  tools.Append(
    new BRepPrimAPI_MakeCylinder(new gp_Ax2(new gp_Pnt(x, y, -1), new gp_Dir(0, 0, 1)), 3, 12)
      .Shape());
}

var cut = new BRepAlgoAPI_Cut();
cut.SetArguments(arguments);
cut.SetTools(tools);
cut.SetFuzzyValue(1e-5); // tolerate near-coincident faces
cut.Build();
if (cut.HasErrors())
{
  throw new InvalidOperationException("the cut failed");
}

var drilled = cut.Shape();
Option Does
SetFuzzyValue(tolerance) treats gaps and overlaps below the tolerance as touching
SetRunParallel(true) uses all cores
SetNonDestructive(true) leaves the input shapes unchanged; by default their tolerances may grow
SetGlue(...) a faster path for arguments that only touch or share whole faces
SimplifyResult() merges faces and edges on the same surface afterwards

History

Builders tell what became of each input sub-shape, to follow a face through a sequence of operations:

flowchart LR
    input["an input sub-shape"] -->|"Modified(s)"| modified["what it became:<br/>split, trimmed, moved"]
    input -->|"Generated(s)"| generated["what it gave rise to:<br/>a swept edge's face, a fillet's face"]
    input -->|"IsDeleted(s)"| deleted["true if nothing of it is left"]
var top = maker.TopFace(); // the box's face at z = 20
var cut = new BRepAlgoAPI_Cut(box, hole);

var topAfter = cut.Modified(top);   // the top face with a hole in it
var fromHole = cut.Generated(hole); // nothing: a boolean modifies faces, it doesn't sweep them
var deleted = cut.IsDeleted(top);   // false: the top face is still there, modified

Modified and Generated return a TopTools_ListOfShape: empty when nothing applies.

Fillets and chamfers

// round the four vertical edges only: those whose ends differ in z alone
var fillet = new BRepFilletAPI_MakeFillet(box);
var edges = new TopTools_IndexedMapOfShape();
TopExp.MapShapes(box, TopAbs_ShapeEnum.TopAbs_EDGE, edges);
foreach (var shape in edges)
{
  var edge = TopoDS.Edge(shape);
  var start = BRep_Tool.Pnt(TopExp.FirstVertex(edge));
  var end = BRep_Tool.Pnt(TopExp.LastVertex(edge));
  if (Math.Abs(start.X() - end.X()) < 1e-9 && Math.Abs(start.Y() - end.Y()) < 1e-9)
  {
    fillet.Add(3, edge);
  }
}

var rounded = fillet.Shape();

// chamfer the edges of the top face by 1: the maker names the box's faces
var chamfer = new BRepFilletAPI_MakeChamfer(box);
foreach (var edge in new TopExp_Explorer(maker.TopFace(), TopAbs_ShapeEnum.TopAbs_EDGE))
{
  chamfer.Add(1, TopoDS.Edge(edge));
}

var chamfered = chamfer.Shape();

Add(r1, r2, edge) makes a fillet whose radius varies from r1 to r2 along the edge. Edges that meet tangentially join one contour, NbContours() counts them. If one contour fails, IsDone() is false; NbFaultyContours() and FaultyContour(i) tell which.

Offsets and shells

// hollow the box to 2 thick walls, open at the top
var removed = new TopTools_ListOfShape();
removed.Append(maker.TopFace());
var thick = new BRepOffsetAPI_MakeThickSolid();
thick.MakeThickSolidByJoin(box, removed, -2, 1e-3); // negative: the walls grow inwards
var tray = thick.Shape();
Builder Does
BRepOffsetAPI_MakeThickSolid hollows a solid, removing faces to open it
BRepOffsetAPI_MakeOffsetShape offsets every face of a shape (PerformByJoin)
BRepOffsetAPI_MakeOffset offsets a planar wire within its plane

Transformations

var trsf = new gp_Trsf();
trsf.SetRotation(new gp_Ax1(new gp_Pnt(0, 0, 0), new gp_Dir(0, 0, 1)), Math.PI / 4);

// Moved shares the geometry and only sets a location: cheap
var placed = box.Moved(new TopLoc_Location(trsf));

// BRepBuilderAPI_Transform copies (true) the geometry, and handles scaling too
var scale = new gp_Trsf();
scale.SetScale(new gp_Pnt(0, 0, 0), 2);
var doubled = new BRepBuilderAPI_Transform(box, scale, true).Shape();
To Use Geometry
place a shape (rotation, translation) shape.Moved(location), shape.Located(location) shared
transform with uniform scale or mirror BRepBuilderAPI_Transform(shape, trsf, true) copied
scale unevenly BRepBuilderAPI_GTransform with a gp_GTrsf converted to B-splines
copy a shape to change it separately BRepBuilderAPI_Copy copied

Moved composes with the shape's current location, Located replaces it.