Interactive examples demonstrating trueform's VTK integration. Each example shows a focused pipeline—spatial queries, boolean operations, scalar fields, and topology analysis—with draggable meshes and real-time updates.
All examples are available in the GitHub repository.
Enable VTK examples when building trueform:
cmake -B build-vtk -DTF_BUILD_VTK_INTEGRATION=ON -DTF_BUILD_VTK_EXAMPLES=ON
cmake --build build-vtk --parallel --target trueform_vtk_examples
Requires VTK 9+ with rendering components (RenderingOpenGL2, InteractionStyle).
Run an example:
./build-vtk/vtk_example_collision
./build-vtk/vtk_example_boolean
A 5×5 grid of draggable meshes. Drag any mesh and colliding neighbors highlight in real-time using intersects with transforms.
// Check collision between two transformed meshes
bool collision = tf::vtk::intersects(
std::make_pair(poly, selected_matrix),
std::make_pair(poly, other_matrix));
if (collision) {
actor->GetProperty()->SetColor(0.9, 0.7, 0.7);
}
Two draggable meshes with a colored tube showing the closest points between them. Distance updates in real-time using neighbor_search. Tube color interpolates green (close) to red (far).
// Find closest points between two transformed meshes
auto result = tf::vtk::neighbor_search(
std::make_pair(poly, matrices[0].Get()),
std::make_pair(poly, matrices[1].Get()));
// Visualize with a line
line_source->SetPoint1(result.info.first.data());
line_source->SetPoint2(result.info.second.data());
// Color by distance
float t = std::sqrt(result.info.metric) / max_distance;
line_actor->GetProperty()->SetColor(t, 1.0 - t, 0.3);
Two-viewport display: input meshes with intersection curves on the left, boolean result on the right. Drag either mesh to reposition—the boolean result and curves update in real-time. Uses the boolean filter with transforms and curve output. Result mesh colored by "Labels" cell data.
// Boolean filter pipeline
vtkNew<tf::vtk::boolean> boolean_filter;
boolean_filter->SetInputConnection(0, adapter0->GetOutputPort());
boolean_filter->SetInputConnection(1, adapter1->GetOutputPort());
boolean_filter->set_matrix0(matrix0);
boolean_filter->set_matrix1(matrix1);
boolean_filter->set_operation(tf::boolean_op::left_difference);
boolean_filter->set_return_curves(true);
// Visualize curves as tubes
vtkNew<vtkTubeFilter> tube;
tube->SetInputConnection(boolean_filter->GetOutputPort(1));
// Color result by Labels
vtkNew<vtkLookupTable> lut;
lut->SetNumberOfTableValues(2);
lut->SetTableValue(0, 0.8, 0.8, 0.9, 1.0); // mesh 0
lut->SetTableValue(1, 0.9, 0.8, 0.8, 1.0); // mesh 1
result_mapper->SetInputConnection(boolean_filter->GetOutputPort(0));
result_mapper->SetScalarModeToUseCellData();
result_mapper->SetLookupTable(lut);
Two draggable meshes with intersection curves. Drag either mesh—curves update in real-time. Uses the intersection_curves filter with transforms.
// Intersection curves pipeline
vtkNew<tf::vtk::intersection_curves> curves;
curves->SetInputConnection(0, adapter0->GetOutputPort());
curves->SetInputConnection(1, adapter1->GetOutputPort());
curves->set_matrix0(matrix0);
curves->set_matrix1(matrix1);
// Visualize as tubes
vtkNew<vtkTubeFilter> tube;
tube->SetInputConnection(curves->GetOutputPort());
tube->SetRadius(0.0005);
Isocontour curves on a mesh with a distance-from-centroid scalar field. Hold Shift and scroll to animate the cut values—contours sweep across the surface. Uses the isocontours filter.
// Create scalar field
auto points = tf::vtk::make_points(poly);
auto center = tf::centroid(points);
auto scalars_range = tf::vtk::make_range(scalars.Get());
tf::parallel_transform(points, scalars_range, tf::distance_f(center));
// Isocontours pipeline
vtkNew<tf::vtk::isocontours> iso;
iso->SetInputConnection(reader->GetOutputPort());
iso->set_cut_values({0.1f, 0.2f, 0.3f, ...});
// Visualize as tubes
vtkNew<vtkTubeFilter> tube;
tube->SetInputConnection(iso->GetOutputPort());
Single viewport showing the original mesh (semi-transparent), isoband curves, and filled isoband polygons. The scalar field is signed distance to a plane through the mesh centroid. Scroll to move the isoband levels—creates a marching-stripes effect across the surface. Uses the isobands filter with curve output.
auto points = tf::vtk::make_points(poly);
auto center = tf::centroid(points);
auto normal = tf::make_unit_vector(1.f, 2.f, 1.f);
auto plane = tf::make_plane(normal, center);
auto scalars_range = tf::vtk::make_range(scalars.Get());
tf::parallel_transform(points, scalars_range, tf::distance_f(plane));
vtkNew<tf::vtk::isobands> bands;
bands->SetInputConnection(reader->GetOutputPort());
bands->set_cut_values({...});
bands->set_selected_bands({0, 2, 4, ...}); // alternating
bands->set_return_curves(true);
// Boundary curves
vtkNew<vtkTubeFilter> tube;
tube->SetInputConnection(bands->GetOutputPort(1));
Extracts cross-section curves and triangulates them into filled polygons. The scalar field is signed distance to a plane through the mesh centroid. Scroll to move the cutting plane through the mesh. Uses make_isocontours and triangulated.
auto points = tf::vtk::make_points(poly);
auto center = tf::centroid(points);
auto normal = tf::make_unit_vector(1.f, 2.f, 1.f);
auto plane = tf::make_plane(normal, center);
vtkNew<vtkFloatArray> scalars;
scalars->SetName("plane_distance");
scalars->SetNumberOfTuples(poly->GetNumberOfPoints());
auto scalars_range = tf::vtk::make_range(scalars.Get());
tf::parallel_transform(points, scalars_range, tf::distance_f(plane));
auto curves = tf::vtk::make_isocontours(poly, nullptr, {cut_value});
auto curve_data = tf::vtk::make_curves(curves);
auto slices = tf::triangulated(
tf::make_polygons(curve_data.paths(), curve_data.points()));
slice_mapper->SetInputData(tf::vtk::make_vtk_polydata(std::move(slices)));
Creates disconnected regions using alternating isobands, then labels and splits them into separate meshes. Uses the connected_components filter and split_into_components function.
// Create disconnected regions with isobands
vtkNew<tf::vtk::isobands> bands;
bands->set_selected_bands({0, 2, 4, 6, 8}); // alternating
// Label components
vtkNew<tf::vtk::connected_components> cc;
cc->SetInputConnection(adapt->GetOutputPort());
cc->set_connectivity(tf::connectivity_type::edge);
cc->Update();
std::cout << "Found " << cc->n_components() << " components\n";
// Split into separate meshes
auto [components, labels] = tf::vtk::split_into_components(cc->GetOutput());
// Color by ComponentLabel
mapper->SetScalarModeToUseCellData();
mapper->SelectColorArray("ComponentLabel");
mapper->SetScalarRange(0, cc->n_components() - 1);
Extracts the boundary of a cut mesh (upper half via isobands) and visualizes it as tubes. Uses the boundary_paths filter.
// Cut mesh with isobands (upper half)
vtkNew<tf::vtk::isobands> bands;
bands->set_cut_values({mid_z, max_z + 1.0f});
bands->set_selected_bands({0});
// Extract boundary
vtkNew<tf::vtk::boundary_paths> boundary;
boundary->SetInputConnection(bands->GetOutputPort(0));
// Visualize as tubes
vtkNew<vtkTubeFilter> tube;
tube->SetInputConnection(boundary->GetOutputPort());
tube->SetRadius(0.0005);
Interactive mesh smoothing with a paint-style brush. Click and drag on the mesh to smooth vertices—the brush highlights affected regions and smooths in real-time. Demonstrates mod_tree for O(delta) spatial tree updates instead of full rebuilds.
// Collect affected polygon IDs from modified vertices
std::vector<vtkIdType> polygon_ids;
const auto &fm = poly->face_membership();
for (auto vid : modified_vertices) {
for (auto poly_id : fm[vid])
polygon_ids.push_back(poly_id);
}
// Apply Laplacian smoothing to neighborhood
auto neigh_points = tf::make_indirect_range(vertex_indices, points);
auto neigh_neighbors = tf::make_indirect_range(
vertex_indices, tf::make_block_indirect_range(vlink, points));
tf::parallel_for_each(
tf::zip(neigh_points, neigh_neighbors),
[&](auto tup) {
auto [pt, neighbors] = tup;
pt = tf::laplacian_smoothed(pt, tf::make_points(neighbors), lambda);
});
// Incrementally update spatial tree (O(delta) instead of O(n))
poly->update_poly_tree(polygon_ids);
Controls: