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
use fj_math::Point;
use itertools::Itertools;

use crate::{
    geometry::surface::SurfaceGeometry,
    objects::{HalfEdge, Objects},
    partial::{Partial, PartialCycle},
    services::Service,
};

use super::{HalfEdgeBuilder, ObjectArgument};

/// Builder API for [`PartialCycle`]
pub trait CycleBuilder {
    /// Add a new half-edge to the cycle
    ///
    /// Creates a half-edge and adds it to the cycle. The new half-edge is
    /// connected to the front vertex of the last half-edge , and the back
    /// vertex of the first edge, making sure the half-edges actually form a
    /// cycle.
    ///
    /// If this is the first half-edge being added, it is connected to itself,
    /// meaning its front and back vertices are the same.
    fn add_half_edge(
        &mut self,
        objects: &mut Service<Objects>,
    ) -> Partial<HalfEdge>;

    /// Update cycle as a polygon from the provided points
    fn update_as_polygon_from_points<O, P>(
        &mut self,
        points: O,
        objects: &mut Service<Objects>,
    ) -> O::SameSize<Partial<HalfEdge>>
    where
        O: ObjectArgument<P>,
        P: Into<Point<2>>;

    /// Connect the cycles to the provided half-edges
    ///
    /// Assumes that the provided half-edges, once translated into local
    /// equivalents of this cycle, form a cycle themselves.
    ///
    /// Returns the local equivalents of the provided half-edges.
    fn connect_to_closed_edges<O>(
        &mut self,
        edges: O,
        surface: &SurfaceGeometry,
        objects: &mut Service<Objects>,
    ) -> O::SameSize<Partial<HalfEdge>>
    where
        O: ObjectArgument<Partial<HalfEdge>>;
}

impl CycleBuilder for PartialCycle {
    fn add_half_edge(
        &mut self,
        objects: &mut Service<Objects>,
    ) -> Partial<HalfEdge> {
        let half_edge = Partial::new(objects);
        self.half_edges.push(half_edge.clone());
        half_edge
    }

    fn update_as_polygon_from_points<O, P>(
        &mut self,
        points: O,
        objects: &mut Service<Objects>,
    ) -> O::SameSize<Partial<HalfEdge>>
    where
        O: ObjectArgument<P>,
        P: Into<Point<2>>,
    {
        let mut start_positions = Vec::new();
        let half_edges = points.map(|point| {
            start_positions.push(point.into());
            self.add_half_edge(objects)
        });

        for ((start, end), half_edge) in start_positions
            .into_iter()
            .circular_tuple_windows()
            .zip(&mut self.half_edges)
        {
            half_edge.write().update_as_line_segment(start, end);
        }

        half_edges
    }

    fn connect_to_closed_edges<O>(
        &mut self,
        edges: O,
        surface: &SurfaceGeometry,
        objects: &mut Service<Objects>,
    ) -> O::SameSize<Partial<HalfEdge>>
    where
        O: ObjectArgument<Partial<HalfEdge>>,
    {
        edges.map_with_prev(|other, prev| {
            let mut this = self.add_half_edge(objects);
            this.write().update_from_other_edge(&other, &prev, surface);
            this
        })
    }
}