Table of Contents

Topology

A shape is topology (what is connected to what) over geometry (where it is): faces lie on surfaces, edges on curves, vertices at points. TopoDS holds the topology, BRep_Tool reads the geometry behind it.

The shape types

TopoDS_Shape is the base of all; each type is made of the one below:

flowchart TD
    compound["TopoDS_Compound<br/><i>any shapes, grouped</i>"]
    compsolid["TopoDS_CompSolid<br/><i>solids sharing faces</i>"]
    solid["TopoDS_Solid<br/><i>a volume bounded by shells</i>"]
    shell["TopoDS_Shell<br/><i>faces joined at edges</i>"]
    face["TopoDS_Face<br/><i>part of a surface, bounded by wires</i>"]
    wire["TopoDS_Wire<br/><i>edges joined at vertices</i>"]
    edge["TopoDS_Edge<br/><i>part of a curve</i>"]
    vertex["TopoDS_Vertex<br/><i>a point</i>"]
    compound --> compsolid --> solid --> shell --> face --> wire --> edge --> vertex

ShapeType() tells which one a TopoDS_Shape is; TopoDS.Solid, TopoDS.Face, TopoDS.Edge and so on cast to it, and throw Standard_TypeMismatch for the wrong type.

What a shape is

A TopoDS_Shape is a light value: a reference to the shared TopoDS_TShape that holds the topology, a location and an orientation. Two shapes can share the TShape and still differ:

classDiagram
    class TopoDS_Shape {
        TShape() the shared topology and geometry
        Location() TopLoc_Location, where it's placed
        Orientation() TopAbs_Orientation, FORWARD or REVERSED
    }
    class TopoDS_TShape {
        sub-shapes
        geometry via BRep_TFace, BRep_TEdge, BRep_TVertex
    }
    TopoDS_Shape --> TopoDS_TShape : refers to
var shift = new gp_Trsf();
shift.SetTranslation(new gp_Vec(100, 0, 0));
var moved = box.Moved(new TopLoc_Location(shift)); // same TShape, another location
var reversed = box.Reversed(); // same TShape and location, other orientation

var partners = box.IsPartner(moved); // true: same TShape
var same = box.IsSame(reversed);     // true: same TShape and location
var equal = box.IsEqual(reversed);   // false: the orientation differs
Compare Same TShape Same location Same orientation
IsPartner yes
IsSame yes yes
IsEqual yes yes yes

Maps and TopExp use IsSame: a face and its reversed twin are one entry.

Exploring

// the explorer visits every occurrence: each edge of a box twice, once per face using it
var occurrences = 0;
for (var explorer = new TopExp_Explorer(box, TopAbs_ShapeEnum.TopAbs_EDGE);
     explorer.More();
     explorer.Next())
{
  occurrences++;
}

// a map keeps each shape once
var edges = new TopTools_IndexedMapOfShape();
TopExp.MapShapes(box, TopAbs_ShapeEnum.TopAbs_EDGE, edges);
var unique = edges.Extent();

// foreach works too; ShapeType() tells what a TopoDS_Shape is, TopoDS.Face() casts it
var areas = new List<TopoDS_Face>();
foreach (var shape in new TopExp_Explorer(box, TopAbs_ShapeEnum.TopAbs_FACE))
{
  if (shape.ShapeType() == TopAbs_ShapeEnum.TopAbs_FACE)
  {
    areas.Add(TopoDS.Face(shape));
  }
}
Tool Gives Duplicates
TopExp_Explorer(shape, type) every sub-shape of a type, at any depth yes: once per occurrence
TopExp.MapShapes(shape, type, map) the same, into a TopTools_IndexedMapOfShape numbered from 1 no
TopoDS_Iterator(shape) the direct children only yes
TopExp.MapShapesAndAncestors each sub-shape with the shapes containing it no
// for each edge, the faces that use it
var facesOfEdge = new TopTools_IndexedDataMapOfShapeListOfShape();
TopExp.MapShapesAndAncestors(box, TopAbs_ShapeEnum.TopAbs_EDGE, TopAbs_ShapeEnum.TopAbs_FACE,
                             facesOfEdge);

var firstEdge = facesOfEdge.FindKey(1);
var neighbours = facesOfEdge.FindFromIndex(1).Extent(); // 2: a box's edges join two faces

TopExp.FirstVertex(edge), LastVertex, Vertices(edge, first, last) (fills two TopoDS_Vertex) and CommonVertex answer the usual questions about edges.

Geometry behind the topology

flowchart LR
    vertex[TopoDS_Vertex] -->|BRep_Tool.Pnt| pnt[gp_Pnt]
    edge[TopoDS_Edge] -->|BRep_Tool.Curve| curve["Geom_Curve<br/>+ range first..last"]
    edge -->|BRep_Tool.CurveOnSurface| pcurve["Geom2d_Curve<br/>on each face"]
    face[TopoDS_Face] -->|BRep_Tool.Surface| surface[Geom_Surface]
    face -->|BRep_Tool.Triangulation| mesh[Poly_Triangulation]
// BRep_Tool reads the geometry behind a vertex, an edge and a face
var point = BRep_Tool.Pnt(vertex);

double first = 0, last = 0;
var curve =
  BRep_Tool.Curve(edge, ref first, ref last); // the edge is the curve between first and last
var start = curve.Value(first);

var surface = BRep_Tool.Surface(face);
var plane = Geom_Plane.DownCast(surface); // a box's faces are planes
var tolerance = BRep_Tool.Tolerance(face);

Every sub-shape carries a tolerance: the distance within which its geometry is considered to meet its neighbours'. Tolerances grow as algorithms work; BRep_Tool.Tolerance reads them.

Tip

For evaluating a face or an edge, BRepAdaptor_Surface and BRepAdaptor_Curve apply the shape's location and bounds for you: new BRepAdaptor_Surface(face).Value(u, v).

Building bottom-up

Vertices, edges, wires, faces: each BRepBuilderAPI_Make* takes the level below.

// edges from points, a wire from edges, a face from the wire
var a = new gp_Pnt(0, 0, 0);
var b = new gp_Pnt(40, 0, 0);
var c = new gp_Pnt(40, 10, 0);
var d = new gp_Pnt(0, 10, 0);

var wire = new BRepBuilderAPI_MakeWire(new BRepBuilderAPI_MakeEdge(a, b).Edge(),
                                       new BRepBuilderAPI_MakeEdge(b, c).Edge(),
                                       new BRepBuilderAPI_MakeEdge(c, d).Edge(),
                                       new BRepBuilderAPI_MakeEdge(d, a).Edge()).Wire();
var face = new BRepBuilderAPI_MakeFace(wire).Face();

// the same rectangle in one go
var polygon = new BRepBuilderAPI_MakePolygon(a, b, c, d, true).Wire();
Builder From
BRepBuilderAPI_MakeVertex a gp_Pnt
BRepBuilderAPI_MakeEdge two points, a gp_Lin/gp_Circ, a Geom_Curve with or without a range
BRepBuilderAPI_MakeWire up to four edges, or Add edges and wires; they must connect
BRepBuilderAPI_MakePolygon points, closed with true or Close()
BRepBuilderAPI_MakeFace a planar wire, a Geom_Surface with bounds, a surface and a wire
BRepBuilderAPI_MakeShell, MakeSolid a surface; shells

Faces from wires need planar wires; for anything else build the surface first, or use BRepFill_Filling or BRepOffsetAPI_MakeFilling.

Compounds

// a compound groups shapes of any type; BRep_Builder fills it
var builder = new BRep_Builder();
var compound = new TopoDS_Compound();
builder.MakeCompound(compound);
builder.Add(compound, new BRepPrimAPI_MakeBox(10, 10, 10).Shape());
builder.Add(compound, new BRepPrimAPI_MakeSphere(new gp_Pnt(30, 0, 0), 5).Shape());

A compound is the usual result of reading a file with several shapes, and a cheap way to pass many shapes as one.