Skip to main content

brepkit_check/validate/
checks.rs

1//! Check identifiers, severity levels, and validation issue types.
2
3use brepkit_topology::edge::EdgeId;
4use brepkit_topology::face::FaceId;
5use brepkit_topology::shell::ShellId;
6use brepkit_topology::solid::SolidId;
7use brepkit_topology::vertex::VertexId;
8use brepkit_topology::wire::WireId;
9
10/// Identifies a specific validation check.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12pub enum CheckId {
13    /// Vertex not on edge 3D curve within tolerance.
14    VertexOnCurve,
15    /// Vertex not on face surface within tolerance.
16    VertexOnSurface,
17    /// Edge has no 3D curve representation.
18    EdgeNoCurve3D,
19    /// 3D curve deviates from PCurve(surface) beyond tolerance.
20    EdgeSameParameter,
21    /// Edge parameter range is invalid.
22    EdgeRangeValid,
23    /// Edge is degenerate (zero length).
24    EdgeDegenerate,
25    /// Wire contains no edges.
26    WireEmpty,
27    /// Consecutive edges not connected at shared vertices.
28    WireNotConnected,
29    /// Wire is not topologically closed (3D).
30    WireClosure3D,
31    /// Edge appears 3+ times in the same wire.
32    WireRedundantEdge,
33    /// Wire has a self-intersection (non-adjacent edges cross).
34    WireSelfIntersection,
35    /// Face has no surface.
36    FaceNoSurface,
37    /// Face orientation inconsistent with wire winding.
38    FaceOrientationConsistency,
39    /// Shell contains no faces.
40    ShellEmpty,
41    /// Shell faces not all connected via shared edges.
42    ShellConnected,
43    /// Shell has free edges (not shared by exactly 2 faces).
44    ShellClosed,
45    /// Adjacent faces use shared edge in same direction (orientation inconsistent).
46    ShellOrientationConsistent,
47    /// Euler characteristic V-E+F != 2 for genus-0 solid.
48    SolidEulerCharacteristic,
49    /// Same face ID appears in multiple shells.
50    SolidDuplicateFaces,
51}
52
53/// Issue severity.
54#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
55pub enum Severity {
56    /// Informational observation.
57    Info,
58    /// Potential problem.
59    Warning,
60    /// Invalid topology.
61    Error,
62}
63
64/// Reference to a topological entity.
65#[derive(Debug, Clone, Copy)]
66pub enum EntityRef {
67    /// A vertex.
68    Vertex(VertexId),
69    /// An edge.
70    Edge(EdgeId),
71    /// A wire.
72    Wire(WireId),
73    /// A face.
74    Face(FaceId),
75    /// A shell.
76    Shell(ShellId),
77    /// A solid.
78    Solid(SolidId),
79}
80
81/// A single validation issue.
82#[derive(Debug, Clone)]
83pub struct ValidationIssue {
84    /// Which check detected this.
85    pub check: CheckId,
86    /// How severe.
87    pub severity: Severity,
88    /// Which entity.
89    pub entity: EntityRef,
90    /// Human-readable description.
91    pub description: String,
92    /// Measured deviation (for geometric checks).
93    pub deviation: Option<f64>,
94}
95
96/// Result of validating a shape.
97#[derive(Debug, Clone, Default)]
98pub struct ValidationReport {
99    /// All issues found.
100    pub issues: Vec<ValidationIssue>,
101}
102
103impl ValidationReport {
104    /// Whether the shape passed all checks (no errors).
105    #[must_use]
106    pub fn is_valid(&self) -> bool {
107        !self.issues.iter().any(|i| i.severity == Severity::Error)
108    }
109
110    /// Count of error-severity issues.
111    #[must_use]
112    pub fn error_count(&self) -> usize {
113        self.issues
114            .iter()
115            .filter(|i| i.severity == Severity::Error)
116            .count()
117    }
118
119    /// Count of warning-severity issues.
120    #[must_use]
121    pub fn warning_count(&self) -> usize {
122        self.issues
123            .iter()
124            .filter(|i| i.severity == Severity::Warning)
125            .count()
126    }
127}