Examples | C++

Coming from Other Libraries

How trueform compares to CGAL, nanoflann, libigl, and VTK.

Common operations in trueform vs established geometry libraries. The key difference: trueform operates directly on polygon arrays without intermediate mesh structures.

CGAL

Connected Components

CGAL requires converting to Surface_mesh and using property maps:

#include <CGAL/Polygon_mesh_processing/connected_components.h>
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>

namespace PMP = CGAL::Polygon_mesh_processing;

// Convert polygon soup to CGAL mesh structure
Surface_mesh mesh;
PMP::polygon_soup_to_polygon_mesh(points, faces, mesh);

// Compute connected components
std::vector<std::size_t> face_cc(num_faces(mesh));
auto n_components = PMP::connected_components(mesh, CGAL::make_property_map(face_cc));

trueform operates directly on polygon arrays:

#include <trueform/trueform.hpp>

auto [labels, n_components] =
    tf::make_manifold_edge_connected_component_labels(polygons);

Boolean Union

CGAL requires mesh conversion and copies for corefinement:

#include <CGAL/Polygon_mesh_processing/corefinement.h>

// Convert to CGAL mesh
auto mesh1 = to_cgal_mesh(polygons);
auto mesh2 = to_cgal_mesh(transformed_polygons);

// Corefinement mutates inputs—copy first
Surface_mesh mesh1_copy = mesh1;
Surface_mesh mesh2_copy = mesh2;
Surface_mesh result;
PMP::corefine_and_compute_union(mesh1_copy, mesh2_copy, result);

trueform composes forms with lazy transformations:

#include <trueform/trueform.hpp>

tf::frame<float, 3> frame = tf::make_frame(rotation);
auto result = tf::make_boolean(polygons0, polygons1 | tf::tag(frame) , tf::boolean_op::merge);

The benchmarks also compare boundary path extraction, polygon tree construction, closest point queries, and mesh-mesh intersection curves. Sources: topology, spatial, cut, intersect.

nanoflann

k-Nearest Neighbors

nanoflann requires an adapter class:

#include <nanoflann.hpp>

// Adapter to expose point data
template <typename Real, int Dims>
struct PointCloudAdapter {
  const Real* data;
  size_t n_points;

  size_t kdtree_get_point_count() const { return n_points; }
  Real kdtree_get_pt(size_t idx, size_t dim) const {
    return data[idx * Dims + dim];
  }
  template <class BBOX> bool kdtree_get_bbox(BBOX&) const { return false; }
};

using Adapter = PointCloudAdapter<float, 3>;
using KDTree = nanoflann::KDTreeSingleIndexAdaptor<
    nanoflann::L2_Simple_Adaptor<float, Adapter>, Adapter, 3>;

Adapter adapter(points_data, n_points);
KDTree tree(3, adapter, {4});

// Query
std::vector<size_t> indices(k);
std::vector<float> distances(k);
nanoflann::KNNResultSet<float> result_set(k);
result_set.init(&indices[0], &distances[0]);
tree.findNeighbors(result_set, &query_point[0], {});

trueform uses a uniform interface:

#include <trueform/trueform.hpp>

tf::aabb_tree<int, float, 3> tree;
tree.build(points, tf::config_tree(4, 4));
auto form = points | tf::tag(tree);

// Query
std::array<tf::nearest_neighbor<int, float, 3>, 10> buffer;
auto knn = tf::make_nearest_neighbors(buffer.begin(), k);
tf::neighbor_search(form, query_point, knn);

// Results in knn[0..k-1]
for (auto& nn : knn) {
    // nn.element (index), nn.info.metric (squared distance), nn.info.point
}

Tree types are interchangeable—aabb_tree, obb_tree, obbrss_tree all use the same query API.

The benchmarks also compare tree construction times. Sources: spatial.

libigl

Connected Components

libigl uses Eigen matrices:

#include <igl/facet_components.h>

// Face indices as Eigen matrix
Eigen::MatrixXi F = to_eigen_faces(faces);

// Compute components
Eigen::VectorXi C;
igl::facet_components(F, C);
// C[i] = component label for face i

trueform works with native arrays:

#include <trueform/trueform.hpp>

auto [labels, n_components] =
    tf::make_manifold_edge_connected_component_labels(polygons);
// labels[i] = component label for face i

The benchmarks also compare boundary path extraction, isocontour generation, boolean operations, and self-intersection detection. Sources: topology, intersect, cut.

VTK

For VTK integration, trueform provides tf::vtk—an extended vtkPolyData with cached acceleration structures, zero-copy views, and VTK pipeline filters.

#include <trueform/vtk.hpp>

auto mesh = vtkSmartPointer<tf::vtk::polydata>::New();
mesh->ShallowCopy(reader->GetOutput());

// Iterate as trueform primitives
for (auto polygon : mesh->polygons()) { /* ... */ }

// Use trueform algorithms
auto [result, curves] = tf::vtk::make_boolean(mesh0, mesh1, tf::boolean_op::merge);

The benchmarks compare connected components, boundary paths, isocontours, mesh-mesh intersection curves, and embedded isocurves. Sources: topology, intersect, cut.

See VTK for the complete API: core utilities, functions, filters, and examples.