fj_core/validation/checks/
face_boundary.rs1use crate::{
2 geometry::Geometry,
3 objects::Face,
4 validation::{ValidationCheck, ValidationConfig},
5};
6
7#[derive(Clone, Debug, thiserror::Error)]
16#[error("`Face` has no boundary")]
17pub struct FaceHasNoBoundary {}
18
19impl ValidationCheck<Face> for FaceHasNoBoundary {
20 fn check(
21 object: &Face,
22 _: &Geometry,
23 _: &ValidationConfig,
24 ) -> impl Iterator<Item = Self> {
25 let error = if object.region().exterior().half_edges().is_empty() {
26 Some(FaceHasNoBoundary {})
27 } else {
28 None
29 };
30
31 error.into_iter()
32 }
33}
34
35#[cfg(test)]
36mod tests {
37 use crate::{
38 objects::{Cycle, Face},
39 operations::{
40 build::{BuildCycle, BuildFace},
41 update::{UpdateFace, UpdateRegion},
42 },
43 validation::{checks::FaceHasNoBoundary, ValidationCheck},
44 Core,
45 };
46
47 #[test]
48 fn face_has_no_boundary() -> anyhow::Result<()> {
49 let mut core = Core::new();
50
51 let valid = Face::circle(
52 core.layers.objects.surfaces.xy_plane(),
53 [0., 0.],
54 1.,
55 &mut core,
56 );
57 FaceHasNoBoundary::check_and_return_first_error(
58 &valid,
59 &core.layers.geometry,
60 )?;
61
62 let invalid = valid.update_region(
63 |region, core| region.update_exterior(|_, _| Cycle::empty(), core),
64 &mut core,
65 );
66 FaceHasNoBoundary::check_and_expect_one_error(
67 &invalid,
68 &core.layers.geometry,
69 );
70
71 Ok(())
72 }
73}