1use runmat_meshing_core::contracts::{
2 MeshingStage, PlcValidationSummary, StageEvidenceStatus, TopologyEntityId,
3};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub enum PlcValidationError {
7 ValidationSummaryNotVolumeReady {
8 summary: PlcValidationSummary,
9 },
10 EvidenceStageMismatch {
11 stage: MeshingStage,
12 },
13 EvidenceStatusNotComplete {
14 status: StageEvidenceStatus,
15 },
16 EmptyNodes,
17 EmptyFacets,
18 DuplicateNode {
19 node_id: TopologyEntityId,
20 },
21 NonFiniteNode {
22 node_id: TopologyEntityId,
23 },
24 PlcEntityStageMismatch {
25 entity_id: TopologyEntityId,
26 },
27 FacetReferencesUnknownNode {
28 facet_id: TopologyEntityId,
29 node_id: TopologyEntityId,
30 },
31 DuplicateFacet {
32 facet_id: TopologyEntityId,
33 },
34 DuplicateBoundaryFacet {
35 first_facet_id: Box<TopologyEntityId>,
36 second_facet_id: Box<TopologyEntityId>,
37 node_ids: Box<[TopologyEntityId; 3]>,
38 },
39 FacetHasRepeatedNode {
40 facet_id: TopologyEntityId,
41 },
42 DegenerateFacet {
43 facet_id: TopologyEntityId,
44 },
45 FacetHasEmptySourceFaceId {
46 facet_id: TopologyEntityId,
47 },
48 FacetSourceFaceStageMismatch {
49 facet_id: TopologyEntityId,
50 source_face_id: TopologyEntityId,
51 },
52 FacetHasEmptyMaterialInterfaceId {
53 facet_id: TopologyEntityId,
54 },
55 FacetHasRepeatedMaterialInterfaceId {
56 facet_id: TopologyEntityId,
57 material_interface_id: String,
58 },
59 ProtectedEdgeReferencesUnknownNode {
60 edge_id: TopologyEntityId,
61 node_id: TopologyEntityId,
62 },
63 DuplicateProtectedEdge {
64 edge_id: TopologyEntityId,
65 },
66 DuplicateProtectedBoundarySegment {
67 first_edge_id: Box<TopologyEntityId>,
68 second_edge_id: Box<TopologyEntityId>,
69 node_ids: Box<[TopologyEntityId; 2]>,
70 },
71 ProtectedEdgeHasRepeatedNode {
72 edge_id: TopologyEntityId,
73 },
74 ProtectedEdgeHasEmptySourceEdgeId {
75 edge_id: TopologyEntityId,
76 },
77 ProtectedEdgeSourceEdgeStageMismatch {
78 edge_id: TopologyEntityId,
79 source_edge_id: TopologyEntityId,
80 },
81 UnreferencedNode {
82 node_id: TopologyEntityId,
83 },
84 DisconnectedBoundaryComponents {
85 component_count: usize,
86 },
87 ProtectedEdgeNotOnBoundary {
88 edge_id: TopologyEntityId,
89 node_ids: [TopologyEntityId; 2],
90 },
91 OpenBoundaryEdge {
92 node_ids: [TopologyEntityId; 2],
93 incidence_count: usize,
94 },
95 NonManifoldBoundaryEdge {
96 node_ids: [TopologyEntityId; 2],
97 incidence_count: usize,
98 },
99 NonManifoldBoundaryVertex {
100 node_id: TopologyEntityId,
101 incident_facet_count: usize,
102 link_component_count: usize,
103 },
104 InconsistentBoundaryEdgeOrientation {
105 node_ids: [TopologyEntityId; 2],
106 },
107}
108
109impl std::fmt::Display for PlcValidationError {
110 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 match self {
112 Self::ValidationSummaryNotVolumeReady { .. } => {
113 write!(formatter, "PLC validation summary is not volume-ready")
114 }
115 Self::EvidenceStageMismatch { stage } => write!(
116 formatter,
117 "PLC validation requires ProtectedBoundaryComplex evidence, got {stage:?}"
118 ),
119 Self::EvidenceStatusNotComplete { status } => write!(
120 formatter,
121 "PLC validation requires complete stage evidence, got {status:?}"
122 ),
123 Self::EmptyNodes => write!(formatter, "PLC has no nodes"),
124 Self::EmptyFacets => write!(formatter, "PLC has no facets"),
125 Self::DuplicateNode { node_id } => {
126 write!(formatter, "PLC has duplicate node {}", node_id.id)
127 }
128 Self::NonFiniteNode { node_id } => {
129 write!(
130 formatter,
131 "PLC node {} has non-finite coordinates",
132 node_id.id
133 )
134 }
135 Self::PlcEntityStageMismatch { entity_id } => write!(
136 formatter,
137 "PLC entity {} is not a ProtectedBoundaryComplex entity",
138 entity_id.id
139 ),
140 Self::FacetReferencesUnknownNode { facet_id, node_id } => write!(
141 formatter,
142 "PLC facet {} references unknown node {}",
143 facet_id.id, node_id.id
144 ),
145 Self::DuplicateFacet { facet_id } => {
146 write!(formatter, "PLC has duplicate facet {}", facet_id.id)
147 }
148 Self::DuplicateBoundaryFacet {
149 first_facet_id,
150 second_facet_id,
151 node_ids,
152 } => write!(
153 formatter,
154 "PLC facets {} and {} both reference boundary facet {}-{}-{}",
155 first_facet_id.id, second_facet_id.id, node_ids[0].id, node_ids[1].id, node_ids[2].id
156 ),
157 Self::FacetHasRepeatedNode { facet_id } => {
158 write!(formatter, "PLC facet {} repeats a node", facet_id.id)
159 }
160 Self::DegenerateFacet { facet_id } => {
161 write!(formatter, "PLC facet {} has degenerate geometry", facet_id.id)
162 }
163 Self::FacetHasEmptySourceFaceId { facet_id } => write!(
164 formatter,
165 "PLC facet {} has an empty source face id",
166 facet_id.id
167 ),
168 Self::FacetSourceFaceStageMismatch {
169 facet_id,
170 source_face_id,
171 } => write!(
172 formatter,
173 "PLC facet {} source face {} is not a SurfaceMesh entity",
174 facet_id.id, source_face_id.id
175 ),
176 Self::FacetHasEmptyMaterialInterfaceId { facet_id } => write!(
177 formatter,
178 "PLC facet {} has an empty material interface id",
179 facet_id.id
180 ),
181 Self::FacetHasRepeatedMaterialInterfaceId {
182 facet_id,
183 material_interface_id,
184 } => write!(
185 formatter,
186 "PLC facet {} repeats material interface id {material_interface_id}",
187 facet_id.id
188 ),
189 Self::ProtectedEdgeReferencesUnknownNode { edge_id, node_id } => write!(
190 formatter,
191 "PLC protected edge {} references unknown node {}",
192 edge_id.id, node_id.id
193 ),
194 Self::DuplicateProtectedEdge { edge_id } => {
195 write!(
196 formatter,
197 "PLC has duplicate protected edge {}",
198 edge_id.id
199 )
200 }
201 Self::DuplicateProtectedBoundarySegment {
202 first_edge_id,
203 second_edge_id,
204 node_ids,
205 } => write!(
206 formatter,
207 "PLC protected edges {} and {} both reference boundary segment {}-{}",
208 first_edge_id.id, second_edge_id.id, node_ids[0].id, node_ids[1].id
209 ),
210 Self::ProtectedEdgeHasRepeatedNode { edge_id } => {
211 write!(
212 formatter,
213 "PLC protected edge {} repeats a node",
214 edge_id.id
215 )
216 }
217 Self::ProtectedEdgeHasEmptySourceEdgeId { edge_id } => write!(
218 formatter,
219 "PLC protected edge {} has an empty source edge id",
220 edge_id.id
221 ),
222 Self::ProtectedEdgeSourceEdgeStageMismatch {
223 edge_id,
224 source_edge_id,
225 } => write!(
226 formatter,
227 "PLC protected edge {} source edge {} is not a CurveMesh entity",
228 edge_id.id, source_edge_id.id
229 ),
230 Self::UnreferencedNode { node_id } => {
231 write!(
232 formatter,
233 "PLC node {} is not referenced by any facet",
234 node_id.id
235 )
236 }
237 Self::DisconnectedBoundaryComponents { component_count } => write!(
238 formatter,
239 "PLC has {component_count} disconnected boundary components and no shell nesting classification"
240 ),
241 Self::ProtectedEdgeNotOnBoundary { edge_id, node_ids } => write!(
242 formatter,
243 "PLC protected edge {} references non-boundary edge {}-{}",
244 edge_id.id, node_ids[0].id, node_ids[1].id
245 ),
246 Self::OpenBoundaryEdge {
247 node_ids,
248 incidence_count,
249 } => write!(
250 formatter,
251 "PLC edge {}-{} has incidence {incidence_count}, expected 2",
252 node_ids[0].id, node_ids[1].id
253 ),
254 Self::NonManifoldBoundaryEdge {
255 node_ids,
256 incidence_count,
257 } => write!(
258 formatter,
259 "PLC edge {}-{} has non-manifold incidence {incidence_count}, expected 2",
260 node_ids[0].id, node_ids[1].id
261 ),
262 Self::NonManifoldBoundaryVertex {
263 node_id,
264 incident_facet_count,
265 link_component_count,
266 } => write!(
267 formatter,
268 "PLC vertex {} has non-manifold boundary incidence: {incident_facet_count} incident facets form {link_component_count} vertex-link components",
269 node_id.id
270 ),
271 Self::InconsistentBoundaryEdgeOrientation { node_ids } => write!(
272 formatter,
273 "PLC edge {}-{} is not oppositely oriented by its incident facets",
274 node_ids[0].id, node_ids[1].id
275 ),
276 }
277 }
278}
279
280impl std::error::Error for PlcValidationError {}