axiolid_heal/
diagnosis.rs

1//! Diagnosis values; diagnosis never mutates geometry.
2
3/// Defect class observed in mesh or exact topology.
4#[non_exhaustive]
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6pub enum DefectKind {
7    /// Edge used by other than two faces where manifoldness is required.
8    NonManifoldEdge,
9    /// Adjacent orientation disagrees.
10    InconsistentOrientation,
11    /// Coincident vertices are represented separately.
12    DuplicateVertex,
13    /// Zero-area/zero-length entity.
14    DegenerateElement,
15    /// Shell is not closed.
16    OpenShell,
17    /// Shape intersects itself.
18    SelfIntersection,
19}
20
21/// One located defect.
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct Defect {
24    /// Defect class.
25    pub kind: DefectKind,
26    /// Representation-specific stable index where available.
27    pub element: Option<u32>,
28    /// Additional diagnostic context.
29    pub detail: Option<String>,
30}
31
32/// Immutable diagnosis report.
33#[derive(Debug, Clone, Default, PartialEq, Eq)]
34pub struct Diagnosis {
35    /// Defects in deterministic discovery order.
36    pub defects: Vec<Defect>,
37}
38
39impl Diagnosis {
40    /// Whether no defects were found.
41    pub fn is_clean(&self) -> bool {
42        self.defects.is_empty()
43    }
44
45    /// Whether a robust boolean precondition is violated.
46    pub fn blocks_boolean(&self) -> bool {
47        self.defects.iter().any(|defect| {
48            matches!(
49                defect.kind,
50                DefectKind::NonManifoldEdge
51                    | DefectKind::InconsistentOrientation
52                    | DefectKind::OpenShell
53                    | DefectKind::SelfIntersection
54            )
55        })
56    }
57}