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}