Skip to main content

runmat_meshing_plc/validate/
errors.rs

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 {}