Modules | TS

Reindex

Extract, filter, and reorganize geometric data with referential integrity.

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)]);
Transformations: When concatenating meshes that have transformations set, the transformations are automatically applied to the points before concatenation. This enables assembly workflows where parts are positioned independently.
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`);
}
Relationship with Concatenation: These operations are inverses:
  • concatenateMeshes: Multiple meshes → Single mesh
  • splitIntoComponents: Single mesh + labels → Multiple meshes
This allows flexible workflows: concatenate for batch processing, then split back for individual analysis.

Summary

FunctionSelects byOperates on
reindexedByMaskBoolean face maskFaces
reindexedByIdsFace ID listFaces
reindexedByMaskOnPointsBoolean point maskPoints → faces
reindexedByIdsOnPointsPoint ID listPoints → faces
reindexedExisting IndexMapNDArray or Mesh
concatenateMeshesMultiple meshes
splitIntoComponentsPer-face labelsSingle mesh

All functions that accept { returnIndexMap: true } return a ReindexedMeshResult with mesh, faceMap, and pointMap fields.

For detailed explanation of the 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);
For implementation details, see the C++ Reindex documentation.