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}