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}