Examples | C++

VTK Integration

Interactive applications demonstrating real-time collision detection, mesh booleans, and curve extraction.

These examples demonstrate how to integrate trueform into a larger framework like VTK, creating zero-copy views directly over VTK's data structures for real-time interactive applications.

Actor Picking and Collision Detection

Source: vtk/collision.cpp

Interactive VTK application demonstrating real-time collision detection. Loads meshes and arranges them in a 5×5 grid with random rotations. Users can pick and drag actors with the mouse while trueform performs real-time collision detection, highlighting colliding objects.

Features Showcased

  • Creating tf::polygons views directly over VTK data buffers
  • Building tf::tree over collections of objects
  • Using tf::intersects with dynamic tf::form for collision detection
  • Using tf::ray_cast for mouse picking

Integration Pattern

The examples use a data bridge (see util/data_bridge.hpp) for zero-copy integration with VTK:

vtk_data_bridge.hpp
// Get points from VTK polydata (zero-copy)
inline auto get_points(vtkPolyData *poly) {
  auto ptr = static_cast<float *>(
      poly->GetPoints()->GetData()->GetVoidPointer(0));
  return tf::make_points<3>(
      tf::make_range(ptr, 3 * poly->GetNumberOfPoints()));
}

// Get triangle faces - handles both VTK versions
#ifdef VTK_CELL_ARRAY_V2
inline auto get_triangle_faces(vtkCellArray *cell_array) {
  return tf::make_blocked_range<3>(tf::make_range(
      static_cast<vtkIdType *>(
          cell_array->GetConnectivityArray()->GetVoidPointer(0)),
      3 * cell_array->GetNumberOfCells()));
}
#else
inline auto get_triangle_faces(vtkCellArray *cell_array) {
  return tf::make_tag_blocked_range<3>(
      tf::make_range(cell_array->GetPointer(),
                     cell_array->GetNumberOfConnectivityEntries()));
}
#endif

// Get triangles (zero-copy view)
inline auto get_triangles(vtkPolyData *poly) {
  return tf::make_polygons(get_triangle_faces(poly), get_points(poly));
}

Usage in application:

usage.cpp
// Load VTK mesh
vtkNew<vtkPolyData> polydata;
reader->SetFileName("bunny.obj");
reader->Update();
polydata->ShallowCopy(reader->GetOutput());

// Create trueform view (zero-copy)
auto triangles = get_triangles(polydata);

// Build spatial tree
tf::aabb_tree<int, float, 3> tree(triangles, tf::config_tree(4, 4));

Collision Detection Loop

collision_detection.cpp
// Static objects in grid
auto static_form = tf::make_form(static_tree, static_polygons);

// Moving object with dynamic transform
auto transform = get_actor_transform();
auto dynamic_form = tf::make_form(
    tf::make_frame(transform), moving_tree, moving_polygons);

// Check collision
if (tf::intersects(static_form, dynamic_form)) {
    // Highlight colliding actors
    actor->GetProperty()->SetColor(1.0, 0.0, 0.0);
} else {
    actor->GetProperty()->SetColor(1.0, 1.0, 1.0);
}

Mouse Picking

picking.cpp
// Create picking ray from mouse position
auto ray = tf::make_ray(camera_position, ray_direction);

// Cast against all actors
if (auto hit = tf::ray_hit(ray, form, tf::make_ray_config(0.f, 1e6f))) {
    auto [object_id, hit_data] = hit;
    auto [status, t, point] = hit_data;

    // Select the clicked actor
    selected_actor = actors[object_id];
}
The zero-copy integration means no data duplication—trueform operates directly on VTK's memory buffers.

Automatic Positioning

Source: vtk/positioning.cpp

Interactive application for precise object positioning using closest-point queries. Loads two mesh copies with random rotations, allows free movement, then computes the exact transformation to bring them into contact along the shortest path.

Features Showcased

  • Using tf::neighbor_search between two tf::form objects
  • Finding closest points on complex meshes
  • Computing precise placement tf::frame from query results
  • Practical application for CAD, robotics, or virtual assembly

Closest Point Query

closest_points.cpp
// Find closest points between two meshes
auto result = tf::neighbor_search(form1, form2);

if (result) {
    auto [primitive_ids, metric_point_pair] = result;
    auto [id0, id1] = primitive_ids;
    auto [dist2, pt_on_mesh1, pt_on_mesh2] = metric_point_pair;

    std::cout << "Closest distance: " << std::sqrt(dist2) << std::endl;
    std::cout << "Triangle on mesh1: " << id0 << std::endl;
    std::cout << "Triangle on mesh2: " << id1 << std::endl;
}

Computing Assembly Transform

assembly_transform.cpp
// Get closest points
auto [dist2, pt1, pt2] = tf::closest_metric_point_pair(form1, form2);

// Compute translation to bring points into contact
auto translation = pt2 - pt1;
auto assembly_transform = tf::make_transformation_from_translation(
    translation.as_vector());

// Apply to mesh
auto assembled_form = tf::make_form(
    tf::make_frame(assembly_transform), tree1, polygons1);
Use Cases: Automated assembly in CAD, robot path planning, virtual fitting, snap-to-surface operations.

Scalar-Field Intersection Curves

Source: vtk/scalar_field_intersections.cpp

Interactive visualization of isocontours based on a scalar field. Loads a mesh, defines a distance field from a random plane, and continuously updates the intersection curve as the plane moves with mouse wheel scrolling.

Features Showcased

  • Using tf::scalar_field_intersections for isocontour extraction
  • Extracting intersection edges with tf::make_intersection_edges
  • Real-time curve updates during interactive manipulation

Scalar Field Definition

scalar_field.cpp
// Define distance field from plane
auto plane = tf::make_plane(
    random_triangle[0], random_triangle[1], random_triangle[2]);

tf::buffer<float> scalar_field;
scalar_field.allocate(points.size());

tf::parallel_transform(points, scalar_field,
                      tf::distance_f(plane));

Isocontour Extraction

isocontours.cpp
// Compute intersections at threshold
float threshold = 0.0f;
tf::scalar_field_intersections<int, float, 3> sfi;
sfi.build(polygons, scalar_field, threshold);

// Extract intersection edges
auto edges = tf::make_intersection_edges(sfi);
auto contour_segments = tf::make_segments(
    edges, sfi.intersection_points());

// Convert to VTK for visualization
update_vtk_polyline(contour_segments);

Interactive Updates

interactive_update.cpp
// Mouse wheel callback
void OnMouseWheel(int delta) {
    // Adjust plane position
    plane_offset += delta * 0.01f;

    // Recompute scalar field
    tf::parallel_transform(points, scalar_field, [&](auto pt) {
        return tf::distance(pt, plane) - plane_offset;
    });

    // Update isocontour
    sfi.build(polygons, scalar_field, 0.0f);
    update_visualization();
}
Scalar field updates and isocontour extraction happen in real-time, demonstrating the performance of trueform's parallel algorithms.

Mesh-Mesh Intersection Curves

Source: vtk/forms_intersections.cpp

Interactive visualization of intersection curves between two moving meshes. Users can grab and move meshes; intersection curves update in real-time when meshes collide.

Features Showcased

  • Using tf::intersections_between_polygons between two tf::form objects
  • Extracting intersection edges
  • Tagging forms with tf::face_membership and tf::manifold_edge_link
  • Type conversion with points.as<double>()
  • Real-time curve extraction during interaction

Setup

mesh_intersection_setup.cpp
// Build topology for both meshes
tf::face_membership<int> fm1, fm2;
fm1.build(mesh1.polygons());
fm2.build(mesh2.polygons());

tf::manifold_edge_link<int, 3> mel1, mel2;
mel1.build(mesh1.faces(), fm1);
mel2.build(mesh2.faces(), fm2);

// Create forms with topology tags
auto form1 = tf::make_form(tree1,
    mesh1.polygons() | tf::tag(mel1) | tf::tag(fm1));
auto form2 = tf::make_form(tree2,
    mesh2.polygons() | tf::tag(mel2) | tf::tag(fm2));

Real-time Intersection

realtime_intersection.cpp
// Update callback (called during interaction)
void OnInteraction() {
    // Get current transform from VTK actor
    auto transform = get_actor_transform();

    // Create dynamic form
    auto dynamic_form = tf::make_form(
        tf::make_frame(transform), tree2,
        mesh2.polygons() | tf::tag(mel2) | tf::tag(fm2));

    // Compute intersections
    tf::intersections_between_polygons<int, double, 3> ibp;
    ibp.build(form1, dynamic_form);

    if (ibp.intersections().size() > 0) {
        // Extract intersection curves
        auto edges = tf::make_intersection_edges(ibp);
        auto curves = tf::make_segments(edges,
                                       ibp.intersection_points());

        // Visualize
        update_vtk_intersection_curves(curves);
    }
}
Practical Applications: CAD interference checking, surgical planning, mechanical assembly validation, animation collision response.

Isobands

Source: vtk/isobands.cpp

Interactive visualization of isobands (regions between isocontours). Users can adjust the scalar field by changing the reference plane (press n), and move isocontour levels by scrolling with Shift held.

Features Showcased

  • Using tf::make_isobands to extract regions between threshold levels
  • Multi-level isocontour extraction
  • Interactive parameter adjustment

Isoband Extraction

isobands.cpp
// Define multiple threshold levels
std::vector<float> levels = {-1.0f, -0.5f, 0.0f, 0.5f, 1.0f};
// Extract only specific bands
std::vector<int> selected_bands = {1, 3};  // 2nd and 4th bands

// Extract isobands
auto [result_mesh, labels] = tf::make_isobands<int>(
    polygons, scalar_field, tf::make_range(levels),
    tf::make_range(selected_bands));

// Color by band
tf::parallel_apply(tf::zip(labels, result_mesh.polygons()),
                  [](auto pair) {
    auto [label, polygon] = pair;
    set_color_by_label(polygon, label);
});

Mesh Booleans

Source: vtk/boolean.cpp

Interactive boolean operations between two moving meshes. Press n to randomize orientations, and watch real-time boolean computation (union, intersection, difference).

Features Showcased

  • Using tf::make_boolean for set operations
  • Real-time boolean updates during interaction
  • Extracting result mesh and intersection curves
  • Supporting all boolean operations

Boolean Operations

boolean_operations.cpp
// Setup forms with topology
auto form1 = tf::make_form(tree1,
    mesh1.polygons() | tf::tag(mel1) | tf::tag(fm1));
auto form2 = tf::make_form(
    tf::make_frame(transform), tree2,
    mesh2.polygons() | tf::tag(mel2) | tf::tag(fm2));

// Compute union
auto [union_mesh, union_labels, union_curves] = tf::make_boolean(
    form1, form2, tf::boolean_op::merge, tf::return_curves);

// Compute intersection
auto [inter_mesh, inter_labels, inter_curves] = tf::make_boolean(
    form1, form2, tf::boolean_op::intersection, tf::return_curves);

// Compute difference
auto [diff_mesh, diff_labels, diff_curves] = tf::make_boolean(
    form1, form2, tf::boolean_op::left_difference, tf::return_curves);

Switching Operations

switch_operations.cpp
// Keyboard callback for operation switching
void OnKeyPress(char key) {
    tf::boolean_op operation;

    switch (key) {
        case 'u': operation = tf::boolean_op::merge; break;
        case 'i': operation = tf::boolean_op::intersection; break;
        case 'd': operation = tf::boolean_op::left_difference; break;
        case 'D': operation = tf::boolean_op::right_difference; break;
        default: return;
    }

    // Recompute with new operation
    auto [result, labels, curves] = tf::make_boolean(
        form1, form2, operation, tf::return_curves);

    update_visualization(result, curves);
}
Performance: Boolean operations on meshes with hundreds of thousands of triangles complete in milliseconds, enabling real-time interactive applications.

General Integration Patterns

Zero-Copy VTK Integration

Using the data bridge helpers from util/data_bridge.hpp:

zero_copy_helpers.cpp
// Extract points (zero-copy)
inline auto get_points(vtkPolyData *poly) {
  auto ptr = static_cast<float *>(
      poly->GetPoints()->GetData()->GetVoidPointer(0));
  return tf::make_points<3>(
      tf::make_range(ptr, 3 * poly->GetNumberOfPoints()));
}

// Extract faces - VTK 8+ version (new cell array format)
#ifdef VTK_CELL_ARRAY_V2
inline auto get_triangle_faces(vtkCellArray *cell_array) {
  return tf::make_blocked_range<3>(tf::make_range(
      static_cast<vtkIdType *>(
          cell_array->GetConnectivityArray()->GetVoidPointer(0)),
      3 * cell_array->GetNumberOfCells()));
}
#else
// VTK 7 version (legacy format with size prefix)
inline auto get_triangle_faces(vtkCellArray *cell_array) {
  return tf::make_tag_blocked_range<3>(
      tf::make_range(cell_array->GetPointer(),
                     cell_array->GetNumberOfConnectivityEntries()));
}
#endif

// Complete integration
auto triangles = get_triangles(polydata);  // Zero-copy

Converting Results Back to VTK

to_vtk_pattern.cpp
auto to_vtk_polydata(const tf::polygons_buffer<int, float, 3, 3> &polys) {
  auto cells = vtk_make_unique<vtkCellArray>();
  cells->Initialize();
  auto offsets = cells->GetOffsetsArray();
  offsets->SetNumberOfComponents(1);
  offsets->SetNumberOfTuples(polys.faces().size() + 1);
  auto offsets_r =
      tf::make_range(static_cast<vtkIdType *>(offsets->GetVoidPointer(0)),
                     offsets->GetNumberOfValues());
  tf::parallel_apply(tf::enumerate(offsets_r), [](auto pair) {
    auto &&[id, offset] = pair;
    offset = 3 * id;
  });
  auto ids = cells->GetConnectivityArray();
  ids->SetNumberOfComponents(3);
  ids->SetNumberOfTuples(polys.faces().size());
  auto ids_r = tf::make_range(static_cast<vtkIdType *>(ids->GetVoidPointer(0)),
                              offsets->GetNumberOfValues());
  tf::parallel_copy(polys.faces_buffer().data_buffer(), ids_r);
  auto points = vtk_make_unique<vtkPoints>();
  points->SetNumberOfPoints(polys.points().size());
  tf::parallel_copy(polys.points(), get_points(points.get()));
  auto out = vtk_make_unique<vtkPolyData>();
  out->SetPoints(points.get());
  out->SetPolys(cells.get());
  return out;
}
For maximum performance, use VTK 8+ with float precision to enable zero-copy integration. For double precision or VTK 7, a single copy is required.