fj_core/operations/sweep/
half_edge.rs

1use fj_interop::{ext::ArrayExt, Color};
2use fj_math::{Point, Scalar, Vector};
3
4use crate::{
5    geometry::SurfaceGeometry,
6    objects::{Cycle, Face, HalfEdge, Region, Vertex},
7    operations::{
8        build::{BuildCycle, BuildHalfEdge},
9        geometry::UpdateHalfEdgeGeometry,
10        insert::Insert,
11        presentation::SetColor,
12        update::{UpdateCycle, UpdateHalfEdge},
13    },
14    storage::Handle,
15    Core,
16};
17
18use super::{vertex::SweepVertex, SweepCache, SweepSurfacePath};
19
20/// # Sweep a [`HalfEdge`]
21///
22/// See [module documentation] for more information.
23///
24/// [module documentation]: super
25pub trait SweepHalfEdge {
26    /// # Sweep the [`HalfEdge`]
27    ///
28    /// Returns a face, the result of sweeping the edge, as well as the top edge
29    /// of that face, i.e. the edge that is the version of the original edge
30    /// that was translated along the sweep path.
31    ///
32    /// In addition to the usual arguments that many sweep operations require,
33    /// some other ones are needed:
34    ///
35    /// - `end_vertex`, the vertex where the half-edge ends. This is the start
36    ///   vertex of the next half-edge in the cycle.
37    /// - The `surface` that the half-edge is defined on.
38    /// - The `color` of the resulting face, if applicable
39    fn sweep_half_edge(
40        &self,
41        end_vertex: Handle<Vertex>,
42        surface: &SurfaceGeometry,
43        color: Option<Color>,
44        path: impl Into<Vector<3>>,
45        cache: &mut SweepCache,
46        core: &mut Core,
47    ) -> (Face, Handle<HalfEdge>);
48}
49
50impl SweepHalfEdge for Handle<HalfEdge> {
51    fn sweep_half_edge(
52        &self,
53        end_vertex: Handle<Vertex>,
54        surface: &SurfaceGeometry,
55        color: Option<Color>,
56        path: impl Into<Vector<3>>,
57        cache: &mut SweepCache,
58        core: &mut Core,
59    ) -> (Face, Handle<HalfEdge>) {
60        let path = path.into();
61
62        let surface = core
63            .layers
64            .geometry
65            .of_half_edge(self)
66            .path
67            .sweep_surface_path(surface, path, core);
68
69        // Next, we need to define the boundaries of the face. Let's start with
70        // the global vertices and edges.
71        let (vertices, curves) = {
72            let [a, b] = [self.start_vertex().clone(), end_vertex];
73            let (curve_up, c) = b.clone().sweep_vertex(cache, core);
74            let (curve_down, d) = a.clone().sweep_vertex(cache, core);
75
76            (
77                [a, b, c, d],
78                [
79                    Some(self.curve().clone()),
80                    Some(curve_up),
81                    None,
82                    Some(curve_down),
83                ],
84            )
85        };
86
87        // Let's figure out the surface coordinates of the edge vertices.
88        let surface_points = {
89            let [a, b] = self.boundary().inner;
90
91            [
92                [a.t, Scalar::ZERO],
93                [b.t, Scalar::ZERO],
94                [b.t, Scalar::ONE],
95                [a.t, Scalar::ONE],
96            ]
97            .map(Point::from)
98        };
99        let surface_points_next = {
100            let mut points = surface_points;
101            points.rotate_left(1);
102            points
103        };
104
105        // Now, the boundaries of each edge.
106        let boundaries = {
107            let [a, b] = self.boundary().inner;
108            let [c, d] = [0., 1.].map(|coord| Point::from([coord]));
109
110            [[a, b], [c, d], [b, a], [d, c]]
111        };
112
113        let mut exterior = Cycle::empty();
114
115        // Armed with all of that, we're ready to create the edges.
116        let [_edge_bottom, _edge_up, edge_top, _edge_down] = boundaries
117            .zip_ext(surface_points)
118            .zip_ext(surface_points_next)
119            .zip_ext(vertices)
120            .zip_ext(curves)
121            .map(|((((boundary, start), end), start_vertex), curve)| {
122                let half_edge = {
123                    let line_segment = HalfEdge::line_segment(
124                        [start, end],
125                        Some(boundary),
126                        core,
127                    );
128                    let half_edge = line_segment
129                        .update_start_vertex(|_, _| start_vertex, core);
130
131                    let half_edge = if let Some(curve) = curve {
132                        half_edge.update_curve(|_, _| curve, core)
133                    } else {
134                        half_edge
135                    };
136
137                    half_edge.insert(core).set_path(
138                        core.layers.geometry.of_half_edge(&line_segment).path,
139                        &mut core.layers.geometry,
140                    )
141                };
142
143                exterior = exterior.add_half_edges([half_edge.clone()], core);
144
145                half_edge
146            });
147
148        let exterior = exterior.insert(core);
149        let region = Region::new(exterior, []).insert(core);
150
151        if let Some(color) = color {
152            region.set_color(color, core);
153        }
154
155        let face = Face::new(surface, region);
156
157        (face, edge_top)
158    }
159}