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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use fj_interop::mesh::Color;
use fj_math::{Line, Point, Scalar};

use crate::{
    algorithms::approx::Tolerance,
    objects::{
        Curve, CurveKind, Edge, GlobalCurve, GlobalEdge, GlobalVertex, Surface,
        SweptCurve, Vertex, VerticesOfEdge,
    },
};

use super::{Path, Sweep};

impl Sweep for (Vertex, Surface) {
    type Swept = Edge;

    fn sweep(
        self,
        path: impl Into<Path>,
        tolerance: impl Into<Tolerance>,
        color: Color,
    ) -> Self::Swept {
        let (vertex, surface) = self;
        let path = path.into();

        // The result of sweeping a `Vertex` is an `Edge`. Seems
        // straight-forward at first, but there are some subtleties we need to
        // understand:
        //
        // 1. To create an `Edge`, we need the `Curve` that defines it. A
        //    `Curve` is defined in a `Surface`, and we're going to need that to
        //    create the `Curve`. Which is why this `Sweep` implementation is
        //    for `(Vertex, Surface)`, and not just for `Vertex`.
        // 2. Please note that, while the result `Edge` has two vertices, our
        //    input `Vertex` is not one of them! It can't be, unless the `Curve`
        //    of the resulting `Edge` happens to be the same `Curve` that the
        //    input `Vertex` is defined on. That would be an edge case that
        //    probably can't result in anything valid, and we're going to ignore
        //    it for now.
        // 3. This means, we have to compute everything that defines the
        //    resulting `Edge`: The `Curve`, the vertices, and the
        //    `GlobalCurve`.
        //
        // Before we get to that though, let's make sure that whoever called
        // this didn't give us bad input.

        // So, we're supposed to create the `Edge` by sweeping a `Vertex` using
        // `path`. Unless `path` is identical to the path that created the
        // `Surface`, this doesn't make any sense.
        //
        // Further, the `Curve` that was swept to create the `Surface` needs to
        // be the same `Curve` that the input `Vertex` is defined on. If it's
        // not, we have no way of knowing the surface coordinates of the input
        // `Vertex` on the `Surface`, and we're going to need to do that further
        // down.
        //
        // Let's make sure that these requirements are met.
        {
            let Surface::SweptCurve(SweptCurve {
                curve: surface_curve,
                path: surface_path,
            }) = surface;

            assert_eq!(vertex.curve().global().kind(), &surface_curve);
            assert_eq!(path.inner(), surface_path);
        }

        // With that out of the way, let's start by creating the `GlobalEdge`,
        // as that is the most straight-forward part of this operations, and
        // we're going to need it soon anyway.
        let edge_global = vertex.global().sweep(path, tolerance, color);

        // Next, let's compute the surface coordinates of the two vertices of
        // the output `Edge`, as we're going to need these for the rest of this
        // operation.
        //
        // They both share a u-coordinate, which is the t-coordinate of our
        // input `Vertex`. Remember, we validated above, that the `Curve` of the
        // `Surface` and the curve of the input `Vertex` are the same, so we can
        // do that.
        //
        // Now remember what we also validated above: That `path`, which we're
        // using to create the output `Edge`, also created the `Surface`, and
        // thereby defined its coordinate system. That makes the v-coordinates
        // straight-forward: The start of the edge is at zero, the end is at
        // one.
        let u = vertex.position().t;
        let v_a = Scalar::ZERO;
        let v_b = Scalar::ONE;

        // Armed with those coordinates, creating the `Curve` of the output
        // `Edge` becomes straight-forward.
        let curve = {
            let a = Point::from([u, v_a]);
            let b = Point::from([u, v_b]);

            let line = Line::from_points([a, b]);

            Curve::new(surface, CurveKind::Line(line), *edge_global.curve())
        };

        // And now the vertices. Again, nothing wild here.
        let vertices = {
            let [&a, &b] = edge_global.vertices().get_or_panic();

            let a = Vertex::new([v_a], curve, a);
            let b = Vertex::new([v_b], curve, b);

            VerticesOfEdge::from_vertices([a, b])
        };

        // And finally, creating the output `Edge` is just a matter of
        // assembling the pieces we've already created.
        Edge::new(curve, vertices, edge_global)
    }
}

impl Sweep for GlobalVertex {
    type Swept = GlobalEdge;

    fn sweep(
        self,
        path: impl Into<Path>,
        _: impl Into<Tolerance>,
        _: Color,
    ) -> Self::Swept {
        let a = self;
        let b =
            GlobalVertex::from_position(self.position() + path.into().inner());

        let curve =
            GlobalCurve::build().line_from_points([a.position(), b.position()]);

        GlobalEdge::new(curve, VerticesOfEdge::from_vertices([a, b]))
    }
}