axiolid_heal/repair.rs
1//! Explicit repair plans and reports.
2
3/// One opt-in repair. There is deliberately no `All` variant.
4///
5/// No action removes self-intersections. [`crate::self_intersections`]
6/// detects them, but removing them cuts and re-triangulates faces, and that
7/// is deliberately not offered as a repair.
8#[non_exhaustive]
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub enum RepairAction {
11 /// Merge vertices within tolerance.
12 WeldVertices,
13 /// Make connected-face orientation consistent.
14 UnifyOrientation,
15 /// Remove degenerate elements.
16 DropDegenerateElements,
17 /// Flip a closed shell that encloses negative volume.
18 ///
19 /// Separate from [`Self::UnifyOrientation`]: that one makes neighbours
20 /// agree, this one decides which way round the agreed shell faces.
21 OrientOutward,
22}
23
24/// Ordered caller-approved repair plan.
25#[derive(Debug, Clone, Default, PartialEq, Eq)]
26pub struct RepairPlan {
27 /// Repairs to attempt in order.
28 pub actions: Vec<RepairAction>,
29}
30
31use axiolid_mesh::AttributeFate;
32
33/// Audit report returned with repaired geometry.
34#[derive(Debug, Clone, Default, PartialEq, Eq)]
35pub struct RepairReport {
36 /// Repairs actually applied.
37 pub applied: Vec<RepairAction>,
38 /// Repairs requested but not applicable.
39 pub skipped: Vec<RepairAction>,
40 /// What happened to each named attribute channel, in input order.
41 ///
42 /// Every input channel appears exactly once, so a caller can tell a
43 /// channel that survived from one that never existed (#114).
44 pub attribute_fates: Vec<(String, AttributeFate)>,
45}