Getting Started | PY

Introduction

Real-time geometric processing on NumPy arrays. Easy to use, robust on real-world data.

trueform is a Python library for real-time geometric processing. Enriched NumPy arrays with support for vectorized spatial queries. Mesh booleans, registration, remeshing — at interactive speed on million-polygon meshes. Robust to non-manifold flaps, inconsistent winding, and pipeline artifacts. NumPy in, NumPy out.

Try it in your browser

Interactive mesh booleans, registration, isobands, and more. No install needed.

Arrays become typed primitives — single or batched. Primitives compose into forms with cached geometric and topological structures.

SingleBatchnp.array(shape)np.array(N, *shape)Primitive N × PrimitivePrimitivesPointLineRaySegmentTrianglePolygonPlaneAABBFormsMeshEdgeMeshPointCloudtransformationCached on demand.normals.vertex_link.face_link.point_normals.spatial_tree...

NumPy arrays become typed primitives — single or batch. Forms add spatial indexing, on-demand topology and geometry caching, and transformations.

Same functions for primitives, batches, and forms. Algorithms transform forms into new geometry.

PrimitiveQueriestf.distancetf.intersectstf.ray_casttf.closest_metric_point_pair...primitive×primitivefloatbatch(N)×primitivendarray(N,)batch(N)×batch(N)ndarray(N,)batch(N)×formndarray(N,)form×formfloatFormAlgorithmstf.boolean_union(mesh0, mesh1)tf.fit_icp_alignment(cloud0, cloud1)...tf.decimated(mesh, 0.1)

One API for any combination of primitives and forms. Queries broadcast. Forms bridge spatial queries and mesh algorithms.

Installation

Requirements and installation via pip.

Modules

Learn how trueform works — data structures, spatial queries, topology, and the algorithms that connect them.

Benchmarks

Benchmarked against VTK, CGAL, libigl, Coal, FCL, and nanoflann.

Blender

Bring trueform performance to Blender add-ons.

Examples

Core functionality and VTK integration demos.

Research

Theory, publications, and citation.

Quick Tour

Primitives — typed NumPy arrays, single or batched:

import numpy as np
import trueform as tf

triangle = tf.Triangle(a=[0, 0, 0], b=[1, 0, 0], c=[0, 1, 0])
segment = tf.Segment([[0, 0, 0], [1, 1, 1]])
ray = tf.Ray(origin=[0.2, 0.2, -1], direction=[0, 0, 1])

# Add a leading dimension for batches
pts = tf.Point(np.random.rand(1000, 3).astype(np.float32))
segs = tf.Segment(start=np.random.rand(500, 3), end=np.random.rand(500, 3))

Meshes are created from NumPy arrays or read from files:

points = np.array([
    [0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]
], dtype=np.float32)
faces = np.array([
    [0, 1, 2], [0, 2, 3], [0, 3, 1], [1, 3, 2]
], dtype=np.int32)

mesh = tf.Mesh(faces, points)

# Or read from file
mesh = tf.Mesh(*tf.read_stl("model.stl"))

Queries — same functions for any combination. Batches broadcast:

# Batch × Primitive — distance field to a plane
plane = tf.Plane(normal=[0, 0, 1], offset=0.0)
scalars = tf.distance(pts, plane)                    # shape (1000,)

# Batch × Form — closest point on mesh for each segment
ids, dist2s, closest = tf.neighbor_search(mesh, segs) # 3 arrays, shape (500,)

# Single × Single
dist2, pt_a, pt_b = tf.closest_metric_point_pair(triangle, segment)

if (t := tf.ray_cast(ray, triangle)) is not None:
    hit_point = ray.origin + t * np.array(ray.direction)

Mesh analysis reveals structure and defects:

# Connected components
num_components, labels = tf.label_connected_components(mesh.face_link)
components, component_ids = tf.split_into_components(mesh, labels)

# Vertex neighborhoods
v_link = mesh.vertex_link
k2_ring = tf.k_rings(v_link, k=2)
neighs = tf.neighborhoods(v_link, mesh.points, radius=0.5)

# Principal curvatures and directions
k0, k1, d0, d1 = tf.principal_curvatures(mesh, directions=True)

# Boundary curves (open edges)
paths, boundary_points = tf.boundary_curves(mesh)

# Non-manifold edges (shared by >2 faces)
bad_edges = tf.non_manifold_edges(mesh)

Spatial acceleration enables queries on transformed geometry:

static_mesh = tf.Mesh(faces0, points0)
dynamic_mesh = tf.Mesh(faces1, points1)
dynamic_mesh.transformation = rotation_matrix

# Collision detection
does_intersect = tf.intersects(static_mesh, dynamic_mesh)
distance = tf.distance(static_mesh, dynamic_mesh)

# Collect all intersecting primitive pairs
pairs = tf.gather_intersecting_ids(static_mesh, dynamic_mesh)

# Compute intersection curves
paths, curve_points = tf.intersection_curves(static_mesh, dynamic_mesh)

Boolean operations combine meshes:

(result_faces, result_points), labels = tf.boolean_union(mesh0, mesh1)

# With intersection curves
(result_faces, result_points), labels, (paths, curve_points) = tf.boolean_union(
    mesh0, mesh1, return_curves=True
)

Scalar fields and isocontours:

# Extract isobands with boundary curves
(band_faces, band_points), labels, (paths, curve_points) = tf.isobands(
    mesh, scalars, [-1.0, 0.0, 1.0], return_curves=True
)

Remeshing — decimate and remesh:

# Decimate to 50%
dec_faces, dec_points = tf.decimated(mesh, 0.5)

# Isotropic remesh to uniform edge lengths
dec_mesh = tf.Mesh(dec_faces, dec_points)
mel = tf.mean_edge_length(dec_mesh)
rem_faces, rem_points = tf.isotropic_remeshed(dec_mesh, mel)

Mesh cleanup prepares geometry for processing:

# Merge coincident vertices, remove degenerates and duplicates
clean_faces, clean_points = tf.cleaned((faces, points))

# Triangulate n-gons
tri_faces, tri_points = tf.triangulated((quad_faces, points))

# Ensure outward-facing normals on closed meshes
new_faces = tf.ensure_positive_orientation(mesh)

Continue Learning

The Quick Tour above shows trueform's syntax. To build intuition for real workflows, start with the Core Functionality examples — complete scripts covering common tasks. Then explore the Modules to understand the underlying patterns.

Core Functionality

Self-contained examples from primitive queries through booleans and isobands. See the library in action.

Modules

Learn how trueform works — data structures, spatial queries, topology, and the algorithms that connect them.