VTK | C++

Examples

Interactive VTK applications using trueform.

Interactive examples demonstrating trueform's VTK integration. Each example shows a focused pipeline—collision detection, boolean operations, isocontours, and more—with draggable meshes and real-time updates.

All examples are available in the GitHub repository.

Building

Enable VTK examples when building trueform:

cmake -DBUILD_VTK=ON -DBUILD_EXAMPLES=ON ..
make vtk_examples -j10

Requires VTK 9+ with rendering components (RenderingOpenGL2, InteractionStyle).

Run an example:

./vtk_example_collision
./vtk_example_boolean

Spatial Queries

Collision Detection

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

Full source

Closest Pair

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

Full source

Boolean Operations

Boolean

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

Full source

Intersection Curves

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

Full source

Scalar Field Operations

Isocontours

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

Full source

Isobands

Alternating isoband regions with boundary curves. Hold Shift and scroll to animate the band selection—creates a marching-stripes effect across the surface. Uses the isobands filter with curve output.

// Isobands pipeline
vtkNew<tf::vtk::isobands> bands;
bands->SetInputConnection(reader->GetOutputPort());
bands->set_cut_values({0.0f, 0.5f, 1.0f, 1.5f, ...});
bands->set_selected_bands({0, 2, 4, ...});  // alternating
bands->set_return_curves(true);

// Color bands by BandLabel
band_mapper->SetInputConnection(bands->GetOutputPort(0));
band_mapper->SetScalarModeToUseCellData();
band_mapper->SetLookupTable(lut);

// Boundary curves
vtkNew<vtkTubeFilter> tube;
tube->SetInputConnection(bands->GetOutputPort(1));

Full source

Topology Analysis

Connected Components

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

Full source

Boundary Paths

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

Full source