fj_core/operations/sweep/
cycle.rs

1use fj_interop::Color;
2use fj_math::Vector;
3
4use crate::{
5    geometry::SurfaceGeometry,
6    objects::{Cycle, Face},
7    operations::{
8        build::BuildCycle, join::JoinCycle, sweep::half_edge::SweepHalfEdge,
9    },
10    Core,
11};
12
13use super::SweepCache;
14
15/// # Sweep a [`Cycle`]
16///
17/// See [module documentation] for more information.
18///
19/// [module documentation]: super
20pub trait SweepCycle {
21    /// # Sweep the [`Cycle`]
22    ///
23    /// Sweep the cycle into a set of connected faces. Each half-edge in the
24    /// cycle is swept into a face, meaning all resulting faces form a connected
25    /// set of side walls.
26    ///
27    /// Requires the surface that the half-edges of the cycle are defined in,
28    /// and optionally the color of the created faces.
29    ///
30    /// There is no face at the "top" (the end of the sweep path), as we don't
31    /// have enough information here to create that. We just have a single
32    /// cycle, and don't know whether that is supposed to be the only cycle
33    /// within a potential top face, or whether it's an exterior or interior
34    /// one.
35    ///
36    /// For the same reason, there also is no "bottom" face. Additionally,
37    /// whether a bottom face is even desirable depends on the context this
38    /// operation is called in, and therefore falls outside of its scope.
39    fn sweep_cycle(
40        &self,
41        surface: &SurfaceGeometry,
42        color: Option<Color>,
43        path: impl Into<Vector<3>>,
44        cache: &mut SweepCache,
45        core: &mut Core,
46    ) -> SweptCycle;
47}
48
49impl SweepCycle for Cycle {
50    fn sweep_cycle(
51        &self,
52        surface: &SurfaceGeometry,
53        color: Option<Color>,
54        path: impl Into<Vector<3>>,
55        cache: &mut SweepCache,
56        core: &mut Core,
57    ) -> SweptCycle {
58        let path = path.into();
59
60        let mut faces = Vec::new();
61        let mut top_edges = Vec::new();
62
63        for bottom_half_edge_pair in self.half_edges().pairs() {
64            let (bottom_half_edge, bottom_half_edge_next) =
65                bottom_half_edge_pair;
66
67            let (side_face, top_edge) = bottom_half_edge.sweep_half_edge(
68                bottom_half_edge_next.start_vertex().clone(),
69                surface,
70                color,
71                path,
72                cache,
73                core,
74            );
75
76            faces.push(side_face);
77
78            top_edges.push((
79                top_edge,
80                core.layers.geometry.of_half_edge(bottom_half_edge).path,
81                bottom_half_edge.boundary(),
82            ));
83        }
84
85        let top_cycle = Cycle::empty().add_joined_edges(top_edges, core);
86
87        SweptCycle { faces, top_cycle }
88    }
89}
90
91/// The result of sweeping a [`Cycle`]
92///
93/// See [`SweepCycle`].
94pub struct SweptCycle {
95    /// The faces created by sweeping each half-edge of the cycle
96    ///
97    /// See [`SweepCycle::sweep_cycle`] for more information.
98    pub faces: Vec<Face>,
99
100    /// A cycle made up of the "top" half-edges of the resulting faces
101    ///
102    /// "Top" here refers to the place that the sweep path points to from the
103    /// original cycle. Essentially, this is a translated (along the sweep path)
104    /// and reversed version of the original cycle.
105    pub top_cycle: Cycle,
106}