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.