All documentation

#Use your own mesh, and see what bad input does

Pass vertex and tetrahedron arrays from Gmsh, TetGen or your own code, check them, and find the cell that contains a point.

AssumesPositively oriented tetrahedra that meet in whole faces.
CostsLinear in the number of cells.
UsesMesh, Locator, generateSingleTetMesh, ValidateError, SingularError, validateMeshInput

#The program

Save it as example.mjs next to a package.json with traceprojector installed, and run node example.mjs. It is the file examples/own-mesh.js of the repository, which the test suite runs.

// Your own mesh: build the two arrays yourself (from Gmsh, TetGen or by hand),
// and see what happens when they are wrong. Bad input is always a typed
// error, never a silent wrong answer.
import {
  Locator, Mesh, StableProjector, ValidateError, validateMeshInput,
} from 'traceprojector';

// Two tetrahedra that share the face (0, 1, 2).
const vertices = [[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 1, -1]];
const tetrahedra = [[0, 1, 2, 3], [0, 2, 1, 4]];

// The tetrahedra must have positive orientation. Mesh tells you where the
// problem is; swap two vertex numbers of the named tetrahedron to repair it.
const attempt = (label, make) => {
  try {
    make();
    console.log(label.padEnd(24), 'accepted');
  } catch (error) {
    console.log(label.padEnd(24), error.constructor.name + ':',
        error.message.split('(')[0].split('.')[0].trim());
  }
};
attempt('as given', () => new Mesh(vertices, tetrahedra));
attempt('second one flipped', () => new Mesh(vertices, [[0, 1, 2, 3],
  [0, 1, 2, 4]]));
attempt('a NaN coordinate', () => new Mesh([[0, 0, 0], [1, 0, 0], [0, 1, 0],
  [NaN, 0, 1]], [[0, 1, 2, 3]]));
attempt('a vertex that is missing', () => new Mesh(vertices, [[0, 1, 2, 9]]));

// To check a mesh without building anything, call validateMeshInput.
attempt('validateMeshInput', () => validateMeshInput(vertices, tetrahedra));

// Every projector checks its mesh when you construct it, and raises the same
// errors for a NaN, a repeated or missing vertex and a flat tetrahedron. They
// do not insist on the orientation: they sort the vertices of each cell and
// give the same answer either way, so a Gmsh or TetGen mesh that mixes the two
// works as it is. Mesh and Projector, which use the sign, do insist.
attempt('projector, flipped', () => new StableProjector(vertices,
    [[0, 2, 1, 3]]));
attempt('projector, flat', () => new StableProjector([[0, 0, 0], [1, 0, 0],
  [0, 1, 0], [1, 1, 0]], [[0, 1, 2, 3]]));

// Once the mesh is good, find the tetrahedron that contains a point.
const mesh = new Mesh(vertices, tetrahedra);
const locator = new Locator(mesh);
console.log('point (0.2, 0.2, 0.2) lies in tetrahedron',
    locator.findTetrahedron([0.2, 0.2, 0.2]).tIdx);
console.log('point (2, 2, 2) lies in', locator.findTetrahedron([2, 2, 2]));

// Catching by class, when you do not care which check failed.
try {
  new Mesh(vertices, [[0, 0, 1, 2]]);
} catch (error) {
  console.log('caught a ValidateError:', error instanceof ValidateError);
}

#What it prints

as given                 accepted
second one flipped       ValidateError: Tetrahedron 1 has non-positive or degenerate volume
a NaN coordinate         ValidateError: Vertex 3 must be an array of 3 finite numbers
a vertex that is missing ValidateError: Tetrahedron 0 contains out-of-bounds vertex index 9
validateMeshInput        accepted
projector, flipped       accepted
projector, flat          ValidateError: Tetrahedron 0 has degenerate volume
point (0.2, 0.2, 0.2) lies in tetrahedron 0
point (2, 2, 2) lies in null
caught a ValidateError: true