Examples | C++

Core Functionality

Self-contained examples demonstrating primary features of trueform.

These examples demonstrate fundamental trueform workflows, from primitive queries to spatial acceleration structures and the compositional policy system.

Queries on Primitives

Source: queries_on_primitives.cpp

Demonstrates fundamental geometric queries between individual primitives, serving as an introduction to the core query system.

Features Showcased

  • Creating basic owning primitives (tf::polygon, tf::segment)
  • Boolean intersection tests with tf::intersects
  • Finding closest points with tf::closest_metric_point_pair
  • Calculating minimum distance with tf::distance
  • Point classification using tf::classify (containment, sidedness)
  • Ray casting with tf::ray_cast and tf::ray_hit

Example Code

queries.cpp
// Create primitives
auto triangle = tf::make_polygon(
    std::array{tf::point<float, 3>{0, 0, 0},
               tf::point<float, 3>{1, 0, 0},
               tf::point<float, 3>{0, 1, 0}});

auto segment = tf::make_segment_between_points(
    tf::point<float, 3>{0.5f, 0.5f, -1.0f},
    tf::point<float, 3>{0.5f, 0.5f, 1.0f});

// Intersection test
if (tf::intersects(triangle, segment)) {
    // Compute closest points
    auto [dist2, pt_on_triangle, pt_on_segment] =
        tf::closest_metric_point_pair(triangle, segment);

    std::cout << "Distance: " << std::sqrt(dist2) << std::endl;
}

// Ray casting
auto ray = tf::make_ray_between_points(
    tf::point<float, 3>{0.2f, 0.2f, -1.0f},
    tf::point<float, 3>{0.2f, 0.2f, 1.0f});

if (auto hit = tf::ray_hit(ray, triangle)) {
    auto [status, t, point] = hit;
    std::cout << "Hit at t=" << t << std::endl;
}

Finding Coincident Points with Tolerance

Source: find_coincident_points_with_tolerance.cpp

Demonstrates cleaning up a point cloud by identifying nearly-coincident points—a crucial preprocessing step for mesh simplification and manifold topology construction.

Features Showcased

  • Generating random tf::points collections
  • Building tf::tree acceleration structure over point clouds
  • Using tf::gather_self_ids to collect point pairs within tolerance
  • Using tf::search_self with custom predicates
  • Thread-safe parallel collection with tf::local_vector

Example Code

coincident_points.cpp
// Generate random point cloud
tf::points_buffer<float, 3> points;
points.allocate(10000);
tf::parallel_apply(points, [](auto& pt) {
    pt = tf::random_point<float, 3>();
});

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

// Define tolerance for "coincident"
float tolerance = 1e-3f;
float tolerance2 = tolerance * tolerance;

// Method 1: High-level API
std::vector<std::pair<int, int>> coincident_pairs;
tf::gather_self_ids(
    tf::make_form(tree, points.points()),
    [tolerance2](const auto& pt0, const auto& pt1) {
        return tf::distance2(pt0, pt1) < tolerance2;
    },
    std::back_inserter(coincident_pairs)
);

// Method 2: General search API with thread-local collection
tf::local_vector<std::pair<int, int>> local_pairs;
tf::search_self(
    tf::make_form(tree, points.points()),
    [tolerance](const auto& aabb0, const auto& aabb1) {
        return tf::distance(aabb0, aabb1) < tolerance;
    },
    [&local_pairs, tolerance2](const auto& pt0, const auto& pt1) {
        if (pt0.id() < pt1.id() &&
            tf::distance2(pt0, pt1) < tolerance2) {
            local_pairs.push_back({pt0.id(), pt1.id()});
        }
    }
);

// Extract results from thread-local storage
std::vector<std::pair<int, int>> all_pairs;
local_pairs.to_iterator(std::back_inserter(all_pairs));
This pattern is essential for welding meshes, removing duplicate vertices, and establishing manifold topology. The spatial tree makes the operation O(n log n) instead of O(n²).

Find Intersecting Primitives in a Mesh

Source: find_intersecting_primitives.cpp

Demonstrates finding all intersecting triangles between a mesh and a dynamically transformed version of itself—core functionality for collision detection with articulated bodies or self-intersection tests.

Features Showcased

  • Creating tf::polygons view from raw vertex and index data
  • Building tf::tree over polygon mesh
  • Applying dynamic tf::frame to perform queries on transformed geometry
  • Using tf::gather_ids to collect intersecting pairs
  • Using general tf::search with custom predicates
  • Thread-safe parallel collection with tf::local_vector

Example Code

intersecting_primitives.cpp
// Load mesh data
auto [raw_points, raw_faces] = load_mesh("bunny.obj");
auto polygons = tf::make_polygons(
    tf::make_blocked_range<3>(raw_faces),
    tf::make_points<3>(raw_points));

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

// Create static and transformed forms
auto static_form = tf::make_form(tree, polygons);

auto transform = tf::random_transformation<float, 3>();
auto dynamic_form = tf::make_form(
    tf::make_frame(transform), tree, polygons);

// Method 1: High-level collection
std::vector<std::pair<int, int>> intersecting_pairs;
tf::gather_ids(
    static_form, dynamic_form,
    tf::intersects_f,
    std::back_inserter(intersecting_pairs)
);

std::cout << "Found " << intersecting_pairs.size()
          << " intersecting triangle pairs" << std::endl;

// Method 2: Custom search with detailed control
tf::local_vector<std::pair<int, int>> local_intersections;
tf::search(
    static_form, dynamic_form,
    [](const auto& aabb0, const auto& aabb1) {
        return tf::intersects(aabb0, aabb1);  // Broad phase
    },
    [&local_intersections](const auto& tri0, const auto& tri1) {
        if (tf::intersects(tri0, tri1)) {     // Narrow phase
            local_intersections.push_back({tri0.id(), tri1.id()});
        }
    }
);
When using tf::search between two forms, the lambda is executed in parallel. Always use thread-safe containers like tf::local_vector for result collection.

Performance Characteristics

The spatial tree enables efficient broad-phase culling:

  • Broad-phase: AABB tests filter out distant triangle pairs
  • Narrow-phase: Triangle-triangle intersection tests only on candidates
  • Complexity: O(n log n + k) where k is the number of actual intersections

Without spatial acceleration, this would require O(n²) triangle-triangle tests for a mesh with n triangles.