Modules | TS

Arrangement

Exact mesh arrangements and polygon arrangements.

The Arrangement module splits meshes along intersection curves, labeling every output face with its provenance. It builds on the Intersect module for computing intersections. All operations are geometrically and topologically exact.

import * as tf from "@polydera/trueform";

Overview

The Arrangement module provides operations at several levels:

  • Mesh arrangements: Decompose two or more meshes along their mutual intersection curves — the complete intersection problem
  • Polygon arrangements: Decompose a mesh at its self-intersection curves

All arrangement operations return faceLabels — an array mapping each output face back to the index of the original face it came from in the source mesh. This enables attribute transfer and provenance tracking. Multi-mesh arrangements additionally return tagLabels — which input mesh each face belongs to.

All arrangement operations support an optional { returnCurves: true } option that additionally returns the intersection curves.

To split a mesh along the level sets of a scalar field, see the Iso module.

Supported Input

Embedding and arrangement operations inherit the same robustness as the Intersect module:

  • Open and closed meshes — boundaries are handled correctly
  • Non-manifold edges — edges shared by 3 or more faces
  • Coplanar faces — overlapping faces are classified
  • Self-intersecting geometry — detected and resolved
  • Crossing intersection curves — where curves from different mesh pairs meet on a face, crossings can be resolved. Configured via IntersectOpts — see Intersection Configuration.
To detect where a single mesh's own polygons intersect each other, use tf.polygonArrangements.

Mesh Arrangements

Decompose intersecting meshes along their intersection curves:

const { mesh, tagLabels, faceLabels } = tf.meshArrangements([mesh0, mesh1]);

// With curves
const { mesh, tagLabels, faceLabels, curves } = tf.meshArrangements(
  [mesh0, mesh1], { returnCurves: true });

// With explicit mode
const { mesh, tagLabels, faceLabels } = tf.meshArrangements(
  [mesh0, mesh1, mesh2], { mode: "primitives", resolveCrossings: true });

// With tolerance — recover the intended topology on inputs that carry
// float-precision drift. See Intersection Configuration.
const { mesh, tagLabels, faceLabels } = tf.meshArrangements(
  [mesh0, mesh1], { tolerance: 1e-6 });

// Quality-refine the cut surface (Ruppert refinement with negotiated
// boundary splits); shared loop boundaries stay watertight by construction.
const { mesh, tagLabels, faceLabels } = tf.meshArrangements(
  [mesh0, mesh1], { triangulation: "refinedCdt" });

Returns:

  • tagLabels: Which input mesh each face came from — its index in the input array (0 … N-1)
  • faceLabels: Index of the original face each output face came from

Default: mode: "primitives", tolerance: 0 (exact), resolveCrossings auto (true for 3+ meshes, false for 2), resolveSelfCrossings: false, within: false (set it when a mesh can self-overlap, e.g. meshes concatenated into one input), triangulation: "cdt" (plain constrained Delaunay per cut loop; "refinedCdt" quality-refines the cut surface). See Intersection Configuration.

Polygon Arrangements

Decompose a single mesh at its self-intersection curves:

const { mesh: split, faceLabels } = tf.polygonArrangements(mesh);

// With curves
const { mesh: split, faceLabels, curves } = tf.polygonArrangements(mesh, {
  returnCurves: true,
});

// Quality-refine the cut surface
const { mesh: split, faceLabels } = tf.polygonArrangements(mesh, {
  triangulation: "refinedCdt",
});

Default: mode: "primitives", resolveCrossings: true, resolveSelfCrossings: true, triangulation: "cdt" ("refinedCdt" quality-refines the cut surface).

Boolean Operations

tf.booleanUnion, tf.booleanIntersection and tf.booleanDifference are the two-operand case of the CSG arrangement and live in the CSG module.

Async

All arrangement functions are available as async variants via tf.async, with the same call shapes:

const { mesh, tagLabels, faceLabels } = await tf.async.meshArrangements([mesh0, mesh1]);
const { mesh, tagLabels, faceLabels, curves } = await tf.async.meshArrangements(
  [mesh0, mesh1], { returnCurves: true });
const { mesh: split, faceLabels } = await tf.async.polygonArrangements(mesh);
For implementation details, see the C++ Arrangement documentation.