Modules | C++

Intersect

Mesh intersections, self-intersections, and scalar field isocontours.

The Intersect module computes geometric intersections between meshes and scalar fields, extracting intersection curves and points with robust handling of all topological cases.

Include the module with:

#include <trueform/intersect.hpp>

Overview

The Intersect module computes intersection geometry without modifying the input meshes:

  • Mesh-mesh intersections: Curves where two meshes intersect
  • Self-intersections: Curves where a mesh intersects itself
  • Scalar field intersections: Contour curves at threshold values

Curves are returned as tf::curves_buffer objects for analysis, visualization, or further processing.

To embed intersection curves into mesh topology (splitting faces along curves), use the Cut module.

Intersection Curves

The simplest way to work with intersections is through curves - connected paths of intersection points.

Between Two Meshes

Extract intersection curves where two meshes intersect:

mesh_intersection.cpp
tf::polygons_buffer<int, float, 3, 3> mesh1, mesh2;
// ... fill with data ...

// Extract intersection curves
auto curves = tf::make_intersection_curves(mesh1.polygons(), mesh2.polygons());

With precomputed structures:

mesh_intersection_precomputed.cpp
// Build structures once, reuse across operations
tf::aabb_tree<int, float, 3> tree1(mesh1.polygons(), tf::config_tree(4, 4));
tf::aabb_tree<int, float, 3> tree2(mesh2.polygons(), tf::config_tree(4, 4));

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

auto form1 = mesh1.polygons() | tf::tag(tree1) | tf::tag(fm1) | tf::tag(mel1);
auto form2 = mesh2.polygons() | tf::tag(tree2) | tf::tag(fm2) | tf::tag(mel2);

// Extract intersection curves
auto curves = tf::make_intersection_curves(form1, form2);

With transformations:

Transformations can be tagged for intersection in transformed space without copying geometry:

auto curves = tf::make_intersection_curves(
    form1 | tf::tag(T1),
    form2 | tf::tag(T2));

Use the curves:

use_curves.cpp
// Access as tf::curves
for (auto curve : curves.curves()) {
}

auto& paths = curves.paths();
auto& points = curves.points();

Self-Intersection Curves

Find where a mesh intersects itself.

To embed self-intersection curves into mesh topology, use tf::embedded_self_intersection_curves from the Cut module.
self_intersection.cpp
// Extract self-intersection curves
auto self_curves = tf::make_self_intersection_curves(mesh.polygons());

// Use identically to regular intersection curves
for (auto curve : self_curves.curves()) {
    // Process self-intersection curve
}

With precomputed structures:

self_intersection_precomputed.cpp
tf::aabb_tree<int, float, 3> tree(mesh.polygons(), tf::config_tree(4, 4));

tf::face_membership<int> fm;
fm.build(mesh.polygons());

tf::manifold_edge_link<int, 3> mel;
mel.build(mesh.faces(), fm);

auto form = mesh.polygons() | tf::tag(tree) | tf::tag(fm) | tf::tag(mel);

// Extract self-intersection curves
auto self_curves = tf::make_self_intersection_curves(form);

Isosurface Curves (Isocontours)

Extract curves where a scalar field crosses threshold values.

To embed isocontours into mesh topology, use tf::embedded_isocurves or tf::make_isobands from the Cut module.

Single Isocontour

isocontour.cpp
// Define scalar field over mesh vertices
std::vector<float> scalar_field{mesh.points().size()};
tf::parallel_transform(mesh.points(),
                      scalar_field,
                      tf::distance_f(tf::make_plane(triangles.front())));

// Extract isocontour at threshold
float threshold = 0.5f;
auto contour = tf::make_isocontours(mesh.polygons(), scalar_field, threshold);

// Use as curves
for (auto curve : contour.curves()) {
}

Multiple Isocontours

Efficiently compute multiple isosurface levels:

multi_isocontours.cpp
// Define threshold levels
std::vector<float> levels = {0.0f, 0.25f, 0.5f, 0.75f, 1.0f};

// Compute all levels at once
auto contours = tf::make_isocontours(mesh.polygons(), scalar_field, levels);

// Each curve belongs to one threshold level
for (auto curve : contours.curves()) {
    // Connected isoline at some threshold
}

Low-Level Intersection Access

For advanced use cases, direct access to intersection data:

Between Two Meshes

low_level_mesh.cpp
tf::intersections_between_polygons<int, double, 3> ibp;
ibp.build(form1, form2);

// Access intersection points
auto points = ibp.intersection_points();
for (auto point : points) {
    // Each point is a tf::point<double, 3>
}

// Access structured intersections
for (auto group : ibp.intersections()) {
    // Each group contains intersections for one face
    for (auto intersection : group) {
        // Intersection fields:
        intersection.tag;           // 0 or 1 (which object)
        intersection.object;        // Face ID in first mesh
        intersection.object_other;  // Face ID in second mesh
        intersection.id;            // Point ID in intersection_points()

        // Topological location on first mesh
        intersection.target.label;  // tf::topo_type: vertex/edge/face
        intersection.target.id;     // Local vertex/edge index

        // Topological location on second mesh
        intersection.target_other.label;
        intersection.target_other.id;
    }
}

// Separate by mesh
auto intersections0 = ibp.intersections0();  // First mesh faces
auto intersections1 = ibp.intersections1();  // Second mesh faces

Self-Intersections

low_level_self.cpp
tf::intersections_within_polygons<int, double, 3> iwp;
iwp.build(form);

auto points = iwp.intersection_points();

for (auto group : iwp.intersections()) {
    for (auto intersection : group) {
        intersection.object;        // Face ID
        intersection.object_other;  // Other intersecting face ID
        intersection.id;            // Point ID
        intersection.target.label;  // Topological type
        intersection.target.id;     // Local index
        intersection.target_other.label;
        intersection.target_other.id;
    }
}

Segment Intersections

For 2D line segment collections:

segment_intersections.cpp
// Prepare segments with edge membership
auto segments = tf::make_segments(edges, points) | tf::tag(tf::edge_membership);

tf::aabb_tree<int, float, 2> tree;
tree.build(segments, tf::config_tree(4, 4));

// Compute intersections
tf::intersections_within_segments<int, float, 2> iws;
iws.build(segments, tree);

auto points = iws.intersection_points();
auto groups = iws.intersections();

// Access structured intersections
for (auto group : iws.intersections()) {
    // Each group contains intersections for one edge
    for (auto intersection : group) {
        intersection.object;        // Edge ID
        intersection.object_other;  // Other intersecting Edge ID
        intersection.id;            // Point ID
        intersection.target.label;  // Topological type
        intersection.target.id;     // Local index
        intersection.target_other.label;
        intersection.target_other.id;
    }
}

Scalar Field Intersections

Low-level access to isosurface intersections:

scalar_field_low_level.cpp
tf::scalar_field_intersections<int, float, 3> sfi;
sfi.build(mesh.polygons(), scalar_field, threshold);

// Access points where field crosses threshold
auto points = sfi.intersection_points();

// Access structured intersections
for (auto group : sfi.intersections()) {
    // Intersections grouped by face
    for (auto intersection : group) {
        intersection.object;       // Face ID
        intersection.id;           // Point ID
        intersection.target.label; // vertex/edge where crossing occurs
        intersection.target.id;    // Local index
    }
}

// Multiple thresholds
sfi.build_many(mesh.polygons(), scalar_field, thresholds);