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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
use std::fmt;

use crate::builder::EdgeBuilder;

use super::{Curve, GlobalCurve, GlobalVertex, Vertex};

/// An edge
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct Edge {
    curve: Curve,
    vertices: VerticesOfEdge<Vertex>,
    global: GlobalEdge,
}

impl Edge {
    /// Build an edge using [`EdgeBuilder`]
    pub fn build() -> EdgeBuilder {
        EdgeBuilder
    }

    /// Create a new instance of `Edge`
    ///
    /// If you only have a curve and the edge vertices, please check out
    /// [`Edge::from_curve_and_vertices`], which is a convenience wrapper around
    /// this method, which creates an instance of [`GlobalEdge`].
    ///
    /// # Panics
    ///
    /// Panics, if the provided [`GlobalEdge`] instance doesn't refer to the
    /// same [`GlobalCurve`] and [`GlobalVertex`] instances that the other
    /// objects that are passed refer to.
    pub fn new(
        curve: Curve,
        vertices: VerticesOfEdge<Vertex>,
        global: GlobalEdge,
    ) -> Self {
        assert_eq!(curve.global(), global.curve());
        assert_eq!(&vertices.to_global(), global.vertices());

        Self {
            curve,
            vertices,
            global,
        }
    }

    /// Create a new instance of `Edge` from a curve and vertices
    ///
    /// The [`GlobalEdge`] instance is created from the provided curve and
    /// vertices. Please refer to [`Edge::new`], if you already have a
    /// [`GlobalEdge`] instance that you can provide.
    pub fn from_curve_and_vertices(
        curve: Curve,
        vertices: VerticesOfEdge<Vertex>,
    ) -> Self {
        let global = GlobalEdge::new(*curve.global(), vertices.to_global());
        Self::new(curve, vertices, global)
    }

    /// Access the curve that defines the edge's geometry
    ///
    /// The edge can be a segment of the curve that is bounded by two vertices,
    /// or if the curve is continuous (i.e. connects to itself), the edge could
    /// be defined by the whole curve, and have no bounding vertices.
    pub fn curve(&self) -> &Curve {
        &self.curve
    }

    /// Access the vertices that bound the edge on the curve
    ///
    /// An edge has either two bounding vertices or none. The latter is possible
    /// if the edge's curve is continuous (i.e. connects to itself), and defines
    /// the whole edge.
    pub fn vertices(&self) -> &VerticesOfEdge<Vertex> {
        &self.vertices
    }

    /// Access the global form of this edge
    pub fn global(&self) -> &GlobalEdge {
        &self.global
    }
}

impl fmt::Display for Edge {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.vertices().0 {
            Some(vertices) => {
                let [a, b] = vertices.map(|vertex| vertex.position());
                write!(f, "edge from {:?} to {:?}", a, b)?
            }
            None => write!(f, "continuous edge")?,
        }

        write!(f, " on {:?}", self.curve().global())?;

        Ok(())
    }
}

/// An edge, defined in global (3D) coordinates
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct GlobalEdge {
    curve: GlobalCurve,
    vertices: VerticesOfEdge<GlobalVertex>,
}

impl GlobalEdge {
    /// Create a new instance
    pub fn new(
        curve: GlobalCurve,
        vertices: VerticesOfEdge<GlobalVertex>,
    ) -> Self {
        Self { curve, vertices }
    }

    /// Access the curve that defines the edge's geometry
    ///
    /// The edge can be a segment of the curve that is bounded by two vertices,
    /// or if the curve is continuous (i.e. connects to itself), the edge could
    /// be defined by the whole curve, and have no bounding vertices.
    pub fn curve(&self) -> &GlobalCurve {
        &self.curve
    }

    /// Access the vertices that bound the edge on the curve
    ///
    /// An edge has either two bounding vertices or none. The latter is possible
    /// if the edge's curve is continuous (i.e. connects to itself), and defines
    /// the whole edge.
    pub fn vertices(&self) -> &VerticesOfEdge<GlobalVertex> {
        &self.vertices
    }
}

/// The vertices that bound an edge
///
/// This struct is generic over the actual vertex type used, but typically, `T`
/// will either be [`Vertex`] or [`GlobalVertex`].
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct VerticesOfEdge<T>(Option<[T; 2]>);

impl<T> VerticesOfEdge<T> {
    /// Construct an instance of `VerticesOfEdge` from two vertices
    pub fn from_vertices(vertices: [T; 2]) -> Self {
        Self(Some(vertices))
    }

    /// Construct an instance of `VerticesOfEdge` without vertices
    pub fn none() -> Self {
        Self(None)
    }

    /// Access the vertices
    pub fn get(&self) -> Option<[&T; 2]> {
        self.0.as_ref().map(|vertices| {
            // Can be cleaned up once `each_ref` is stable:
            // https://doc.rust-lang.org/std/primitive.array.html#method.each_ref
            let [a, b] = vertices;
            [a, b]
        })
    }

    /// Access the two vertices
    ///
    /// # Panics
    ///
    /// Panics, if the edge has no vertices.
    pub fn get_or_panic(&self) -> [&T; 2] {
        self.get().expect("Expected edge to have vertices")
    }

    /// Iterate over the vertices
    pub fn iter(&self) -> impl Iterator<Item = &T> {
        self.0.iter().flatten()
    }

    /// Map each vertex using the provided function
    pub fn map<F>(self, f: F) -> Self
    where
        F: FnMut(T) -> T,
    {
        Self(self.convert(f))
    }

    /// Convert each vertex using the provided function
    pub fn convert<F, U>(self, f: F) -> Option<[U; 2]>
    where
        F: FnMut(T) -> U,
    {
        self.0.map(|vertices| vertices.map(f))
    }
}

impl VerticesOfEdge<Vertex> {
    /// Reverse the order of vertices
    ///
    /// Makes sure that the local coordinates are still correct.
    pub fn reverse(self) -> Self {
        Self(self.0.map(|[a, b]| {
            [
                Vertex::new(-b.position(), *b.global()),
                Vertex::new(-a.position(), *a.global()),
            ]
        }))
    }

    /// Convert this instance into its global variant
    pub fn to_global(&self) -> VerticesOfEdge<GlobalVertex> {
        VerticesOfEdge(self.convert(|vertex| *vertex.global()))
    }
}