runmat_meshing_surface/validate/
types.rs1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
4pub struct SurfaceValidationOptions {
5 pub max_projection_error_m: f64,
6 pub min_orientation_alignment: f64,
7 pub require_source_edge_conformity: bool,
8}
9
10impl Default for SurfaceValidationOptions {
11 fn default() -> Self {
12 Self {
13 max_projection_error_m: 1.0e-8,
14 min_orientation_alignment: 1.0 - 1.0e-8,
15 require_source_edge_conformity: true,
16 }
17 }
18}
19
20#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
21pub struct SurfaceValidationReport {
22 pub source_face_count: usize,
23 pub surface_element_count: usize,
24 pub source_edge_loop_count: usize,
25 pub closed_source_edge_loop_count: usize,
26 pub conforming_source_edge_count: usize,
27 pub missing_source_edge_count: usize,
28 pub max_projection_error_m: f64,
29 pub min_orientation_alignment: f64,
30 pub face_coverage_ratio: f64,
31}
32
33#[derive(Debug, Clone, PartialEq)]
34pub enum SurfaceValidationError {
35 InvalidOptions,
36 EmptySurface,
37 MissingSurfaceNode {
38 element_id: u32,
39 node_id: u32,
40 },
41 MissingSourceFace {
42 source_face_id: u32,
43 },
44 MissingSourceEdge {
45 source_edge_id: u32,
46 },
47 MissingCadFaceId {
48 element_id: u32,
49 },
50 MissingCadFace {
51 cad_face_id: String,
52 },
53 InvalidCadLoopEdgeId {
54 cad_face_id: String,
55 loop_edge_id: String,
56 },
57 SourceEdgeOutsideCadFace {
58 cad_face_id: String,
59 source_edge_id: u32,
60 },
61 EdgeConformityFailed {
62 source_edge_id: u32,
63 source_edge_node_ids: [u32; 2],
64 recovered_segment_count: usize,
65 },
66 OpenSourceLoop {
67 source_edge_id: u32,
68 endpoint_id: u32,
69 incidence_count: usize,
70 },
71 DegenerateElement {
72 element_id: u32,
73 },
74 InvalidElementNormal {
75 element_id: u32,
76 },
77 InvalidElementArea {
78 element_id: u32,
79 },
80 InvalidParametricEvidence {
81 element_id: u32,
82 },
83 InvalidProjectionEvidence {
84 element_id: u32,
85 },
86 ProjectionError {
87 element_id: u32,
88 error_m: f64,
89 max_error_m: f64,
90 },
91 OrientationMismatch {
92 element_id: u32,
93 source_face_id: u32,
94 alignment: f64,
95 min_alignment: f64,
96 },
97 UncoveredSourceFace {
98 source_face_id: u32,
99 },
100 UncoveredCadFace {
101 cad_face_id: String,
102 },
103}
104
105impl std::fmt::Display for SurfaceValidationError {
106 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 match self {
108 Self::InvalidOptions => write!(
109 formatter,
110 "surface validation options must use finite projection and orientation thresholds"
111 ),
112 Self::EmptySurface => write!(formatter, "surface validation input has no elements"),
113 Self::MissingSurfaceNode {
114 element_id,
115 node_id,
116 } => write!(
117 formatter,
118 "surface element {element_id} references missing node {node_id}"
119 ),
120 Self::MissingSourceFace { source_face_id } => {
121 write!(formatter, "source face {source_face_id} is missing")
122 }
123 Self::MissingSourceEdge { source_edge_id } => {
124 write!(formatter, "source edge {source_edge_id} is missing")
125 }
126 Self::MissingCadFaceId { element_id } => write!(
127 formatter,
128 "surface element {element_id} does not carry CAD face provenance"
129 ),
130 Self::MissingCadFace { cad_face_id } => {
131 write!(formatter, "CAD face {cad_face_id} is missing")
132 }
133 Self::InvalidCadLoopEdgeId {
134 cad_face_id,
135 loop_edge_id,
136 } => write!(
137 formatter,
138 "CAD face {cad_face_id} has invalid loop edge id {loop_edge_id}"
139 ),
140 Self::SourceEdgeOutsideCadFace {
141 cad_face_id,
142 source_edge_id,
143 } => write!(
144 formatter,
145 "source edge {source_edge_id} is not a loop edge for CAD face {cad_face_id}"
146 ),
147 Self::EdgeConformityFailed {
148 source_edge_id,
149 source_edge_node_ids,
150 recovered_segment_count,
151 } => write!(
152 formatter,
153 "source edge {source_edge_id} with endpoints {:?} is not represented by a matching surface element edge; recovered surface segment count is {recovered_segment_count}",
154 source_edge_node_ids
155 ),
156 Self::OpenSourceLoop {
157 source_edge_id,
158 endpoint_id,
159 incidence_count,
160 } => write!(
161 formatter,
162 "source edge {source_edge_id} endpoint {endpoint_id} has loop incidence {incidence_count}, expected 2"
163 ),
164 Self::DegenerateElement { element_id } => {
165 write!(formatter, "surface element {element_id} is degenerate")
166 }
167 Self::InvalidElementNormal { element_id } => write!(
168 formatter,
169 "surface element {element_id} has invalid unit-normal evidence"
170 ),
171 Self::InvalidElementArea { element_id } => write!(
172 formatter,
173 "surface element {element_id} has invalid area evidence"
174 ),
175 Self::InvalidParametricEvidence { element_id } => write!(
176 formatter,
177 "surface element {element_id} has invalid parametric coordinate evidence"
178 ),
179 Self::InvalidProjectionEvidence { element_id } => write!(
180 formatter,
181 "surface element {element_id} has invalid projection evidence"
182 ),
183 Self::ProjectionError {
184 element_id,
185 error_m,
186 max_error_m,
187 } => write!(
188 formatter,
189 "surface element {element_id} projection error {error_m:.6e} m exceeds {max_error_m:.6e} m"
190 ),
191 Self::OrientationMismatch {
192 element_id,
193 source_face_id,
194 alignment,
195 min_alignment,
196 } => write!(
197 formatter,
198 "surface element {element_id} on source face {source_face_id} orientation alignment {alignment:.6e} is below {min_alignment:.6e}"
199 ),
200 Self::UncoveredSourceFace { source_face_id } => {
201 write!(formatter, "source face {source_face_id} is not covered")
202 }
203 Self::UncoveredCadFace { cad_face_id } => {
204 write!(formatter, "CAD face {cad_face_id} is not covered")
205 }
206 }
207 }
208}
209
210impl std::error::Error for SurfaceValidationError {}