Functions
The functions module provides VTK-friendly wrappers for trueform's algorithms. Pass in tf::vtk::polydata, get back results as VTK objects or trueform primitives. Many functions accept an optional vtkMatrix4x4* transform for operating on meshes in world space without modifying the underlying geometry.
Include the module with:
#include <trueform/vtk/functions.hpp>
Spatial Queries
These functions wrap trueform's Spatial module queries. They automatically select the appropriate primitive type based on what the polydata contains: polygons first, then lines, then points.
neighbor_search
Find the nearest point on a mesh to a query point. Returns neighbor_result, an alias for tf::nearest_neighbor<vtkIdType, float, 3>:
| Member | Type | Description |
|---|---|---|
element | vtkIdType | Cell index of nearest element |
info.point | tf::point<float, 3> | Closest point on the mesh |
info.metric | float | Squared distance |
operator bool() | True if a neighbor was found |
auto result = tf::vtk::neighbor_search(mesh, point);
if (result) {
auto closest = result.info.point; // tf::point<float, 3>
auto dist2 = result.info.metric; // squared distance
auto cell_id = result.element; // vtkIdType
}
// With radius constraint (returns false if nothing within radius)
auto result = tf::vtk::neighbor_search(mesh, point, 10.0f);
// With transform
auto result = tf::vtk::neighbor_search({mesh, matrix}, point);
For mesh-vs-mesh queries, returns neighbor_pair_result, an alias for tf::nearest_neighbor_pair<vtkIdType, vtkIdType, float, 3>:
| Member | Type | Description |
|---|---|---|
elements | std::pair<vtkIdType, vtkIdType> | Cell indices on each mesh |
info.metric | float | Squared distance |
info.first | tf::point<float, 3> | Closest point on first mesh |
info.second | tf::point<float, 3> | Closest point on second mesh |
operator bool() | True if a pair was found |
auto pair = tf::vtk::neighbor_search(mesh0, mesh1);
if (pair) {
auto [dist2, pt0, pt1] = pair.info;
auto [id0, id1] = pair.elements;
}
// With transforms
auto pair = tf::vtk::neighbor_search({mesh0, matrix0}, {mesh1, matrix1});
neighbor_search_k
Find the k nearest points on a mesh. Returns std::vector<neighbor_result> sorted by squared distance. See kNN Queries.
auto results = tf::vtk::neighbor_search_k(mesh, point, 5);
for (const auto& r : results) {
// r.element, r.info.point, r.info.metric
}
// With radius constraint
auto results = tf::vtk::neighbor_search_k(mesh, point, 5, 10.0f);
neighbor_search_batch
Find nearest neighbors for multiple query points in parallel. Returns std::vector<neighbor_result>.
auto results = tf::vtk::neighbor_search_batch(mesh, query_points);
// With radius
auto results = tf::vtk::neighbor_search_batch(mesh, query_points, 10.0f);
neighbor_search_k_batch
Find k nearest neighbors for multiple query points. Returns tf::offset_block_vector<std::size_t, neighbor_result> with variable results per query.
auto results = tf::vtk::neighbor_search_k_batch(mesh, query_points, 5);
for (const auto& pt_results : results) {
for (const auto& r : pt_results) {
// r.element, r.info.point, r.info.metric
}
}
// With radius
auto results = tf::vtk::neighbor_search_k_batch(mesh, query_points, 5, 10.f);
distance and distance2
Convenience wrappers around neighbor_search that return only the distance.
// Squared distance (faster, avoids sqrt)
float d2 = tf::vtk::distance2(mesh, point);
float d2 = tf::vtk::distance2(mesh0, mesh1);
// Euclidean distance
float d = tf::vtk::distance(mesh, point);
float d = tf::vtk::distance({mesh0, matrix0}, {mesh1, matrix1});
intersects
Test whether two meshes intersect. See Distance and Intersection.
if (tf::vtk::intersects(mesh0, mesh1)) {
// meshes overlap
}
// With transforms
if (tf::vtk::intersects({mesh0, matrix0}, {mesh1, matrix1})) {
// meshes overlap in world space
}
Ray Operations
Cast rays against meshes for picking and visibility testing. These wrap trueform's Ray Casting with VTK polydata.
ray_cast
Cast a tf::ray and get parametric hit information. Returns ray_cast_result, an alias for tf::tree_ray_info<vtkIdType, tf::ray_cast_info<float>>:
| Member | Type | Description |
|---|---|---|
element | vtkIdType | Cell index of hit element |
info.status | tf::intersect_status | Intersection status |
info.t | float | Parametric distance along ray |
operator bool() | True if intersection found |
auto result = tf::vtk::ray_cast(ray, mesh);
if (result) {
auto t = result.info.t; // parametric distance along ray
auto cell_id = result.element; // hit cell
}
// With ray config (min/max t)
auto result = tf::vtk::ray_cast(ray, mesh, {0.1f, 100.0f});
// With transform
auto result = tf::vtk::ray_cast(ray, {mesh, matrix});
ray_hit
Cast a ray and get the 3D hit position. Returns ray_hit_result, an alias for tf::tree_ray_info<vtkIdType, tf::ray_hit_info<float, 3>>:
| Member | Type | Description |
|---|---|---|
element | vtkIdType | Cell index of hit element |
info.status | tf::intersect_status | Intersection status |
info.t | float | Parametric distance along ray |
info.point | tf::point<float, 3> | Hit position |
operator bool() | True if intersection found |
auto result = tf::vtk::ray_hit(ray, mesh);
if (result) {
auto hit_point = result.info.point; // tf::point<float, 3>
auto t = result.info.t;
auto cell_id = result.element;
}
// With transform
auto result = tf::vtk::ray_hit(ray, {mesh, matrix});
pick
Pick the closest actor along a ray from a collection of actors. Automatically handles actor transforms via GetUserMatrix().
std::vector<vtkActor*> actors = {...};
auto ray = tf::vtk::make_world_ray(renderer, mouse_x, mouse_y);
if (auto result = tf::vtk::pick(ray, actors)) {
vtkActor* hit_actor = result.actor;
vtkIdType cell_id = result.cell_id;
auto position = result.position; // tf::point<float, 3>
float t = result.t;
}
Bounding Boxes
Compute bounding boxes from polydata geometry. See AABB for the underlying types.
aabb_from
Compute the axis-aligned bounding box. Returns tf::aabb<float, 3>.
auto box = tf::vtk::aabb_from(polydata);
auto center = box.center();
auto size = box.size();
obb_from
Compute the oriented bounding box (minimum-volume enclosing box). Returns tf::obb<float, 3>.
auto box = tf::vtk::obb_from(polydata);
Boolean Operations
Combine meshes using constructive solid geometry. See the Cut module for details on boolean operations and input requirements.
make_boolean
Compute boolean operations between two meshes. Returns vtkSmartPointer<polydata> with "Labels" cell scalars indicating face origin (positive for mesh0, negative for mesh1).
auto result = tf::vtk::make_boolean(mesh0, mesh1, tf::boolean_op::merge);
auto result = tf::vtk::make_boolean(mesh0, mesh1, tf::boolean_op::intersection);
auto result = tf::vtk::make_boolean(mesh0, mesh1, tf::boolean_op::difference);
// With transforms
auto result = tf::vtk::make_boolean(
{mesh0, matrix0}, {mesh1, matrix1}, tf::boolean_op::merge);
With tf::return_curves, returns std::pair<vtkSmartPointer<polydata>, vtkSmartPointer<polydata>> — the result mesh and intersection curves.
auto [result, curves] = tf::vtk::make_boolean(
mesh0, mesh1, tf::boolean_op::merge, tf::return_curves);
embedded_intersection_curves
Embed intersection curves from mesh1 into mesh0 without performing a boolean operation. Returns vtkSmartPointer<polydata> containing mesh0 with faces split along intersection curves. No faces from mesh1 are included. See Embedded Intersection Curves.
auto result = tf::vtk::embedded_intersection_curves(mesh0, mesh1);
// With transforms
auto result = tf::vtk::embedded_intersection_curves(
{mesh0, matrix0}, {mesh1, matrix1});
With tf::return_curves, returns std::pair<vtkSmartPointer<polydata>, vtkSmartPointer<polydata>> — the result mesh and intersection curves.
auto [result, curves] = tf::vtk::embedded_intersection_curves(
mesh0, mesh1, tf::return_curves);
make_intersection_curves
Compute intersection curves between two meshes without performing a boolean operation. Returns vtkSmartPointer<polydata> with line cells. See Intersect module for the underlying algorithm.
auto curves = tf::vtk::make_intersection_curves(mesh0, mesh1);
// With transforms
auto curves = tf::vtk::make_intersection_curves(
{mesh0, matrix0}, {mesh1, matrix1});
resolved_self_intersections
Find where a mesh intersects itself and embed the intersection curves as edges. Returns vtkSmartPointer<polydata>. See Embedded Self-Intersection Curves.
auto result = tf::vtk::resolved_self_intersections(mesh);
With tf::return_curves, returns std::tuple<vtkSmartPointer<polydata>, vtkSmartPointer<polydata>> — the resolved mesh and intersection curves.
auto [result, curves] = tf::vtk::resolved_self_intersections(
mesh, tf::return_curves);
Topology Analysis
Analyze and modify mesh connectivity. See the Topology module for the underlying structures.
make_connected_components
Label connected components in a mesh. Returns std::pair<vtkSmartPointer<polydata>, int> — a polydata with "ComponentLabel" cell scalars and the number of components found.
auto [labeled, n_components] = tf::vtk::make_connected_components(
mesh, tf::connectivity_type::edge);
std::cout << "Found " << n_components << " components\n";
Connectivity types:
tf::connectivity_type::manifold_edge— faces sharing a manifold edge are connectedtf::connectivity_type::edge— faces sharing an edge are connectedtf::connectivity_type::vertex— faces sharing a vertex are connected
split_into_components
Split a labeled polydata into separate meshes, one per unique label. Returns std::pair<std::vector<vtkSmartPointer<polydata>>, std::vector<vtkIdType>> — a vector of polydata objects and their corresponding labels.
auto [labeled, n] = tf::vtk::make_connected_components(
mesh, tf::connectivity_type::edge);
auto [components, labels] = tf::vtk::split_into_components(labeled);
for (const auto &[polydata, label] : tf::zip(components, labels)) {
}
// Split by a named cell data array
auto [components, labels] = tf::vtk::split_into_components(polydata, "RegionId");
make_boundary_paths
Extract boundary edges connected into continuous paths. Returns vtkSmartPointer<polydata> with line cells. The output shares points with the input. See Boundary Detection.
auto boundaries = tf::vtk::make_boundary_paths(mesh);
std::cout << "Found " << boundaries->GetNumberOfLines() << " boundary paths\n";
make_boundary_edges
Extract individual boundary edges (edges belonging to only one face). Returns vtkSmartPointer<polydata> with line cells.
auto edges = tf::vtk::make_boundary_edges(mesh);
make_non_manifold_edges
Extract edges belonging to more than two faces. Returns vtkSmartPointer<polydata> with line cells. See Non-Manifold Edge Detection.
auto edges = tf::vtk::make_non_manifold_edges(mesh);
make_non_simple_edges
Extract both boundary and non-manifold edges. Returns vtkSmartPointer<polydata> with line cells and "EdgeType" cell scalars (0=boundary, 1=non-manifold). See Non-Simple Edge Detection.
auto edges = tf::vtk::make_non_simple_edges(mesh);
orient_faces_consistently
Orient face winding so adjacent faces have compatible normals. Modifies the input in place. Uses flood-fill through manifold edges; non-manifold edges act as barriers. See Face Orientation.
tf::vtk::orient_faces_consistently(mesh);
Scalar Field Operations
Extract features from scalar fields defined on mesh vertices. See the Cut module for the underlying algorithms.
make_isocontours
Extract curves at specified scalar values. Returns vtkSmartPointer<polydata> with line cells representing isocontours.
auto contours = tf::vtk::make_isocontours(mesh, "height", {0.1f, 0.2f, 0.3f});
// nullptr for active scalars
auto contours = tf::vtk::make_isocontours(mesh, nullptr, {0.5f});
make_isobands
Extract regions between scalar values. Returns vtkSmartPointer<polydata> with polygon cells and "BandLabel" cell scalars. See Isobands.
// cut_values define band boundaries
// selected_bands: 0=first band, 1=second, etc.
auto bands = tf::vtk::make_isobands(mesh, "height",
{0.0f, 0.5f, 1.0f}, // cut values
{1, 2}); // select bands 1 and 2
With tf::return_curves, returns std::pair<vtkSmartPointer<polydata>, vtkSmartPointer<polydata>> — the bands and their boundary curves.
auto [bands, curves] = tf::vtk::make_isobands(mesh, "height",
{0.0f, 0.5f, 1.0f}, {1, 2}, tf::return_curves);
Geometry
Geometric computations and transformations. See the Geometry module for the underlying algorithms.
compute_cell_normals
Compute face normals and store as "Normals" cell data array. Modifies the input in place. See Polygon Normals.
tf::vtk::compute_cell_normals(polydata);
compute_point_normals
Compute vertex normals by averaging adjacent face normals and store as "Normals" point data array. Modifies the input in place. Computes cell normals first if not present. See Point Normals.
tf::vtk::compute_point_normals(mesh);
compute_principal_curvatures
Compute principal curvatures at each vertex using quadric fitting on k-ring neighborhoods. Stores "K1" and "K2" scalar arrays on point data. Optionally computes principal directions as "D1" and "D2" vector arrays. Modifies the input in place. See Principal Curvatures.
tf::vtk::compute_principal_curvatures(mesh);
// With custom k-ring size (default: 2)
tf::vtk::compute_principal_curvatures(mesh, 3);
// With principal directions
tf::vtk::compute_principal_curvatures(mesh, 2, true);
// Now mesh has K1, K2, D1, D2 arrays
signed_volume
Compute the signed volume of a closed mesh. Positive indicates outward-facing normals, negative indicates inward-facing.
double vol = tf::vtk::signed_volume(mesh);
area
Compute the total surface area of a mesh.
double surface_area = tf::vtk::area(mesh);
mean_edge_length
Compute the mean edge length of a mesh.
float mel = tf::vtk::mean_edge_length(mesh);
ensure_positive_orientation
Ensure faces are oriented with outward-pointing normals. First orients faces consistently, then flips all if signed volume is negative. Modifies the input in place. See Ensure Positive Orientation.
tf::vtk::ensure_positive_orientation(mesh);
// Skip consistency step if already consistent
tf::vtk::ensure_positive_orientation(mesh, true);
triangulated
Triangulate all polygons using ear-cutting. Returns a new polydata with triangle cells. See Triangulation.
auto triangles = tf::vtk::triangulated(mesh);
// Without preserving point data
auto triangles = tf::vtk::triangulated(mesh, false);
Smoothing
laplacian_smoothed
Smooth point positions by iteratively moving vertices towards their neighbors' centroid. See Laplacian Smoothing. Returns vtkSmartPointer<vtkPoints>.
// Smooth: 100 iterations, lambda=0.5
auto smoothed = tf::vtk::laplacian_smoothed(mesh, 100, 0.5f);
// Apply smoothed points to polydata
mesh->SetPoints(smoothed);
| Parameter | Default | Description |
|---|---|---|
input | Input polydata | |
iterations | Number of smoothing passes | |
lambda | 0.5 | Movement factor in 0,1 |
taubin_smoothed below.taubin_smoothed
Smooth point positions while preserving volume by alternating shrink (positive λ) and inflate (negative μ) passes. See Taubin Smoothing. Returns vtkSmartPointer<vtkPoints>.
// Smooth: 50 iterations, lambda=0.5, pass-band frequency kpb=0.1
auto smoothed = tf::vtk::taubin_smoothed(mesh, 50, 0.5f, 0.1f);
// Apply smoothed points to polydata
mesh->SetPoints(smoothed);
| Parameter | Default | Description |
|---|---|---|
input | Input polydata | |
iterations | Number of smoothing passes (each = shrink + inflate) | |
lambda | 0.5 | Shrink factor in (0,1] |
kpb | 0.1 | Pass-band frequency in (0,1) |
Point Cloud Alignment
Functions for aligning point sets. See Point Cloud Alignment for the underlying algorithms.
All alignment functions automatically detect point normals and select the best variant:
- Point-to-Point (no normals) — minimizes Euclidean distance between correspondences
- Point-to-Plane (target has normals) — minimizes distance along normal direction, converges 2-3x faster
- Point-to-Plane with Normal Weighting (both have normals) — weights correspondences by normal agreement for better accuracy on surfaces with varying detail
chamfer_error
Compute one-way Chamfer error (mean nearest-neighbor distance) from source to target. See Chamfer Error. This is an asymmetric measure; for symmetric Chamfer distance, compute both directions and average.
float error = tf::vtk::chamfer_error(source, target);
// With transforms
float error = tf::vtk::chamfer_error({source, matrix0}, {target, matrix1});
fit_rigid_alignment
Fit a rigid transformation (rotation + translation) between corresponding point sets using the Kabsch/Procrustes algorithm. See Rigid Alignment. Requires same vertex count in same order. Returns vtkSmartPointer<vtkMatrix4x4>.
auto T = tf::vtk::fit_rigid_alignment(source, target);
// With transforms
auto T = tf::vtk::fit_rigid_alignment({source, matrix0}, {target, matrix1});
fit_obb_alignment
Fit a rigid transformation by matching oriented bounding boxes. See Coarse Alignment. No correspondences needed. The 180° ambiguity is resolved by testing orientations and selecting the one with lowest chamfer distance. Returns vtkSmartPointer<vtkMatrix4x4>.
auto T = tf::vtk::fit_obb_alignment(source, target);
// With sample size for disambiguation (default: 100)
auto T = tf::vtk::fit_obb_alignment(source, target, 200);
// With transforms
auto T = tf::vtk::fit_obb_alignment({source, matrix0}, {target, matrix1});
fit_icp_alignment
Fit a rigid transformation using iterative closest point with automatic convergence detection. See Iterative Refinement. This is the recommended entry point for ICP registration. Returns a DELTA transformation (vtkSmartPointer<vtkMatrix4x4>) mapping source world coordinates to target world coordinates.
// Default configuration
auto T_delta = tf::vtk::fit_icp_alignment(source, target);
// With configuration
tf::icp_config config;
config.max_iterations = 50;
config.n_samples = 1000;
config.k = 1;
auto T_delta = tf::vtk::fit_icp_alignment(source, target, config);
// With initial transform (returns delta, compose for total)
auto T_init = tf::vtk::fit_obb_alignment(source, target);
auto T_delta = tf::vtk::fit_icp_alignment({source, T_init}, target, config);
auto T_total = vtkSmartPointer<vtkMatrix4x4>::New();
vtkMatrix4x4::Multiply4x4(T_delta, T_init, T_total);
tf::icp_config parameters:
| Parameter | Default | Description |
|---|---|---|
max_iterations | 100 | Maximum iterations |
min_relative_improvement | 1e-6 | Convergence threshold |
n_samples | 1000 | Subsample size (0 = all) |
k | 1 | Nearest neighbors |
sigma | -1 | Gaussian width (-1 = adaptive) |
outlier_proportion | 0 | Outlier rejection ratio |
fit_knn_alignment
Fit a rigid transformation using k-nearest neighbor correspondences (single ICP step). See Single ICP Step. For custom ICP pipelines with special convergence logic. Returns vtkSmartPointer<vtkMatrix4x4>.
// Default (k=1, classic ICP step)
auto T = tf::vtk::fit_knn_alignment(source, target);
// With configuration
auto T = tf::vtk::fit_knn_alignment(source, target, {.k = 5, .sigma = -1.f});
// With transforms
auto T = tf::vtk::fit_knn_alignment({source, matrix0}, {target, matrix1});
tf::knn_alignment_config parameters:
| Parameter | Default | Description |
|---|---|---|
k | 1 | Nearest neighbors (k=1 is classic ICP) |
sigma | -1 | Gaussian width (-1 = adaptive) |
outlier_proportion | 0 | Outlier rejection ratio |
Recommended pipeline:
// 1. Coarse alignment with OBB
auto T = tf::vtk::fit_obb_alignment(source, target);
// 2. Refine with ICP (computes normals automatically if available)
tf::vtk::compute_point_normals(target); // Enable point-to-plane
auto T_delta = tf::vtk::fit_icp_alignment({source, T}, target);
// 3. Compose delta with initial transform for total
auto T_total = vtkSmartPointer<vtkMatrix4x4>::New();
vtkMatrix4x4::Multiply4x4(T_delta, T, T_total);
Remeshing
Modify triangle mesh resolution through decimation, isotropic remeshing, and edge collapse. These functions wrap the Remesh module. All assume triangle input and return a new polydata with cached half-edges.
triangulated.decimated
Reduce face count using quadric error metrics. Returns vtkSmartPointer<polydata> with cached half-edges. See Decimation.
// Decimate to 10% of original faces
auto result = tf::vtk::decimated(mesh, 0.1f);
// With configuration
tf::decimate_config<float> config;
config.preserve_boundary = true;
auto result = tf::vtk::decimated(mesh, 0.1f, config);
See decimate_config for all parameters.
isotropic_remeshed
Redistribute vertices to achieve uniform edge lengths. Returns vtkSmartPointer<polydata> with cached half-edges. See Isotropic Remeshing.
// Remesh to target edge length
auto result = tf::vtk::isotropic_remeshed(mesh, 2.0f);
// With configuration
tf::remesh_config<float> config;
config.target_length = 2.0f;
config.iterations = 5;
config.use_quadric = true;
auto result = tf::vtk::isotropic_remeshed(mesh, config);
See remesh_config for all parameters.
collapsed_short_edges
Collapse edges shorter than a threshold. Unlike decimation which uses quadric error ordering, this collapses by edge length — shortest first. Returns vtkSmartPointer<polydata> with cached half-edges. See Edge Collapse.
float mel = tf::vtk::mean_edge_length(mesh);
auto result = tf::vtk::collapsed_short_edges(mesh, 0.75f * mel);
// With configuration
tf::length_collapse_config<float> config;
config.use_quadric = true;
auto result = tf::vtk::collapsed_short_edges(mesh, 0.75f * mel, config);
See length_collapse_config for all parameters.
Cleaning
Remove degeneracies and duplicates from mesh data. See the Clean module for the underlying algorithms.
cleaned_polygons
Remove duplicate points and degenerate faces from polygon data. Returns vtkSmartPointer<polydata>. See Polygon Cleaning.
auto clean = tf::vtk::cleaned_polygons(mesh);
// With tolerance for merging nearby points
auto clean = tf::vtk::cleaned_polygons(mesh, 0.001f);
// Without preserving point/cell data
auto clean = tf::vtk::cleaned_polygons(mesh, 0.0f, false);
cleaned_lines
Clean line data: merge duplicate points, remove degenerate edges, and reconnect edges into continuous paths. Returns vtkSmartPointer<polydata>. See Curve Cleaning.
auto clean = tf::vtk::cleaned_lines(mesh);
auto clean = tf::vtk::cleaned_lines(mesh, 0.001f);
cleaned_points
Remove duplicate points. Returns vtkSmartPointer<vtkPoints>. See Point Cleaning.
auto clean = tf::vtk::cleaned_points(points);
auto clean = tf::vtk::cleaned_points(points, 0.001f);
File I/O
Read and write mesh files directly to/from tf::vtk::polydata. See the I/O module for the underlying algorithms.
read_stl
Read an STL file. Returns vtkSmartPointer<polydata> with cached acceleration structures ready to use.
auto mesh = tf::vtk::read_stl("model.stl");
write_stl
Write polydata to binary STL. Returns bool indicating success. Input must contain triangles.
bool ok = tf::vtk::write_stl(polydata, "output.stl");
// With transform applied
bool ok = tf::vtk::write_stl({polydata, matrix}, "output.stl");
read_obj
Read an OBJ file. Returns vtkSmartPointer<polydata>. Only vertices and faces are read.
auto mesh = tf::vtk::read_obj("model.obj");
write_obj
Write polydata to OBJ format. Returns bool indicating success.
bool ok = tf::vtk::write_obj(polydata, "output.obj");
// With transform applied
bool ok = tf::vtk::write_obj({polydata, matrix}, "output.obj");
