Modules | PY

Tetmesh

Constrained Delaunay tetrahedralization of closed surfaces.
This module is in active development: its surface and its results may change between releases.

The Tetmesh module fills the solid a closed surface encloses with tetrahedra. The surface is recovered exactly: every input face is a union of tetrahedron faces, and the tetrahedralization is constrained Delaunay.

import trueform as tf

tet_mesh

mesh = tf.Mesh(faces, points)
tets, points, status = tf.tet_mesh(mesh)
# tets: (T, 4) corners into points; points: (P, 3) float64

if status == tf.TetMeshStatus.MESHED:
    ...
ParameterTypeDescription
meshMeshA 3D triangle mesh; its transformation places it, and its face membership and manifold edge link are reused
split_constraintsbool, default TrueCut the crossings the recovery finds; without it the surface is meshed as given and a crossing in it refuses
tolerancefloat, default 0.0Plane pooling, in the mesh's coordinates: near-coplanar faces pool onto one plane at the entrance, and it is the band of every drain
site_budget_ratioint, optionalThe sites a run may hold per site its entrance states; a recovery past it refuses. Default: the library's
return_reportbool, default FalseReturn the TetMeshReport in the status's place
return_index_mapbool, default FalseAlso return a TetMeshIndexMap

Faces that cross each other are cut where they cross, so a self-intersecting surface meshes too; inside is decided by the surface's winding, a cell kept when the surface winds around it a positive number of times. The points come back in float64 whatever the mesh's dtype: they are exact lattice positions mapped back, finer than a float32 holds. A mesh with a transformation is meshed where the transformation places it, and its points are world positions.

A crossing is found where the constraint recovery refuses it and is cut there, so a surface that crosses nowhere pays nothing for it. With split_constraints=False no crossing is cut (the report's drains is zero) and the first one the recovery names refuses; a clean surface gives the same cells either way.

The Index Map

tets, points, status, imap = tf.tet_mesh(mesh, return_index_map=True)
for facet in imap.face_facets[f]:
    rows = imap.facet_triangles[imap.facet_offsets[facet]:imap.facet_offsets[facet + 1]]
    # rows: (k, 3) triangles into points, wound as the facet

Coplanar input triangles that meet wound alike are one facet. facet_offsets / facet_triangles hold per facet the boundary triangles of the tet mesh covering it; face_facets (an OffsetBlockedArray) lists per input face, ascending, the facets it lies in — one unless a crossing cut it. The map is only computed when asked for.

The Report

The call's third value is a tf.TetMeshStatus:

StatusMeaning
MESHEDEvery constraint recovered and the surface winds consistently; the mesh is the cells it winds positively
REFUSEDSome constraint was refused, the entrance left a carrier without its triangles, or its lattice cannot resolve the crossings its passes kept naming; the report counts each kind. A mesh is returned only when the surface still winds consistently
OPENThe recovered surface has a hole, a rim of free edges that hangs off no non-manifold attachment; no mesh. tf.fill_holes closes a hole
UNWOUNDThe surface does not wind consistently, or it holds a sheet such as a flap whose free rim bounds nothing; no mesh
RANK_DEFICIENTThe points span less than three dimensions
CAPACITYThe cells or sites outgrew the index type

tf.tet_mesh(mesh, return_report=True) returns the TetMeshReport in the status's place; its diagnostics are measured only when it is asked for. It mirrors the C++ tf::tet_mesh_report: status is a TetMeshStatus, the refusals are counted by kind (refused_segments, refused_depth, refused_budget, refused_faces), the cuts by drains, pairs_named, pairs_cut, triangles_cut, failed_triangles and pairs_unresolved, the entrance's statements by dropped_degenerate and stitched_triangles, and census is the constraint recovery's census as a dict. See the C++ Tetmesh module for every field.