fj_core/validation/checks/
face_boundary.rs

1use crate::{
2    geometry::Geometry,
3    objects::Face,
4    validation::{ValidationCheck, ValidationConfig},
5};
6
7/// [`Face`] has no boundary
8///
9/// A face must have a boundary, meaning its exterior cycle must not be empty.
10/// Checking *that* the exterior cycle is not empty is enough, as
11/// [`AdjacentHalfEdgesNotConnected`] makes sure that any cycle that is not
12/// empty, is closed.
13///
14/// [`AdjacentHalfEdgesNotConnected`]: super::AdjacentHalfEdgesNotConnected
15#[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}