Migrating from libigl
libigl's input convention (float64 (n, 3) vertices, int64 (n_faces, 3) faces) is the
closest of any reference library to triwarp's own — the difference is entirely the face layout
(flat (3 * n_faces,) wp.int32 in triwarp, (n_faces, 3) int64 in libigl) and dtype
(float32 by default in triwarp; pass float64 arrays through where a solve genuinely needs the
extra precision, as heat_geodesic itself does internally).
import igl # before
import triwarp as tw # after
Discrete differential geometry
| libigl | triwarp |
|---|---|
igl.cotmatrix(V, F) |
laplacian.cotmatrix(vertices, faces) |
igl.massmatrix(V, F) |
laplacian.mass_matrix(vertices, faces) |
igl.gaussian_curvature(V, F) |
vertices.vertex_defects(vertices, faces) |
igl.principal_curvature(V, F) |
curvature.principal_curvature |
igl.per_vertex_normals(V, F) |
vertices.vertex_normals / mean_vertex_normals / weighted_vertex_normals |
igl.per_face_normals(V, F, Z) |
triangles.face_normals_and_areas (normals and areas together) |
igl.doublearea(V, F) / 2 |
triangles.face_normals_and_areas's area output |
igl.heat_geodesics_precompute + igl.heat_geodesics_solve |
heat.heat_operators + heat.heat_geodesic |
igl.exact_geodesic |
geodesic_walk (a direct combinatorial surface walk rather than the heat-method approximation) |
igl.harmonic(V, F, b, bc, k) |
parametrization.harmonic |
igl.lscm(V, F, b, bc) |
parametrization.lscm |
igl.arap_precomputation + igl.arap_solve |
parametrization.arap |
igl.min_quad_with_fixed |
linalg.min_quad_with_fixed |
igl.adjacency_matrix(F) |
adjacency.face_adjacency(faces) for face-face, or vertices/edges helpers for vertex-vertex |
igl.boundary_loop(F) |
boundary.longest_boundary_loop (all loops: boundary.boundary_loops) |
igl.upsample / igl.loop |
remesh.subdivide / remesh.subdivide_loop |
igl.decimate |
remesh.quadric_decimate |
igl.is_vertex_manifold |
validation.is_vertex_manifold |
igl.is_edge_manifold |
validation.is_edge_manifold |
igl.connected_components(igl.adjacency_matrix(F)) |
Trimesh.face_connected_component_labels |
What's different, not just renamed
igl's(V, F)positional convention becomes triwarp's(vertices, faces)keyword-friendly one, withfacesflat rather than(n_faces, 3).- libigl bounds nothing — an out-of-range face index is a process crash in libigl (documented
in this project's own test-oracle notes) and a
ValueErroror a defined result in triwarp. Don't port an "it happened to work" libigl call site without re-checking its inputs. igl.min_quad_with_fixedand friends return NumPy arrays libigl solved with its own factorization (Eigen::SimplicialLLTunder the hood); triwarp'slinalg.solve_spdfamily solves on-device with conjugate gradient, optionally multigrid-preconditioned for large or ill-conditioned systems. Both converge to the same answer; only the method (direct factorization vs. iterative solve) differs.