Expand description
Triangle mesh repair and processing utilities.
This crate provides comprehensive tools for loading, validating, repairing, and transforming triangle meshes. It’s designed for 3D printing pipelines, mesh processing, and geometry operations.
§Features
- File I/O: Load and save STL, OBJ, 3MF, and PLY formats
- Validation: Check for non-manifold edges, holes, self-intersections, winding issues
- Repair: Fill holes, fix winding, remove degenerates, weld vertices
- Analysis: Component detection, wall thickness measurement, volume/surface area
- Transformation: Decimation, subdivision, isotropic remeshing
§Units and Scale
This library assumes millimeter (mm) units.
- Default hole filling skips holes larger than 500 edges (adjustable via params)
- Default vertex welding tolerance is 1e-6 (sub-micron precision)
- Wall thickness analysis defaults: 1mm minimum for FDM, 0.4mm for SLA
- Ray casting max distance defaults to 1000mm (1 meter)
If your mesh uses different units, scale accordingly:
- Meters → mm: Multiply all coordinates by 1000
- Inches → mm: Multiply all coordinates by 25.4
- Microns → mm: Divide all coordinates by 1000
§Coordinate System
The library uses a right-handed coordinate system:
- X: typically width (left/right)
- Y: typically depth (front/back)
- Z: typically height (up/down)
Face winding is counter-clockwise (CCW) when viewed from outside the mesh. This means normals point outward by the right-hand rule.
§Quick Start
use mesh_repair::Mesh;
// Load a mesh from any supported format
let mut mesh = Mesh::load("model.stl").unwrap();
// Validate and check for issues
let report = mesh.validate();
println!("{}", report);
// Repair common issues
mesh.repair().unwrap();
// Save to any supported format
mesh.save("repaired.3mf").unwrap();§Common Workflows
§3D Printing Pipeline
use mesh_repair::{Mesh, RepairParams, ThicknessParams};
let mut mesh = Mesh::load("scan.stl").unwrap();
// Use printing-optimized repair settings
mesh.repair_with_config(&RepairParams::for_printing()).unwrap();
// Check printability requirements
let report = mesh.validate();
if report.is_printable() {
println!("Mesh is ready for printing!");
} else {
if !report.is_watertight {
println!("Has {} boundary edges", report.boundary_edge_count);
}
if !report.is_manifold {
println!("Has {} non-manifold edges", report.non_manifold_edge_count);
}
if report.is_inside_out {
println!("Normals are inverted");
}
}
// Check wall thickness for FDM printing
let thickness = mesh.analyze_thickness(&ThicknessParams::for_printing());
if thickness.has_thin_regions() {
println!("Warning: {} thin regions below 0.8mm", thickness.thin_regions.len());
}
mesh.save("print_ready.3mf").unwrap();§Processing 3D Scans (with RepairBuilder)
use mesh_repair::{Mesh, RepairBuilder};
let mesh = Mesh::load("scan.ply").unwrap();
// Use fluent builder API for repair operations
let result = RepairBuilder::new(mesh)
.for_scans() // Use scan-optimized settings
.remove_small_components(100) // Remove debris < 100 faces
.build()
.unwrap();
println!("Welded {} vertices, removed {} degenerates",
result.vertices_welded, result.degenerates_removed);
result.mesh.save("processed_scan.obj").unwrap();§Processing 3D Scans (with params)
use mesh_repair::{Mesh, RepairParams};
let mut mesh = Mesh::load("scan.ply").unwrap();
// Remove small debris/noise components
let removed = mesh.remove_small_components(100); // Remove components < 100 faces
println!("Removed {} noise components", removed);
// Use scan-optimized repair (smaller hole filling, more aggressive cleanup)
mesh.repair_with_config(&RepairParams::for_scans()).unwrap();
// Remesh for uniform triangle quality
let remeshed = mesh.remesh_with_edge_length(2.0); // 2mm target edge length
remeshed.mesh.save("processed_scan.obj").unwrap();§CAD Model Cleanup
use mesh_repair::{Mesh, RepairParams};
let mut mesh = Mesh::load("cad_export.stl").unwrap();
// CAD models often have precise vertices that shouldn't be welded aggressively
mesh.repair_with_config(&RepairParams::for_cad()).unwrap();
// Check for self-intersections (common in boolean operation results)
let intersections = mesh.detect_self_intersections();
if !intersections.is_clean() {
println!("Warning: {} self-intersecting triangle pairs", intersections.intersection_count);
}
mesh.save("cleaned.stl").unwrap();§Mesh Simplification
use mesh_repair::{Mesh, DecimateParams};
let mesh = Mesh::load("high_poly.obj").unwrap();
// Decimate to 25% of original triangles
let result = mesh.decimate_with_params(&DecimateParams::with_target_ratio(0.25));
println!("Reduced from {} to {} triangles", result.original_triangles, result.final_triangles);
// Or decimate to a specific count
let result = mesh.decimate_to_count(10000);
result.mesh.save("low_poly.obj").unwrap();§Error Handling
Most operations return MeshResult<T>, which is Result<T, MeshError>.
use mesh_repair::{Mesh, MeshError};
fn process_mesh(path: &str) -> Result<(), MeshError> {
let mut mesh = Mesh::load(path)?;
mesh.repair()?;
mesh.save("output.stl")?;
Ok(())
}
// Handle specific errors
match Mesh::load("nonexistent.stl") {
Ok(_) => println!("Loaded successfully"),
Err(MeshError::IoRead { path, source }) => {
println!("Failed to read {:?}: {}", path, source);
}
Err(MeshError::ParseError { path, details }) => {
println!("Failed to parse {:?}: {}", path, details);
}
Err(MeshError::UnsupportedFormat { extension }) => {
println!("Unsupported format: {:?}", extension);
}
Err(e) => println!("Other error: {}", e),
}§Troubleshooting
§“Mesh appears inside-out”
This means face normals point inward instead of outward. Fix with:
use mesh_repair::Mesh;
let mut mesh = Mesh::new();
// ... load or create mesh
mesh.fix_winding().unwrap();§“Mesh has holes / not watertight”
Boundary edges indicate gaps in the surface. Fill holes with:
use mesh_repair::Mesh;
let mut mesh = Mesh::new();
// ... load or create mesh
let filled = mesh.fill_holes().unwrap();
println!("Filled {} holes", filled);§“Non-manifold edges detected”
This means some edges have more than 2 adjacent faces. Use full repair:
use mesh_repair::{Mesh, RepairParams};
let mut mesh = Mesh::new();
// ... load or create mesh
let mut params = RepairParams::default();
params.fix_non_manifold = true;
mesh.repair_with_config(¶ms).unwrap();§“Scale seems wrong”
Check the mesh dimensions and scale if needed:
use mesh_repair::Mesh;
let mesh = Mesh::new();
// ... load or create mesh
if let Some((min, max)) = mesh.bounds() {
let dims = max - min;
println!("Dimensions: {:.1} x {:.1} x {:.1} mm", dims.x, dims.y, dims.z);
}
// If dimensions are in meters, they'll be 1000x too small
// If dimensions are in inches, they'll be ~25x too small§“Multiple disconnected parts”
Keep only the main component or split into separate meshes:
use mesh_repair::Mesh;
let mut mesh = Mesh::new();
// ... load or create mesh
// Option 1: Keep only largest component
let removed = mesh.keep_largest_component();
println!("Removed {} small components", removed);
// Option 2: Split into separate meshes
let parts = mesh.split_components();
for (i, part) in parts.iter().enumerate() {
println!("Component {}: {} faces", i, part.face_count());
}§Supported Formats
| Format | Extension | Load | Save | Index Preservation | Notes |
|---|---|---|---|---|---|
| STL | .stl | ✓ | ✓ | ✗ | Binary & ASCII, common for printing |
| OBJ | .obj | ✓ | ✓ | ✓ | ASCII, preserves vertex order |
| 3MF | .3mf | ✓ | ✓ | ✓ | ZIP-compressed XML, modern standard |
| PLY | .ply | ✓ | ✓ | ✓ | ASCII & binary, supports colors/normals |
Note: STL format does not preserve vertex indices because it stores triangles independently. OBJ, 3MF, and PLY use indexed storage and preserve vertex order.
Re-exports§
pub use adjacency::MeshAdjacency;pub use io::Beam;pub use io::BeamCap;pub use io::BeamLatticeData;pub use io::BeamSet;pub use io::ColorGroup;pub use io::MeshFormat;pub use io::ThreeMfExportParams;pub use io::ThreeMfLoadResult;pub use io::TriangleColors;pub use io::load_3mf_with_materials;pub use io::load_mesh;pub use io::save_3mf;pub use io::save_3mf_extended;pub use io::save_3mf_with_materials;pub use io::save_mesh;pub use io::save_obj;pub use io::save_ply;pub use io::save_ply_ascii;pub use io::save_stl;pub use repair::RepairParams;pub use repair::compute_vertex_normals;pub use repair::fix_inverted_faces;pub use repair::fix_non_manifold_edges;pub use repair::remove_degenerate_triangles;pub use repair::remove_degenerate_triangles_enhanced;pub use repair::remove_duplicate_faces;pub use repair::remove_unreferenced_vertices;pub use repair::repair_mesh;pub use repair::repair_mesh_with_config;pub use repair::weld_vertices;pub use components::ComponentAnalysis;pub use components::find_connected_components;pub use components::keep_largest_component;pub use components::remove_small_components;pub use components::split_into_components;pub use decimate::DecimateParams;pub use decimate::DecimateResult;pub use decimate::decimate_mesh;pub use decimate::decimate_mesh_with_progress;pub use holes::BoundaryLoop;pub use holes::detect_holes;pub use holes::fill_holes;pub use holes::fill_holes_with_max_edges;pub use intersect::IntersectionParams;pub use intersect::SelfIntersectionResult;pub use intersect::detect_self_intersections;pub use remesh::CurvatureResult;pub use remesh::FeatureEdge;pub use remesh::FeatureEdgeResult;pub use remesh::RemeshParams;pub use remesh::RemeshResult;pub use remesh::VertexCurvature;pub use remesh::compute_curvature;pub use remesh::detect_feature_edges;pub use remesh::remesh_adaptive;pub use remesh::remesh_anisotropic;pub use remesh::remesh_isotropic;pub use remesh::remesh_isotropic_with_progress;pub use subdivide::SubdivideParams;pub use subdivide::SubdivideResult;pub use subdivide::subdivide_mesh;pub use thickness::ThicknessParams;pub use thickness::ThicknessResult;pub use thickness::ThinRegion;pub use thickness::analyze_thickness;pub use validate::DataValidationResult;pub use validate::MeshReport;pub use validate::ValidationOptions;pub use validate::validate_mesh;pub use validate::validate_mesh_data;pub use validate::validate_mesh_data_strict;pub use winding::fix_winding_order;pub use morph::Constraint;pub use morph::MorphAlgorithm;pub use morph::MorphParams;pub use morph::MorphResult;pub use morph::RbfKernel;pub use morph::morph_mesh;pub use registration::Landmark;pub use registration::NonRigidParams;pub use registration::NonRigidRegistrationResult;pub use registration::RegistrationAlgorithm;pub use registration::RegistrationParams;pub use registration::RegistrationResult;pub use registration::RigidTransform;pub use registration::align_meshes;pub use registration::non_rigid_align;pub use template::ControlRegion;pub use template::FitParams;pub use template::FitResult;pub use template::FitStage;pub use template::FitTemplate;pub use template::Measurement;pub use template::MeasurementType;pub use template::RegionDefinition;pub use region::FloodFillCriteria;pub use region::MaterialProperties;pub use region::MaterialZone;pub use region::MeshRegion;pub use region::RegionMap;pub use region::RegionSelector;pub use region::ThicknessMap;pub use assembly::Assembly;pub use assembly::AssemblyExportFormat;pub use assembly::AssemblyValidation;pub use assembly::BillOfMaterials;pub use assembly::BomItem;pub use assembly::ClearanceResult;pub use assembly::Connection;pub use assembly::ConnectionParams;pub use assembly::ConnectionType;pub use assembly::InterferenceResult;pub use assembly::Part;pub use lattice::DensityMap;pub use lattice::InfillParams;pub use lattice::InfillResult;pub use lattice::LatticeParams;pub use lattice::LatticeResult;pub use lattice::LatticeType;pub use lattice::generate_infill;pub use lattice::generate_lattice;pub use boolean::BooleanOp;pub use boolean::BooleanParams;pub use boolean::BooleanResult;pub use boolean::BooleanStats;pub use boolean::CoplanarStrategy;pub use boolean::boolean_operation;pub use boolean::boolean_operation_with_progress;pub use scan::DenoiseMethod;pub use scan::DenoiseParams;pub use scan::DenoiseResult;pub use scan::HoleFillParams;pub use scan::HoleFillResult;pub use scan::HoleFillStrategy;pub use scan::OutlierRemovalParams;pub use scan::ScanCleanupParams;pub use scan::ScanCleanupResult;pub use scan::cleanup_scan;pub use scan::denoise_mesh;pub use scan::fill_holes_advanced;pub use scan::remove_outliers;pub use multiscan::MergeParams;pub use multiscan::MergeResult;pub use multiscan::MultiAlignmentParams;pub use multiscan::MultiAlignmentResult;pub use multiscan::OverlapHandling;pub use multiscan::OverlapRegion;pub use multiscan::align_multiple_scans;pub use multiscan::align_multiple_scans_with_params;pub use multiscan::merge_scans;pub use printability::IssueSeverity as PrintIssueSeverity;pub use printability::OrientParams;pub use printability::OrientResult;pub use printability::OverhangRegion;pub use printability::PrintIssue;pub use printability::PrintIssueType;pub use printability::PrintTechnology;pub use printability::PrintValidation;pub use printability::PrinterConfig;pub use printability::SupportAnalysis;pub use printability::SupportRegion;pub use printability::ThinWallRegion;pub use printability::auto_orient_for_printing;pub use printability::detect_support_regions;pub use printability::validate_for_printing;pub use measure::CrossSection;pub use measure::Dimensions;pub use measure::DistanceMeasurement;pub use measure::OrientedBoundingBox;pub use measure::circumference_at_height;pub use measure::closest_point_on_mesh;pub use measure::cross_section;pub use measure::cross_sections;pub use measure::dimensions;pub use measure::measure_distance;pub use measure::oriented_bounding_box;pub use slice::Contour;pub use slice::FdmParams;pub use slice::FdmValidationResult;pub use slice::GapIssue;pub use slice::Layer;pub use slice::LayerBounds;pub use slice::LayerStats;pub use slice::SlaParams;pub use slice::SlaValidationResult;pub use slice::SliceParams;pub use slice::SliceResult;pub use slice::SmallFeatureIssue;pub use slice::SvgExportParams;pub use slice::ThinWallIssue;pub use slice::calculate_layer_stats;pub use slice::export_3mf_slices;pub use slice::export_layer_svg;pub use slice::export_slices_svg;pub use slice::slice_mesh;pub use slice::slice_preview;pub use slice::validate_for_fdm;pub use slice::validate_for_sla;pub use pointcloud::CloudPoint;pub use pointcloud::PointCloud;pub use pointcloud::PointCloudFormat;pub use pointcloud::ReconstructionAlgorithm;pub use pointcloud::ReconstructionParams;pub use pointcloud::ReconstructionResult;pub use progress::OperationEstimate;pub use progress::OperationType;pub use progress::Progress;pub use progress::ProgressCallback;pub use progress::ProgressReporter;pub use progress::ProgressTracker;pub use progress::estimate_operation_time;pub use tracing_ext::OperationTimer;pub use tracing_ext::log_io_operation;pub use tracing_ext::log_mesh_stats;pub use tracing_ext::log_mesh_stats_detailed;pub use tracing_ext::log_perf_section;pub use tracing_ext::log_progress;pub use tracing_ext::log_repair_result;pub use tracing_ext::log_validation_result;
Modules§
- adjacency
- Mesh topology queries via adjacency structures.
- assembly
- Multi-part assembly management.
- boolean
- Mesh boolean operations.
- components
- Connected component analysis for meshes.
- decimate
- Mesh decimation using edge collapse with quadric error metrics.
- holes
- Hole detection and filling for mesh repair.
- intersect
- Self-intersection detection for meshes.
- io
- Mesh file I/O for STL, OBJ, and 3MF formats.
- lattice
- Lattice and infill structure generation.
- measure
- Measurement and dimensioning tools.
- morph
- Mesh morphing and deformation algorithms.
- multiscan
- Multi-scan alignment and merging.
- pointcloud
- Point cloud data structures and surface reconstruction.
- printability
- Print validation and manufacturing analysis.
- progress
- Progress reporting and operation estimation for long-running operations.
- region
- Mesh region definition and management.
- registration
- Mesh registration and alignment algorithms.
- remesh
- Isotropic and adaptive remeshing for uniform edge lengths and improved triangle quality.
- repair
- Mesh repair operations: degenerate removal, welding, compaction.
- scan
- Scan processing and cleanup utilities.
- slice
- Slicing and layer preview for 3D printing.
- subdivide
- Mesh subdivision for surface smoothing.
- template
- Template-based mesh fitting.
- thickness
- Wall thickness analysis for meshes.
- tracing_
ext - Tracing extensions for mesh operations.
- validate
- Mesh validation and reporting.
- winding
- Normal consistency and winding order correction.
Macros§
- mesh_
span - Macro for creating instrumented mesh operation spans.
Structs§
- Fitting
Builder - Fluent builder for mesh fitting workflows.
- Fitting
Result - Result from FittingBuilder containing the fitted mesh and statistics.
- Mesh
- A triangle mesh with indexed vertices and faces.
- Pipeline
- A mesh processing pipeline.
- Pipeline
Result - Result of a pipeline execution.
- Repair
Builder - Fluent builder for mesh repair operations.
- Repair
Result - Result from RepairBuilder containing the repaired mesh and statistics.
- Triangle
- A triangle with concrete vertex positions.
- Vertex
- A vertex in the mesh with optional computed attributes.
- Vertex
Color - RGB color with 8-bit components.
Enums§
- Error
Code - Machine-readable error codes for mesh operations.
- Issue
Severity - Severity levels for validation issues.
- Mesh
Error - Errors that can occur during mesh operations.
- Recovery
Suggestion - Recovery suggestions for mesh errors.
- Validation
Issue - Validation issues that can be collected during mesh validation.
Traits§
- Into
Pipeline - Trait for types that can be converted into a Pipeline.
Type Aliases§
- Mesh
Result - Result type alias for mesh operations.