embedded_graphics/primitives/polyline/
points.rs

1use crate::{
2    geometry::Point,
3    primitives::{
4        line::{self, Line},
5        polyline::Polyline,
6        PointsIter,
7    },
8};
9
10/// An iterator over all pixel positions on the polyline
11#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
12#[cfg_attr(feature = "defmt", derive(::defmt::Format))]
13pub struct Points<'a> {
14    vertices: &'a [Point],
15    translate: Point,
16    segment_iter: line::Points,
17}
18
19impl<'a> Points<'a> {
20    pub(in crate::primitives) fn new<'b>(polyline: &'b Polyline<'a>) -> Self
21    where
22        'a: 'b,
23    {
24        polyline
25            .vertices
26            .split_first()
27            .and_then(|(start, rest)| {
28                // Polyline is 2 or more vertices long, return an iterator for it
29                rest.get(0).map(|end| Points {
30                    vertices: rest,
31                    translate: polyline.translate,
32                    segment_iter: Line::new(*start + polyline.translate, *end + polyline.translate)
33                        .points(),
34                })
35            })
36            .unwrap_or_else(||
37                // Polyline is less than 2 vertices long. Return a dummy iterator that will short
38                // circuit
39                Points {
40                    vertices: &[],
41                    translate: Point::zero(),
42                    segment_iter: line::Points::empty(),
43                })
44    }
45}
46
47impl<'a> Iterator for Points<'a> {
48    type Item = Point;
49
50    fn next(&mut self) -> Option<Self::Item> {
51        if let Some(p) = self.segment_iter.next() {
52            Some(p)
53        } else {
54            let (start, rest) = self.vertices.split_first()?;
55            let end = rest.get(0)?;
56
57            self.vertices = rest;
58
59            self.segment_iter = Line::new(*start + self.translate, *end + self.translate).points();
60
61            // Skip first point of next line, otherwise we overlap with the previous line
62            self.nth(1)
63        }
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70    use crate::primitives::polyline::tests::SMALL;
71
72    // Ensure that consecutive points are always different
73    #[test]
74    fn no_duplicate_points() {
75        let expected: [Point; 14] = [
76            Point::new(2, 5),
77            Point::new(3, 4),
78            Point::new(4, 3),
79            Point::new(5, 2),
80            Point::new(6, 3),
81            Point::new(7, 3),
82            Point::new(8, 4),
83            Point::new(9, 4),
84            Point::new(10, 5),
85            Point::new(11, 4),
86            Point::new(12, 4),
87            Point::new(13, 3),
88            Point::new(14, 3),
89            Point::new(15, 2),
90        ];
91
92        assert!(Polyline::new(&SMALL).points().eq(expected.iter().copied()))
93    }
94
95    #[test]
96    fn one_point() {
97        let points = &[Point::zero()];
98
99        let polyline = Polyline::new(points);
100
101        assert!(polyline.points().eq(core::iter::empty()));
102    }
103
104    #[test]
105    fn equal_points() {
106        let points: [Point; 3] = [Point::new(2, 5), Point::new(2, 5), Point::new(2, 5)];
107
108        assert!(Polyline::new(&points)
109            .points()
110            .eq(core::iter::once(Point::new(2, 5))));
111    }
112}