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

use crate::{
    objects::{
        Curve, GlobalCurve, GlobalVertex, HalfEdge, Surface, SurfaceVertex,
        Vertex,
    },
    path::{GlobalPath, SurfacePath},
};

/// API for building an [`HalfEdge`]
pub struct HalfEdgeBuilder {
    surface: Surface,
}

impl HalfEdgeBuilder {
    /// Construct a new instance of [`HalfEdgeBuilder`]
    ///
    /// Also see [`HalfEdge::build`].
    pub fn new(surface: Surface) -> Self {
        Self { surface }
    }

    /// Build a circle from the given radius
    pub fn circle_from_radius(&self, radius: impl Into<Scalar>) -> HalfEdge {
        let curve = Curve::build(self.surface).circle_from_radius(radius);

        let vertices = {
            let [a_curve, b_curve] =
                [Scalar::ZERO, Scalar::TAU].map(|coord| Point::from([coord]));

            let global_vertex = GlobalVertex::from_position(
                curve.global_form().path().point_from_path_coords(a_curve),
            );

            let surface_vertices = [a_curve, b_curve].map(|point_curve| {
                let point_surface =
                    curve.path().point_from_path_coords(point_curve);
                SurfaceVertex::new(point_surface, self.surface, global_vertex)
            });

            // Can be cleaned up, once `zip` is stable:
            // https://doc.rust-lang.org/std/primitive.array.html#method.zip
            let [a_surface, b_surface] = surface_vertices;
            [(a_curve, a_surface), (b_curve, b_surface)].map(
                |(point_curve, surface_vertex)| {
                    Vertex::new(
                        point_curve,
                        curve.clone(),
                        surface_vertex,
                        global_vertex,
                    )
                },
            )
        };

        HalfEdge::from_curve_and_vertices(curve, vertices)
    }

    /// Build a line segment from two points
    pub fn line_segment_from_points(
        &self,
        points: [impl Into<Point<2>>; 2],
    ) -> HalfEdge {
        let points = points.map(Into::into);

        let global_vertices = points.map(|position| {
            let position = self.surface.point_from_surface_coords(position);
            GlobalVertex::from_position(position)
        });

        let surface_vertices = {
            // Can be cleaned up, once `zip` is stable:
            // https://doc.rust-lang.org/std/primitive.array.html#method.zip
            let [a_surface, b_surface] = points;
            let [a_global, b_global] = global_vertices;
            [(a_surface, a_global), (b_surface, b_global)].map(
                |(point_surface, vertex_global)| {
                    SurfaceVertex::new(
                        point_surface,
                        self.surface,
                        vertex_global,
                    )
                },
            )
        };

        let curve = {
            let path = SurfacePath::Line(Line::from_points(points));
            let curve_global = {
                let points = global_vertices
                    .map(|global_vertex| global_vertex.position());
                GlobalCurve::from_path(GlobalPath::Line(Line::from_points(
                    points,
                )))
            };

            Curve::new(self.surface, path, curve_global)
        };

        let vertices = {
            let [a_global, b_global] = global_vertices;
            let [a_surface, b_surface] = surface_vertices;

            [
                Vertex::new(
                    Point::from([0.]),
                    curve.clone(),
                    a_surface,
                    a_global,
                ),
                Vertex::new(
                    Point::from([1.]),
                    curve.clone(),
                    b_surface,
                    b_global,
                ),
            ]
        };

        HalfEdge::from_curve_and_vertices(curve, vertices)
    }
}