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}