Skip to main content

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    /// Split triangle edges at vertices lying on them within tolerance
23    /// (T-junctions).
24    ///
25    /// Opt-in: it turns a mesh closed up to T-junctions into a closed
26    /// oriented cycle, and adds no vertex. A triangle is declined, not split,
27    /// when a vertex it would reuse carries per-vertex data that differs from
28    /// interpolating the side's endpoints, so no value is invented. See
29    /// [`crate::split_t_junctions`].
30    SplitTJunctions,
31}
32
33/// Ordered caller-approved repair plan.
34#[derive(Debug, Clone, Default, PartialEq, Eq)]
35pub struct RepairPlan {
36    /// Repairs to attempt in order.
37    pub actions: Vec<RepairAction>,
38}
39
40use axiolid_mesh::AttributeFate;
41
42/// Audit report returned with repaired geometry.
43#[derive(Debug, Clone, Default, PartialEq, Eq)]
44pub struct RepairReport {
45    /// Repairs actually applied.
46    pub applied: Vec<RepairAction>,
47    /// Repairs requested but not applicable.
48    pub skipped: Vec<RepairAction>,
49    /// What happened to each named attribute channel, in input order.
50    ///
51    /// Every input channel appears exactly once, so a caller can tell a
52    /// channel that survived from one that never existed (#114).
53    pub attribute_fates: Vec<(String, AttributeFate)>,
54}