fj_core/operations/build/
face.rs

1use std::{array, borrow::Borrow};
2
3use fj_interop::ext::ArrayExt;
4use fj_math::{Point, Scalar};
5
6use crate::{
7    objects::{Cycle, Face, HalfEdge, Region, Surface, Vertex},
8    operations::{
9        build::{BuildCycle, BuildRegion, BuildSurface},
10        insert::{Insert, IsInserted, IsInsertedNo},
11    },
12    storage::Handle,
13    Core,
14};
15
16/// Build a [`Face`]
17///
18/// See [module-level documentation] for context.
19///
20/// [module-level documentation]: super
21pub trait BuildFace {
22    /// Build a face with an empty exterior, no interiors, and no color
23    fn unbound(surface: Handle<Surface>, core: &mut Core) -> Face {
24        let exterior = Cycle::empty().insert(core);
25        let region = Region::new(exterior, []).insert(core);
26        Face::new(surface, region)
27    }
28
29    /// Build a circle
30    fn circle(
31        surface: Handle<Surface>,
32        center: impl Into<Point<2>>,
33        radius: impl Into<Scalar>,
34        core: &mut Core,
35    ) -> Face {
36        let region = Region::circle(center, radius, core).insert(core);
37        Face::new(surface, region)
38    }
39
40    /// Build a triangle
41    fn triangle(
42        points: [impl Into<Point<3>>; 3],
43        core: &mut Core,
44    ) -> Polygon<3> {
45        let (surface, points_surface) =
46            Surface::plane_from_points(points, core);
47
48        let face = Face::polygon(surface, points_surface, core);
49
50        let half_edges = {
51            let mut edges =
52                face.region().exterior().half_edges().iter().cloned();
53
54            let array = array::from_fn(|_| edges.next()).map(|edge| {
55                edge.expect("Just asserted that there are three edges")
56            });
57
58            assert!(edges.next().is_none());
59
60            array
61        };
62        let vertices = half_edges
63            .each_ref_ext()
64            .map(|edge: &Handle<HalfEdge>| edge.start_vertex().clone());
65
66        Polygon {
67            face,
68            half_edges,
69            vertices,
70        }
71    }
72
73    /// Build a polygon
74    fn polygon<P, Ps>(
75        surface: Handle<Surface>,
76        points: Ps,
77        core: &mut Core,
78    ) -> Face
79    where
80        P: Into<Point<2>>,
81        Ps: IntoIterator<Item = P>,
82        Ps::IntoIter: Clone + ExactSizeIterator,
83    {
84        let region = Region::polygon(points, core).insert(core);
85        Face::new(surface, region)
86    }
87}
88
89impl BuildFace for Face {}
90
91/// A polygon
92///
93/// # Implementation Note
94///
95/// Currently code that deals with `Polygon` might assume that the polygon has
96/// no holes. Unless you create a `Polygon` yourself, or modify a `Polygon`'s
97/// `face` field to have interior cycles, this should not affect you.
98pub struct Polygon<const D: usize, I: IsInserted = IsInsertedNo> {
99    /// The face that forms the polygon
100    pub face: I::T<Face>,
101
102    /// The half-edges of the polygon
103    pub half_edges: [Handle<HalfEdge>; D],
104
105    /// The vertices of the polygon
106    pub vertices: [Handle<Vertex>; D],
107}
108
109impl<const D: usize, I: IsInserted> Polygon<D, I> {
110    /// Replace the face of the polygon
111    ///
112    /// Returns a new instance of `Polygon` with the replaced face. Also updates
113    /// the other fields of `Polygon` to match the new face.
114    pub fn replace_face(&self, face: I::T<Face>) -> Self {
115        let half_edges = array::from_fn(|i| {
116            face.borrow()
117                .region()
118                .exterior()
119                .half_edges()
120                .nth(i)
121                .expect("Operation should not have changed length of cycle")
122                .clone()
123        });
124        let vertices = array::from_fn(|i| {
125            // The duplicated code here is unfortunate, but unless we get a
126            // stable `array::each_ref` and something like `array::unzip`, I'm
127            // not sure how to avoid it.
128            face.borrow()
129                .region()
130                .exterior()
131                .half_edges()
132                .nth(i)
133                .expect("Operation should not have changed length of cycle")
134                .start_vertex()
135                .clone()
136        });
137
138        Self {
139            face,
140            half_edges,
141            vertices,
142        }
143    }
144}