amicola/
geo.rs

1//! Geometry primitives.
2
3use nalgebra::{base::*, Matrix};
4
5pub type V2 = Matrix<f32, U2, U1, ArrayStorage<f32, U2, U1>>;
6pub type V4 = Matrix<f32, U4, U1, ArrayStorage<f32, U4, U1>>;
7
8/// A path is an input to the rasterizer, a series of vertices.
9#[derive(Debug, PartialEq, Clone)]
10pub struct Path {
11    vertices: Vec<V2>,
12}
13
14impl Path {
15    /// Returns an iterator over edges between the vertices of the path.
16    pub fn edges<'a>(&'a self) -> impl Iterator<Item = (&'a V2, &'a V2)> + 'a {
17        self.vertices().iter().zip(self.vertices().iter().skip(1))
18    }
19
20    /// Returns an iterator over edges between the vertices of the path, including an inferred
21    /// edge between the last and vertex, to close the path.
22    pub fn edges_wrapped<'a>(&'a self) -> impl Iterator<Item = (&'a V2, &'a V2)> + 'a {
23        let wrap_around = self
24            .vertices
25            .iter()
26            .skip(self.vertices.len() - 1)
27            .zip(self.vertices.iter().take(1));
28        self.edges().chain(wrap_around)
29    }
30
31    pub fn vertices(&self) -> &[V2] { &self.vertices }
32}
33
34impl From<Vec<V2>> for Path {
35    fn from(vertices: Vec<V2>) -> Self { Path { vertices } }
36}
37
38#[cfg(test)]
39mod test {
40    use super::*;
41
42    #[test]
43    fn polygon_edges() {
44        let polygon = Path {
45            vertices: vec![V2::new(0.0, 0.0), V2::new(0.0, 1.0), V2::new(1.0, 0.0)],
46        };
47        assert_eq!(
48            polygon.edges().collect::<Vec<(&V2, &V2)>>(),
49            vec![
50                (&V2::new(0.0, 0.0), &V2::new(0.0, 1.0)),
51                (&V2::new(0.0, 1.0), &V2::new(1.0, 0.0)),
52                (&V2::new(1.0, 0.0), &V2::new(0.0, 0.0))
53            ]
54        );
55    }
56}