fj_kernel/validate/
solid.rs1use std::iter::repeat;
2
3use crate::{
4 objects::{Solid, Vertex},
5 storage::Handle,
6};
7use fj_math::Point;
8
9use super::{Validate, ValidationConfig, ValidationError};
10
11impl Validate for Solid {
12 fn validate_with_config(
13 &self,
14 config: &ValidationConfig,
15 errors: &mut Vec<ValidationError>,
16 ) {
17 SolidValidationError::check_vertices(self, config, errors)
18 }
19}
20
21#[derive(Clone, Debug, thiserror::Error)]
23pub enum SolidValidationError {
24 #[error(
26 "Solid contains Vertices that are coincident but not identical\n
27 Vertex 1: {vertex_a:#?} ({position_a:?})
28 Vertex 2: {vertex_b:#?} ({position_b:?})"
29 )]
30 DistinctVerticesCoincide {
31 vertex_a: Handle<Vertex>,
33
34 vertex_b: Handle<Vertex>,
36
37 position_a: Point<3>,
39
40 position_b: Point<3>,
42 },
43
44 #[error(
46 "Solid contains Vertices that are identical but do not coincide\n
47 Vertex 1: {vertex_a:#?} ({position_a:?})
48 Vertex 2: {vertex_b:#?} ({position_b:?})"
49 )]
50 IdenticalVerticesNotCoincident {
51 vertex_a: Handle<Vertex>,
53
54 vertex_b: Handle<Vertex>,
56
57 position_a: Point<3>,
59
60 position_b: Point<3>,
62 },
63}
64
65impl SolidValidationError {
66 fn check_vertices(
67 solid: &Solid,
68 config: &ValidationConfig,
69 errors: &mut Vec<ValidationError>,
70 ) {
71 let vertices: Vec<(Point<3>, Handle<Vertex>)> = solid
72 .shells()
73 .flat_map(|s| s.faces())
74 .flat_map(|face| {
75 face.all_cycles()
76 .flat_map(|cycle| cycle.half_edges().cloned())
77 .zip(repeat(face.surface().geometry()))
78 })
79 .map(|(h, s)| {
80 (
81 s.point_from_surface_coords(h.start_position()),
82 h.start_vertex().clone(),
83 )
84 })
85 .collect();
86
87 for (position_a, vertex_a) in &vertices {
91 for (position_b, vertex_b) in &vertices {
92 let vertices_are_identical = vertex_a.id() == vertex_b.id();
93 let vertices_are_not_identical = !vertices_are_identical;
94
95 let too_far_to_be_identical = position_a
96 .distance_to(position_b)
97 > config.identical_max_distance;
98 let too_close_to_be_distinct = position_a
99 .distance_to(position_b)
100 < config.distinct_min_distance;
101
102 if vertices_are_identical && too_far_to_be_identical {
103 errors.push(
104 Self::IdenticalVerticesNotCoincident {
105 vertex_a: vertex_a.clone(),
106 vertex_b: vertex_b.clone(),
107 position_a: *position_a,
108 position_b: *position_b,
109 }
110 .into(),
111 )
112 }
113
114 if vertices_are_not_identical && too_close_to_be_distinct {
115 errors.push(
116 Self::DistinctVerticesCoincide {
117 vertex_a: vertex_a.clone(),
118 vertex_b: vertex_b.clone(),
119 position_a: *position_a,
120 position_b: *position_b,
121 }
122 .into(),
123 )
124 }
125 }
126 }
127 }
128}