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
use fj_math::{Scalar, Vector};

use crate::{
    geometry::GlobalPath,
    objects::{Face, Sketch, Solid, Surface},
    operations::{insert::Insert, reverse::Reverse},
    services::Services,
    storage::Handle,
};

use super::{face::SweepFace, SweepCache};

/// # Sweep a [`Sketch`]
///
/// See [module documentation] for more information.
///
/// [module documentation]: super
pub trait SweepSketch {
    /// # Sweep the [`Sketch`]
    fn sweep_sketch(
        &self,
        surface: Handle<Surface>,
        path: impl Into<Vector<3>>,
        services: &mut Services,
    ) -> Solid;
}

impl SweepSketch for Sketch {
    fn sweep_sketch(
        &self,
        surface: Handle<Surface>,
        path: impl Into<Vector<3>>,
        services: &mut Services,
    ) -> Solid {
        let path = path.into();
        let mut cache = SweepCache::default();

        let mut shells = Vec::new();
        for region in self.regions() {
            let region = {
                // The following code assumes that the sketch is winded counter-
                // clockwise. Let's check that real quick.
                assert!(region.exterior().winding().is_ccw());

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

                    let normal = u.cross(&v);

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

                if is_negative_sweep {
                    region.clone()
                } else {
                    region.reverse(services).insert(services)
                }
            };

            let face =
                Face::new(surface.clone(), region.clone()).insert(services);
            let shell =
                face.sweep_face(path, &mut cache, services).insert(services);
            shells.push(shell);
        }

        Solid::new(shells)
    }
}