Reindex
The Reindex module provides tools for extracting, filtering, and reorganizing geometric data while maintaining referential integrity. It supports filtering by face masks, face IDs, point masks, and point IDs, with optional index map generation for downstream reindexing.
Reindexing by Mask
Filter a mesh using a boolean face mask:
import * as tf from "@polydera/trueform";
const mesh = tf.sphereMesh(1.0, 10, 10);
// Create a face mask — keep first half of faces
const faceIds = tf.arange("int32", mesh.numberOfFaces);
const mask = faceIds.lt(Math.floor(mesh.numberOfFaces / 2));
// Filter — automatically removes unreferenced points
const filtered = tf.reindexedByMask(mesh, mask);
With index maps:
const { mesh: filtered, faceMap, pointMap } = tf.reindexedByMask(mesh, mask, {
returnIndexMap: true,
});
// Use maps to reindex associated per-face or per-vertex data
const filteredFaceData = tf.reindexed(faceData, faceMap);
const filteredPointData = tf.reindexed(pointData, pointMap);
Reindexing by IDs
Extract specific faces by their IDs:
// Extract the first 5 faces
const ids = tf.arange("int32", 5);
const subset = tf.reindexedByIds(mesh, ids);
With index maps:
const { mesh: subset, faceMap, pointMap } = tf.reindexedByIds(mesh, ids, {
returnIndexMap: true,
});
Point-Based Filtering
Filter faces based on point criteria rather than face criteria. A face is kept only if all its vertices pass the filter.
Mask on Points
// Keep vertices above a height threshold (z > 0)
const heights = mesh.points.take(2, 1); // column 2 (z)
const pointMask = heights.gt(0);
// Keep only faces whose ALL vertices pass the mask
const filtered = tf.reindexedByMaskOnPoints(mesh, pointMask);
IDs on Points
// Keep only faces whose ALL vertices are in the first 20 point IDs
const pointIds = tf.arange("int32", 20);
const filtered = tf.reindexedByIdsOnPoints(mesh, pointIds);
Both point-based functions support { returnIndexMap: true } for index maps.
Applying Index Maps
Apply an existing IndexMap to reindex data:
// Apply to an NDArray (gather by keptIds)
const filteredFaceNormals = tf.reindexed(faceNormals, faceMap);
// Apply to a Mesh (re-apply face + point maps)
const remapped = tf.reindexed(mesh, faceMap, pointMap);
Concatenation
Merge multiple meshes into one. Face indices are automatically offset to reference the correct vertices in the combined point buffer.
const s1 = tf.sphereMesh(1.0, 8, 8);
const s2 = tf.sphereMesh(0.5, 6, 6);
// Variadic
const combined = tf.concatenateMeshes(s1, s2);
// Or with an array
const combined2 = tf.concatenateMeshes([s1, s2, tf.boxMesh(1, 1, 1)]);
const sphere = tf.sphereMesh(1.0, 8, 8);
const box = tf.boxMesh(1, 1, 1);
box.transformation = tf.makeTranslation(10, 0, 0);
// Box points are transformed during concatenation
const combined = tf.concatenateMeshes(sphere, box);
Split into Components
Split a mesh into separate meshes by per-face labels:
const s1 = tf.sphereMesh(1.0, 8, 8);
const s2 = tf.sphereMesh(0.5, 6, 6);
const combined = tf.concatenateMeshes(s1, s2);
// Label connected components
const cc = tf.connectedComponents(combined, "edge");
// Split by labels
const { components, labels } = tf.splitIntoComponents(combined, cc.labels);
for (let i = 0; i < components.length; i++) {
console.log(`Component ${labels[i]}: ${components[i].numberOfFaces} faces`);
}
concatenateMeshes: Multiple meshes → Single meshsplitIntoComponents: Single mesh + labels → Multiple meshes
Summary
| Function | Selects by | Operates on |
|---|---|---|
reindexedByMask | Boolean face mask | Faces |
reindexedByIds | Face ID list | Faces |
reindexedByMaskOnPoints | Boolean point mask | Points → faces |
reindexedByIdsOnPoints | Point ID list | Points → faces |
reindexed | Existing IndexMap | NDArray or Mesh |
concatenateMeshes | — | Multiple meshes |
splitIntoComponents | Per-face labels | Single mesh |
All functions that accept { returnIndexMap: true } return a ReindexedMeshResult with mesh, faceMap, and pointMap fields.
IndexMap structure (f and keptIds), see the Clean module documentation.Async
All reindex functions are available as async variants via tf.async for off-main-thread execution:
const filtered = await tf.async.reindexedByMask(mesh, mask);
const subset = await tf.async.reindexedByIds(mesh, ids);
const combined = await tf.async.concatenateMeshes(s1, s2);
const split = await tf.async.splitIntoComponents(mesh, labels);
