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

use crate::{
    objects::Surface,
    partial::{Partial, PartialGlobalEdge, PartialHalfEdge},
};

use super::{CurveBuilder, SurfaceVertexBuilder};

/// Builder API for [`PartialHalfEdge`]
pub trait HalfEdgeBuilder {
    /// Update partial half-edge to be a circle, from the given radius
    fn update_as_circle_from_radius(
        &mut self,
        radius: impl Into<Scalar>,
    ) -> &mut Self;

    /// Update partial half-edge to be a line segment, from the given points
    fn update_as_line_segment_from_points(
        &mut self,
        surface: Partial<Surface>,
        points: [impl Into<Point<2>>; 2],
    ) -> &mut Self;

    /// Update partial half-edge to be a line segment
    fn update_as_line_segment(&mut self) -> &mut Self;
}

impl HalfEdgeBuilder for PartialHalfEdge {
    fn update_as_circle_from_radius(
        &mut self,
        radius: impl Into<Scalar>,
    ) -> &mut Self {
        let mut curve = self.curve();
        curve.write().update_as_circle_from_radius(radius);

        let path = curve
            .read()
            .path
            .expect("Expected path that was just created");

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

        let mut surface_vertex = {
            let [vertex, _] = &mut self.vertices;
            vertex.write().surface_form.clone()
        };
        surface_vertex.write().position =
            Some(path.point_from_path_coords(a_curve));

        for (vertex, point_curve) in
            self.vertices.each_mut_ext().zip_ext([a_curve, b_curve])
        {
            let mut vertex = vertex.write();
            vertex.position = Some(point_curve);
            vertex.surface_form = surface_vertex.clone();
        }

        let global_vertex = surface_vertex.read().global_form.clone();
        self.global_form.write().vertices =
            [global_vertex.clone(), global_vertex];

        self
    }

    fn update_as_line_segment_from_points(
        &mut self,
        surface: Partial<Surface>,
        points: [impl Into<Point<2>>; 2],
    ) -> &mut Self {
        for (vertex, point) in self.vertices.each_mut_ext().zip_ext(points) {
            let mut vertex = vertex.write();
            vertex.curve.write().surface = surface.clone();

            let mut surface_form = vertex.surface_form.write();
            surface_form.position = Some(point.into());
            surface_form.surface = surface.clone();
            surface_form.infer_global_position();
        }

        self.update_as_line_segment()
    }

    fn update_as_line_segment(&mut self) -> &mut Self {
        let points_surface = self.vertices.each_ref_ext().map(|vertex| {
            vertex
                .read()
                .surface_form
                .read()
                .position
                .expect("Can't infer line segment without surface position")
        });

        let mut curve = self.curve();
        curve.write().update_as_line_from_points(points_surface);

        for (vertex, position) in self.vertices.each_mut_ext().zip_ext([0., 1.])
        {
            vertex.write().position = Some([position].into());
            vertex.write().curve = curve.clone();
        }

        self.global_form.write().curve = curve.read().global_form.clone();

        self
    }
}

/// Builder API for [`PartialGlobalEdge`]
pub trait GlobalEdgeBuilder {
    // No methods are currently defined. This trait serves as a placeholder, to
    // make it clear where to add such methods, once necessary.
}

impl GlobalEdgeBuilder for PartialGlobalEdge {}