Meshing
Renderers, STL and glTF files, and FEM need triangles. BRepMesh_IncrementalMesh triangulates each face and stores the result in the shape; BRep_Tool.Triangulation reads it back.
flowchart LR
shape[TopoDS_Shape] -->|BRepMesh_IncrementalMesh| stored["a Poly_Triangulation<br/>on each face"]
stored -->|"BRep_Tool.Triangulation(face, location)"| read["nodes + triangles<br/>in the face's coordinates"]
read -->|"location, orientation"| buffers["vertex and index buffers"]
stored --> stl["StlAPI_Writer"]
stored --> gltf["RWGltf_CafWriter"]
stored --> view["AIS_Shape<br/><i>shows it, meshes if missing</i>"]
Triangulating
// 0.1: how far a triangle may stray from the surface; 0.5 rad: how far its normals may turn
var mesh = new BRepMesh_IncrementalMesh(sphere, 0.1, false, 0.5, true); // true: in parallel
var done = mesh.IsDone();
| Parameter | Means |
|---|---|
| linear deflection | the largest distance between a triangle and the surface, in model units |
| relative | true: the deflection is a fraction of each edge's size |
| angular deflection | the largest angle, in radians, between neighbouring triangles' normals on curved faces |
| parallel | mesh faces on all cores |
The deflection trades accuracy for size: halving it roughly doubles the triangles on curved faces. For rendering, a deflection of about 0.1% of the model's size looks smooth.
Meshing again
new BRepMesh_IncrementalMesh(sphere, 1.0);
var coarse = Triangles(sphere);
// the triangulation stays on the shape: meshing again with a finer deflection refines it,
// a coarser one keeps what's there. BRepTools.Clean drops it.
new BRepMesh_IncrementalMesh(sphere, 0.01);
var fine = Triangles(sphere);
BRepTools.Clean(sphere);
var cleaned = Triangles(sphere); // 0
Reading the triangles
Each face's nodes are in the face's own coordinates: apply the location BRep_Tool.Triangulation writes. A reversed face points its triangles the other way: swap two indices to keep normals outward.
// one vertex and index list for the whole shape, as a renderer wants it
var vertices = new List<gp_Pnt>();
var indices = new List<int>();
foreach (var item in new TopExp_Explorer(shape, TopAbs_ShapeEnum.TopAbs_FACE))
{
var face = TopoDS.Face(item);
var location = new TopLoc_Location();
var triangulation =
BRep_Tool.Triangulation(face, location); // writes the face's location into it
if (triangulation is null)
{
continue;
}
// the nodes are in the face's own coordinates: move them where the face is
var trsf = location.Transformation();
var offset = vertices.Count;
foreach (var node in triangulation.NodesToArray()) // one native call for all nodes
{
vertices.Add(node.Transformed(trsf));
}
// a reversed face's triangles turn the other way
var reversed = face.Orientation() == TopAbs_Orientation.TopAbs_REVERSED;
foreach (var triangle in triangulation.TrianglesToArray())
{
int n1 = 0, n2 = 0, n3 = 0;
triangle.Get(ref n1, ref n2, ref n3); // node numbers from 1
indices.Add(offset + n1 - 1);
indices.Add(offset + (reversed ? n3 : n2) - 1);
indices.Add(offset + (reversed ? n2 : n3) - 1);
}
}
NodesToArray() and TrianglesToArray() copy everything in one native call; Node(i) and Triangle(i) cost a call each. With BRepLib_ToolTriangulatedShape.ComputeNormals(face, triangulation) the triangulation gets normals, read with Normal(i).
Note
Edges have their own polygons on the triangulation (BRep_Tool.PolygonOnTriangulation), which line up with the faces' nodes: use them to draw edges that match the shading.
Writing triangles
STL: see Files. glTF and OBJ write XCAF documents, with colors and names: see Files.