Clean
The Clean module removes duplicate, degenerate, and unreferenced elements from geometric data. It operates on trueform's primitive ranges, maintains referential integrity, and provides optional index maps for reindexing associated data.
Include the module with:
#include <trueform/clean.hpp>
What Gets Removed
| Geometry | Removes |
|---|---|
| Points | Duplicate vertices |
| Segments | Duplicate vertices, duplicate edges, degenerate edges, unreferenced vertices |
| Polygons | Duplicate vertices, duplicate faces, degenerate faces, unreferenced vertices |
| Curves | Duplicate vertices, degenerate edges, unreferenced vertices |
Definitions:
- Duplicate vertices: Points at the same location (exact or within tolerance)
- Duplicate edges: Edges connecting the same pair of vertices (either direction)
- Duplicate faces: Faces with the same vertex set (any cyclic rotation, either winding)
- Degenerate edges: Zero-length edges (both endpoints are the same vertex)
- Degenerate faces: Faces with fewer than 3 unique vertices (zero area)
- Unreferenced vertices: Vertices not used by any edge or face
When duplicates are removed, the element with the smallest index is kept.
Points
Remove duplicate points from point collections:
// Exact duplicate removal
auto clean_points = tf::cleaned(points);
// Tolerance-based: merge points within distance
auto clean_points = tf::cleaned(points, 1e-6f);
// Get index map for reindexing associated data
auto [clean_points, point_map] = tf::cleaned(points, tolerance, tf::return_index_map);
auto clean_normals = tf::reindexed(point_normals, point_map);
For points (and soups), the index type defaults to int. Specify explicitly for large data:
auto clean_points = tf::cleaned<int64_t>(points);
Segments
Clean segment collections:
// Clean segments
auto clean_segments = tf::cleaned(segments);
// With tolerance
auto clean_segments = tf::cleaned(segments, 1e-5f);
// Get both edge and point index maps
auto [clean_segments, edge_map, point_map] =
tf::cleaned(segments, tolerance, tf::return_index_map);
// Reindex associated data
auto clean_edge_attrs = tf::reindexed(tf::make_edges(edge_attrs), edge_map);
auto clean_point_attrs = tf::reindexed(point_attrs, point_map);
The index type is deduced from segments.edges()[0][0].
Polygons
Clean polygon meshes:
// Clean polygons
auto clean_polygons = tf::cleaned(polygons);
// With tolerance
auto clean_polygons = tf::cleaned(polygons, 1e-8);
// Get both face and point index maps
auto [clean_polygons, face_map, point_map] =
tf::cleaned(polygons, tolerance, tf::return_index_map);
// Reindex associated data
auto clean_face_normals = tf::reindexed(face_normals, face_map);
auto clean_vertex_attrs = tf::reindexed(vertex_attrs, point_map);
The index type is deduced from polygons.faces()[0][0]. Specify explicitly for large meshes:
auto clean_polygons = tf::cleaned<int64_t>(polygons);
Curves
Clean curve collections (connected paths):
// Clean curves
auto clean_curves = tf::cleaned(curves);
// With tolerance
auto clean_curves = tf::cleaned(curves, 1e-5f);
// Get point index map (edge map not available since paths are reconnected)
auto [clean_curves, point_map] = tf::cleaned(curves, tolerance, tf::return_index_map);
Soups
Polygon and segment soups (unindexed geometry) can be cleaned, converting them to indexed geometry:
// Triangle soup: each element stores its own vertices
auto soup = tf::make_polygons(tf::make_blocked_range<3>(raw_points));
// Clean converts to indexed geometry with shared vertices
auto clean_mesh = tf::cleaned(soup);
// With tolerance
auto clean_mesh = tf::cleaned(soup, 1e-6f);
Index Maps
All cleaning operations can return index maps for tracking how elements were remapped:
auto [clean_polygons, face_map, point_map] =
tf::cleaned(polygons, tf::return_index_map);
// Use maps to reindex associated data
auto clean_face_colors = tf::reindexed(face_colors, face_map);
auto clean_vertex_uvs = tf::reindexed(vertex_uvs, point_map);
Low-Level API
For more control, use tf::make_clean_index_map directly:
// Points
auto point_map = tf::make_clean_index_map(points);
auto point_map = tf::make_clean_index_map(points, tolerance);
// Segments
auto [edge_map, point_map] = tf::make_clean_index_map(segments);
auto [edge_map, point_map] = tf::make_clean_index_map(segments, tolerance);
// Polygons
auto [face_map, point_map] = tf::make_clean_index_map(polygons);
auto [face_map, point_map] = tf::make_clean_index_map(polygons, tolerance);
// Explicit index type
auto [face_map, point_map] = tf::make_clean_index_map<int64_t>(polygons);
