Real-time geometric processing. Easy to use, robust on real-world data.
Spatial queries, mesh booleans, isocontours, topology — at interactive speed on million-polygon meshes. Robust to non-manifold flaps, inconsistent winding, and pipeline artifacts. Header-only C++17; works directly on your data with zero-copy views.
▶ Try it live — Interactive mesh booleans, collisions, isobands and more. No install needed.
Documentation and Tutorials — Primitives, trees, topology, booleans — step by step.
trueform is a C++17 header-only library. It depends on oneTBB.
pip install trueformThe pip package includes C++ headers with cmake and conan integration modules.
Conan (handles TBB automatically):
python -m trueform.conan createCMake (requires TBB installed):
find_package(trueform REQUIRED CONFIG)
target_link_libraries(my_target PRIVATE tf::trueform)cmake -B build -Dtrueform_ROOT=$(python -m trueform.cmake)For manual installation without pip (FetchContent, system install, conan from repo), see the full installation guide.
- VTK — Filters and functions that integrate with VTK pipelines
- Python — NumPy in, NumPy out
- Blender — Cached meshes with automatic updates for live preview
#include <trueform/trueform.hpp>
// Start with your raw data—no copies, no conversions
std::vector<float> raw_points = {0, 0, 0, 1, 0, 0, 0, 1, 0};
std::vector<int> indices = {0, 1, 2};
auto points = tf::make_points<3>(raw_points);
auto faces = tf::make_faces<3>(indices);
auto triangles = tf::make_polygons(faces, points);
// or maybe faces are variable
std::vector<int> offsets = {0, 3};
auto d_faces = tf::make_faces(offsets, indices);
auto d_polygons = tf::make_polygons(d_faces, points);
auto polygons_buffer = tf::read_stl("file.stl");
auto polygons = polygons_buffer.polygons();Primitive queries work directly on geometry:
auto polygon = polygons.front();
auto segment = tf::make_segment_between_points(points[0], points[1]);
auto ray = tf::make_ray_between_points(
tf::make_point(0.2f, 0.2f, -1.0f),
tf::make_point(0.2f, 0.2f, 1.0f));
auto [dist2, pt_on_poly, pt_on_seg] = tf::closest_metric_point_pair(polygon, segment);
bool contains = tf::contains_point(polygon, points[0]);
if (auto hit = tf::ray_hit(ray, polygon)) {
auto [status, t, hit_point] = hit;
}Mesh analysis reveals structure and defects:
auto polygons = polygons_buffer.polygons();
// Connected components
auto [n_components, labels] = tf::make_manifold_edge_connected_component_labels(polygons);
auto [components, component_ids] = tf::split_into_components(polygons, labels);
// Vertex neighborhoods
auto v_link = tf::make_vertex_link(polygons);
auto k2_ring = tf::make_k_rings(v_link, 2);
auto neighs = tf::make_neighborhoods(polygons.points() | tf::tag(v_link), 0.5f);
// Principal curvatures and directions
auto [k0, k1, d0, d1] = tf::make_principal_directions(polygons);
// Boundary curves (open edges)
auto boundary_paths = tf::make_boundary_paths(polygons);
auto boundary_curves = tf::make_curves(boundary_paths, polygons.points());
// Non-manifold edges (shared by >2 faces)
auto bad_edges = tf::make_non_manifold_edges(polygons);
auto bad_segments = tf::make_segments(bad_edges, polygons.points());
// Fix inconsistent face winding
tf::orient_faces_consistently(polygons);Spatial acceleration enables queries on transformed geometry:
tf::aabb_tree<int, float, 3> tree(polygons, tf::config_tree(4, 4));
auto dynamic_form = polygons | tf::tag(tree)
| tf::tag(tf::random_transformation<float, 3>());
auto static_form = polygons | tf::tag(tree);
// Collision detection
bool does_intersect = tf::intersects(static_form, dynamic_form);
float distance2 = tf::distance2(static_form, dynamic_form);
// Collect all intersecting primitive pairs
std::vector<std::pair<int, int>> collisions;
tf::gather_ids(static_form, dynamic_form, tf::intersects_f,
std::back_inserter(collisions));
// Compute intersection curves
auto curves = tf::make_intersection_curves(static_form, dynamic_form);Boolean operations combine meshes:
auto [result_mesh, labels] = tf::make_boolean(
polygons0,
polygons1 | tf::tag(tf::make_rotation(tf::deg(45.f), tf::axis<2>)),
tf::boolean_op::merge);
// With intersection curves
auto [result, labels, curves] = tf::make_boolean(
polygons0, polygons1, tf::boolean_op::intersection, tf::return_curves);Scalar fields and isocontours:
// Compute distance field from a plane
auto plane = tf::make_plane(polygons.front());
tf::buffer<float> scalars;
scalars.allocate(polygons.points().size());
tf::parallel_transform(polygons.points(), scalars, tf::distance_f(plane));
// Extract isocontours embedded into the mesh
std::vector<float> cut_values = {-0.5f, 0.0f, 0.5f};
auto [contour_mesh, contour_labels, isocontours] = tf::embedded_isocurves(
polygons, scalars, tf::make_range(cut_values), tf::return_curves);Mesh cleanup prepares geometry for processing:
// Merge coincident vertices, remove degenerates and duplicates
auto clean_mesh = tf::cleaned(polygons, tf::epsilon<float>);
// Triangulate n-gons
auto tri_mesh = tf::triangulated(polygons);
// Ensure outward-facing normals on closed meshes
tf::ensure_positive_orientation(polygons);→ Geometry Walkthrough — A hands-on tour from raw geometry through booleans and connected components.
→ Modules — Primitives, ranges, policies, and the patterns that connect them.
Sample comparisons against VTK, CGAL, libigl, Coal, FCL, and nanoflann:
| Operation | Input | Time | Speedup | Baseline | TrueForm |
|---|---|---|---|---|---|
| Boolean Union | 2 × 1M | 28 ms | 84× | CGAL Simple_cartesian<double> |
reduction diagrams, double |
| Mesh–Mesh Curves | 2 × 1M | 7 ms | 233× | CGAL Simple_cartesian<double> |
reduction diagrams, double |
| Self-Intersection | 1M | 78 ms | 37× | libigl EPECK (GMP/MPFR) | reduction diagrams, double |
| Isocontours | 1M, 16 cuts | 3.8 ms | 38× | VTK vtkContourFilter |
reduction diagrams, float |
| Connected Components | 1M | 15 ms | 10× | CGAL | parallel union-find |
| Boundary Paths | 1M | 12 ms | 11× | CGAL | Hierholzer's algorithm |
| k-NN Query | 500K | 1.7 µs | 3× | nanoflann k-d tree | AABB tree |
| Mesh–Mesh Distance | 2 × 1M | 0.2 ms | 2× | Coal (FCL) OBBRSS |
OBBRSS tree |
| Principal Curvatures | 1M | 25 ms | 55× | libigl | parallel k-ring quadric fitting |
Apple M4 Max, 16 threads, Clang -O3 -march=native. Full methodology, interactive charts, source code, and datasets in benchmarks documentation.
- Getting Started — Installation and first steps
- Modules — Primitives, trees, topology, booleans
- Benchmarks — Performance comparisons
- Examples — Workflows and library comparisons
- Python Bindings — Full API for Python
- Research — Theory, publications, and citation
Dual-licensed:
- Noncommercial: PolyForm Noncommercial License 1.0.0
- Commercial: Contact info@polydera.com
Browse open issues labeled by difficulty. See CONTRIBUTING.md for guidelines.
If you use trueform in your work, please cite:
@software{trueform2025,
title={trueform: Real-time Geometric Processing},
author={Sajovic, {\v{Z}}iga and {et al.}},
organization={XLAB d.o.o.},
year={2025},
url={https://github.com/polydera/trueform}
}Developed by XLAB Medical