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}