fj_kernel/algorithms/sweep/
face.rs1use std::ops::Deref;
2
3use fj_math::{Scalar, Vector};
4use itertools::Itertools;
5
6use crate::{
7 algorithms::{reverse::Reverse, transform::TransformObject},
8 geometry::curve::GlobalPath,
9 objects::{Cycle, Face, Shell},
10 operations::{BuildCycle, Insert, JoinCycle},
11 services::Services,
12 storage::Handle,
13};
14
15use super::{Sweep, SweepCache};
16
17impl Sweep for Handle<Face> {
18 type Swept = Handle<Shell>;
19
20 fn sweep_with_cache(
21 self,
22 path: impl Into<Vector<3>>,
23 cache: &mut SweepCache,
24 services: &mut Services,
25 ) -> Self::Swept {
26 let path = path.into();
27
28 let mut faces = Vec::new();
29
30 let is_negative_sweep = {
31 let u = match self.surface().geometry().u {
32 GlobalPath::Circle(_) => todo!(
33 "Sweeping from faces defined in round surfaces is not \
34 supported"
35 ),
36 GlobalPath::Line(line) => line.direction(),
37 };
38 let v = self.surface().geometry().v;
39
40 let normal = u.cross(&v);
41
42 normal.dot(&path) < Scalar::ZERO
43 };
44
45 let bottom_face = {
46 if is_negative_sweep {
47 self.clone()
48 } else {
49 self.clone().reverse(services)
50 }
51 };
52 faces.push(bottom_face.clone());
53
54 let top_surface =
55 bottom_face.surface().clone().translate(path, services);
56
57 let mut exterior = None;
58 let mut interiors = Vec::new();
59
60 for (i, cycle) in bottom_face.all_cycles().cloned().enumerate() {
61 let cycle = cycle.reverse(services);
62
63 let mut top_edges = Vec::new();
64 for (half_edge, next) in
65 cycle.half_edges().cloned().circular_tuple_windows()
66 {
67 let (face, top_edge) = (
68 half_edge.deref(),
69 next.start_vertex(),
70 self.surface().deref(),
71 self.color(),
72 )
73 .sweep_with_cache(path, cache, services);
74
75 faces.push(face);
76
77 top_edges.push((
78 top_edge,
79 half_edge.curve(),
80 half_edge.boundary(),
81 ));
82 }
83
84 let top_cycle = Cycle::empty()
85 .add_joined_edges(top_edges, services)
86 .insert(services);
87
88 if i == 0 {
89 exterior = Some(top_cycle);
90 } else {
91 interiors.push(top_cycle);
92 };
93 }
94
95 let top_face =
96 Face::new(top_surface, exterior.unwrap(), interiors, self.color());
97
98 let top_face = top_face.insert(services);
99 faces.push(top_face);
100
101 Shell::new(faces).insert(services)
102 }
103}