Table of Contents

Analysis and repair

Properties

// volume properties: Mass() is the volume (density 1), with centre of mass and inertia
var volume = new GProp_GProps();
BRepGProp.VolumeProperties(box, volume);
var centre = volume.CentreOfMass();     // (5, 10, 15)
var inertia = volume.MatrixOfInertia(); // about the centre of mass

// surface properties: Mass() is the area; linear properties: the length of the edges
var surface = new GProp_GProps();
BRepGProp.SurfaceProperties(box, surface);
var linear = new GProp_GProps();
BRepGProp.LinearProperties(box, linear, true); // true: each shared edge once, 12 not 24
Function Mass() is For
BRepGProp.VolumeProperties the volume solids
BRepGProp.SurfaceProperties the area faces, shells, solids
BRepGProp.LinearProperties the length edges, wires

GProp_GProps also gives CentreOfMass(), MatrixOfInertia(), MomentOfInertia(axis) and PrincipalProperties(). Results assume density 1: multiply by your material's density.

Bounding boxes

// Bnd_Box is a struct: BRepBndLib fills it through a ref
var fast = new Bnd_Box();
BRepBndLib.Add(sphere, ref fast); // quick, may be larger than the shape

var tight = new Bnd_Box();
BRepBndLib.AddOptimal(sphere, ref tight, false, false); // exact, slower
var min = tight.CornerMin();                            // (-10, -10, -10)
var max = tight.CornerMax();                            // (10, 10, 10)

BRepBndLib.Add is fast and may overestimate; it uses the triangulation where there is one. AddOptimal is exact.

Distances

var extrema = new BRepExtrema_DistShapeShape(a, b);
var gap = extrema.Value();          // 10: from x = 10 to the sphere at x = 20
var onA = extrema.PointOnShape1(1); // the closest points, numbered from 1
var onB = extrema.PointOnShape2(1);

BRepExtrema_DistShapeShape works on any two shapes: vertices, edges, faces, solids. NbSolution() counts the pairs of closest points, SupportOnShape1(i) tells which sub-shape each lies on. Value() is 0 for touching or intersecting shapes, and for a shape inside a solid (InnerSolution() is then true).

Inside or outside

var inside =
  new BRepClass3d_SolidClassifier(box, new gp_Pnt(5, 5, 5), 1e-7).State(); // TopAbs_IN
var onFace =
  new BRepClass3d_SolidClassifier(box, new gp_Pnt(5, 5, 10), 1e-7).State(); // TopAbs_ON
var outside =
  new BRepClass3d_SolidClassifier(box, new gp_Pnt(5, 5, 20), 1e-7).State(); // TopAbs_OUT

For many points on one solid, construct the classifier once with the solid and call Perform(point, tolerance) for each.

Checking and repairing

Shapes from files, especially other systems' IGES and STEP, may have gaps, wrong tolerances or reversed faces. Algorithms given such shapes fail or produce garbage; check and repair first:

flowchart LR
    input[shape from a file] --> check{"BRepCheck_Analyzer<br/>IsValid()"}
    check -->|valid| use[use it]
    check -->|invalid| fix["ShapeFix_Shape<br/>tolerances, orientation, wires"]
    loose[loose faces] --> sew["BRepBuilderAPI_Sewing<br/>joins them into shells"]
    sew --> fix
    fix --> unify["ShapeUpgrade_UnifySameDomain<br/>merges split faces"]
    unify --> use

Six loose faces sewn into a shell, made a solid, fixed:

// sewing joins faces along edges that lie within the tolerance of each other
var sewing = new BRepBuilderAPI_Sewing(1e-6);
foreach (var face in faces)
{
  sewing.Add(face);
}

sewing.Perform();
var shell = TopoDS.Shell(sewing.SewedShape());

// a solid from the closed shell; ShapeFix_Shape repairs what's left, orientation included
var solid = new BRepBuilderAPI_MakeSolid(shell).Solid();
var fix = new ShapeFix_Shape(solid);
fix.Perform();
var fixedSolid = fix.Shape();

var valid = new BRepCheck_Analyzer(fixedSolid).IsValid();

ShapeFix_Shape runs the fixes of ShapeFix_Solid, ShapeFix_Shell, ShapeFix_Face, ShapeFix_Wire and ShapeFix_Edge as needed; each can also be run on its own for control over what changes. ShapeAnalysis_* classes report problems without changing anything.

Merging faces

Booleans leave faces split where the inputs met, even on one surface:

// two boxes side by side fuse into one solid, still with the seam's split faces
var fused = new BRepAlgoAPI_Fuse(left, right).Shape(); // 10 faces

// merge faces (and edges) that lie on the same surface
var unify = new ShapeUpgrade_UnifySameDomain(fused, true, true, false);
unify.Build();
var merged = unify.Shape(); // 6 faces, a 20 x 10 x 10 box

// booleans do the same when asked
var fuse = new BRepAlgoAPI_Fuse(left, right);
fuse.SimplifyResult();
var simplified = fuse.Shape(); // 6 faces