1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use std::ops::Deref;

use fj_math::{Scalar, Vector};
use itertools::Itertools;

use crate::{
    algorithms::{reverse::Reverse, transform::TransformObject},
    builder::CycleBuilder,
    geometry::curve::GlobalPath,
    objects::{Face, Shell},
    operations::Insert,
    services::Services,
    storage::Handle,
};

use super::{Sweep, SweepCache};

impl Sweep for Handle<Face> {
    type Swept = Handle<Shell>;

    fn sweep_with_cache(
        self,
        path: impl Into<Vector<3>>,
        cache: &mut SweepCache,
        services: &mut Services,
    ) -> Self::Swept {
        let path = path.into();

        let mut faces = Vec::new();

        let is_negative_sweep = {
            let u = match self.surface().geometry().u {
                GlobalPath::Circle(_) => todo!(
                    "Sweeping from faces defined in round surfaces is not \
                    supported"
                ),
                GlobalPath::Line(line) => line.direction(),
            };
            let v = self.surface().geometry().v;

            let normal = u.cross(&v);

            normal.dot(&path) < Scalar::ZERO
        };

        let bottom_face = {
            if is_negative_sweep {
                self.clone()
            } else {
                self.clone().reverse(services)
            }
        };
        faces.push(bottom_face.clone());

        let top_surface =
            bottom_face.surface().clone().translate(path, services);

        let mut exterior = None;
        let mut interiors = Vec::new();

        for (i, cycle) in bottom_face.all_cycles().cloned().enumerate() {
            let cycle = cycle.reverse(services);

            let mut top_edges = Vec::new();
            for (half_edge, next) in
                cycle.half_edges().cloned().circular_tuple_windows()
            {
                let (face, top_edge) = (
                    half_edge.deref(),
                    next.start_vertex(),
                    self.surface().deref(),
                    self.color(),
                )
                    .sweep_with_cache(path, cache, services);

                faces.push(face);

                top_edges.push((
                    top_edge,
                    half_edge.curve(),
                    half_edge.boundary(),
                ));
            }

            let top_cycle = CycleBuilder::connect_to_edges(top_edges, services)
                .build(services);

            if i == 0 {
                exterior = Some(top_cycle.insert(services));
            } else {
                interiors.push(top_cycle.insert(services));
            };
        }

        let top_face =
            Face::new(top_surface, exterior.unwrap(), interiors, self.color());

        let top_face = top_face.insert(services);
        faces.push(top_face);

        Shell::new(faces).insert(services)
    }
}