VTK | C++

Functions

Standalone mesh operations wrapping trueform algorithms.

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.

Find the nearest point on a mesh to a query point. Returns neighbor_result, an alias for tf::nearest_neighbor<vtkIdType, float, 3>:

MemberTypeDescription
elementvtkIdTypeCell index of nearest element
info.pointtf::point<float, 3>Closest point on the mesh
info.metricfloatSquared 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>:

MemberTypeDescription
elementsstd::pair<vtkIdType, vtkIdType>Cell indices on each mesh
info.metricfloatSquared distance
info.firsttf::point<float, 3>Closest point on first mesh
info.secondtf::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>>:

MemberTypeDescription
elementvtkIdTypeCell index of hit element
info.statustf::intersect_statusIntersection status
info.tfloatParametric 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>>:

MemberTypeDescription
elementvtkIdTypeCell index of hit element
info.statustf::intersect_statusIntersection status
info.tfloatParametric distance along ray
info.pointtf::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);

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 connected
  • tf::connectivity_type::edge — faces sharing an edge are connected
  • tf::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);

Normals

Compute and set normal vectors on polydata. 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);

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);
Cell data cannot be preserved because edges are reconnected into paths.

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");
Normals are not read from the file.

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");