fj_kernel/algorithms/sweep/
face.rs

1use 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}