Intersect
The Intersect module computes geometric intersections between meshes. All intersection computations are geometrically and topologically exact, using exact arithmetic.
import * as tf from "@polydera/trueform";
Overview
The Intersect module computes intersection geometry without modifying the input meshes:
- Mesh-mesh intersections: Curves where two or more meshes intersect
- Self-intersections: Curves where a mesh intersects itself
Curves are returned as Curves objects with paths (an OffsetBlockedBuffer of index sequences) and points (an NDArrayFloat32 of coordinates).
Supported Input
Intersection computation supports a wide range of input geometry:
- Open and closed meshes — boundaries are handled correctly
- Non-manifold edges — edges shared by 3 or more faces
- Coplanar faces — overlapping faces from the same or different meshes
- Self-intersecting geometry — meshes that intersect themselves are detected and curves are extracted
- Crossing intersection curves — where curves from different mesh pairs meet on a face, crossings can be resolved. Configured via the
IntersectOptsinterface — see Intersection Configuration.
tf.selfIntersectionCurves.Intersection Configuration
The IntersectOpts interface controls intersection computation. It maps to the C++ tf::intersect_config (mode + tolerance) extended with the contour-crossing flags.
interface IntersectOpts {
mode?: "sos" | "primitives";
tolerance?: number;
resolveCrossings?: boolean;
resolveSelfCrossings?: boolean;
within?: boolean;
}
| Field | Description |
|---|---|
mode | "sos" (Simulation of Simplicity — fast, no degenerate cases) or "primitives" (handles shared edges/vertices/coplanar faces). |
tolerance | World-coordinate distance an input vertex may move to reach the lattice (default 0, exact). |
resolveCrossings | Crossings between contours of different classes — (A,B) against (A,C). Such a pair needs a third mesh to exist, so the pipeline derives this from the number of operands; the flag is declarative. |
resolveSelfCrossings | Crossings within one contour class (A,B): a contour with itself, or with another contour of the same pair — e.g. two disjoint components of one mesh cutting the same face. |
within | Also intersect each mesh with itself. Required when a mesh can self-overlap, e.g. meshes concatenated into one input; implies self-crossing resolution. Applies to arrangements and booleans only — intersectionCurves ignores it; for a mesh against itself use selfIntersectionCurves. Default false. |
Tolerance
A non-zero tolerance is a statement about the INPUT, not about a predicate: it is the pitch the input's planes are quantized to. Every face's plane — its direction and its offset — is rounded onto a grid of that pitch, so two faces whose planes differ by less than it get one plane; every vertex is then moved, by at most the tolerance, onto a lattice point of the quantized planes its own faces stand on — the meet of three at a corner, a line of two on a crease, its own tangent plane where the surface is smooth — and the result is the EXACT arrangement of that moved mesh: every predicate below the placement runs exact. Two features closer than the tolerance therefore meet only when their quantized planes agree and the placement puts them on the same lattice point: a weld is identity, not proximity, and one form's rim is never dragged onto another's wall for being near it.
const { mesh, tagLabels, faceLabels } = tf.meshArrangements(
[mesh0, mesh1], { tolerance: 1e-6 });
A tolerance of 0 is the identity: nothing moves, no placement table is built, and the result is the exact arrangement of the input as given.
Each function sets appropriate defaults — see individual function documentation below and in Arrangement.
Intersection Curves
Between Two Meshes
const curves = tf.intersectionCurves(mesh0, mesh1);
const curves = tf.intersectionCurves(mesh0, mesh1, { mode: "primitives" });
Default: mode: "primitives", resolveCrossings: false, resolveSelfCrossings: false. With two meshes every contour is of the one class (A,B); crossings among them — e.g. from disjoint components of one mesh — are resolved by resolveSelfCrossings or within.
N-Mesh Intersection Curves
Compute all pairwise intersection curves from an array of meshes:
const curves = tf.intersectionCurves([mesh0, mesh1, mesh2]);
const curves = tf.intersectionCurves([mesh0, mesh1, mesh2], {
mode: "primitives", resolveCrossings: true,
});
Default: mode: "primitives", resolveCrossings: true (for 3+ meshes), resolveSelfCrossings: false.
Self-Intersection Curves
Find where a mesh intersects itself:
const curves = tf.selfIntersectionCurves(mesh);
const curves = tf.selfIntersectionCurves(mesh, { mode: "primitives" });
Default: mode: "primitives", resolveCrossings: true, resolveSelfCrossings: true.
tf.polygonArrangements from the Arrangement module.With Transformations
mesh1.transformation = tf.makeTranslation([5, 0, 0]);
const curves = tf.intersectionCurves(mesh0, mesh1);
Using Curves
for (let i = 0; i < curves.length; i++) {
const pathIds = curves.paths.at(i);
// Access points: curves.points
}
Async
All intersect functions are available as async variants via tf.async for off-main-thread execution:
const curves = await tf.async.intersectionCurves(mesh0, mesh1);
const self = await tf.async.selfIntersectionCurves(mesh);
