1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use itertools::Itertools;
use crate::{
objects::{Cycle, SurfaceVertex},
storage::Handle,
};
use super::{Validate, ValidationConfig};
impl Validate for Cycle {
type Error = CycleValidationError;
fn validate_with_config(
&self,
_: &ValidationConfig,
) -> Result<(), Self::Error> {
CycleValidationError::check_half_edge_connections(self)?;
Ok(())
}
}
#[derive(Clone, Debug, thiserror::Error)]
pub enum CycleValidationError {
#[error(
"`HalfEdge`s of `Cycle` are not connected\n\
- Front vertex of previous `HalfEdge`: {prev:#?}\n\
- Back vertex of next `HalfEdge`: {next:#?}"
)]
HalfEdgeConnection {
prev: Handle<SurfaceVertex>,
next: Handle<SurfaceVertex>,
},
}
impl CycleValidationError {
fn check_half_edge_connections(cycle: &Cycle) -> Result<(), Self> {
for (a, b) in cycle.half_edges().circular_tuple_windows() {
let [_, prev] = a.vertices();
let [next, _] = b.vertices();
let prev = prev.surface_form();
let next = next.surface_form();
if prev.id() != next.id() {
return Err(Self::HalfEdgeConnection {
prev: prev.clone(),
next: next.clone(),
});
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::{
builder::CycleBuilder,
objects::Cycle,
partial::{Partial, PartialCycle, PartialObject},
services::Services,
validate::Validate,
};
#[test]
fn cycle_half_edge_connections() {
let mut services = Services::new();
let valid = {
let mut cycle = PartialCycle::default();
cycle.update_as_polygon_from_points(
services.objects.surfaces.xy_plane(),
[[0., 0.], [1., 0.], [0., 1.]],
);
cycle.build(&mut services.objects)
};
let invalid = {
let mut half_edges = valid
.half_edges()
.map(|half_edge| Partial::from(half_edge.clone()))
.collect::<Vec<_>>();
{
let first_half_edge = half_edges.first_mut().unwrap();
let [first_vertex, _] = &mut first_half_edge.write().vertices;
let surface_vertex = Partial::from_partial(
first_vertex.read().surface_form.read().clone(),
);
first_vertex.write().surface_form = surface_vertex;
}
let half_edges = half_edges
.into_iter()
.map(|half_edge| half_edge.build(&mut services.objects));
Cycle::new(half_edges)
};
assert!(valid.validate().is_ok());
assert!(invalid.validate().is_err());
}
}