1 | use crate::{ |
2 | geometry::{Point, PointExt}, |
3 | primitives::{ |
4 | rectangle::{self, Rectangle}, |
5 | PointsIter, |
6 | }, |
7 | }; |
8 | |
9 | /// Iterator that returns the squared distance to the center for all points in the bounding box. |
10 | /// |
11 | /// The iterator returns a tuple of three values: |
12 | /// |
13 | /// 1. The current position inside the bounding box. |
14 | /// 2. The difference between the current position and the center point of the bounding box. |
15 | /// Note that this value is scaled up by a factor of 2 to increase the resolution. |
16 | /// 3. The squared length of the second value. |
17 | #[derive (Clone, Eq, PartialEq, Hash, Debug)] |
18 | #[cfg_attr (feature = "defmt" , derive(::defmt::Format))] |
19 | pub struct DistanceIterator { |
20 | center_2x: Point, |
21 | points: rectangle::Points, |
22 | } |
23 | |
24 | impl DistanceIterator { |
25 | /// Creates a distance iterator for the given bounding box. |
26 | /// |
27 | /// Note that `DistanceIterator` internally uses coordinates that are scaled up by a factor |
28 | /// of two to increase the resolution. The given center point must be scaled up by the caller. |
29 | pub fn new(center_2x: Point, bounding_box: &Rectangle) -> Self { |
30 | Self { |
31 | center_2x, |
32 | points: bounding_box.points(), |
33 | } |
34 | } |
35 | |
36 | /// Creates an empty distance iterator. |
37 | pub const fn empty() -> Self { |
38 | Self { |
39 | center_2x: Point::zero(), |
40 | points: rectangle::Points::empty(), |
41 | } |
42 | } |
43 | } |
44 | |
45 | impl Iterator for DistanceIterator { |
46 | type Item = (Point, Point, u32); |
47 | |
48 | fn next(&mut self) -> Option<Self::Item> { |
49 | self.points.next().map(|point: Point| { |
50 | let delta: Point = point * 2 - self.center_2x; |
51 | let distance: u32 = delta.length_squared() as u32; |
52 | |
53 | (point, delta, distance) |
54 | }) |
55 | } |
56 | } |
57 | |
58 | #[cfg (test)] |
59 | mod tests { |
60 | use super::*; |
61 | |
62 | use crate::{geometry::Dimensions, primitives::Circle}; |
63 | |
64 | #[test ] |
65 | fn distance_iter() { |
66 | let circle = Circle::new(Point::zero(), 3); |
67 | |
68 | let mut iter = DistanceIterator::new(circle.center_2x(), &circle.bounding_box()); |
69 | assert_eq!(iter.next(), Some((Point::new(0, 0), Point::new(-2, -2), 8))); |
70 | assert_eq!(iter.next(), Some((Point::new(1, 0), Point::new(0, -2), 4))); |
71 | assert_eq!(iter.next(), Some((Point::new(2, 0), Point::new(2, -2), 8))); |
72 | assert_eq!(iter.next(), Some((Point::new(0, 1), Point::new(-2, 0), 4))); |
73 | assert_eq!(iter.next(), Some((Point::new(1, 1), Point::new(0, 0), 0))); |
74 | assert_eq!(iter.next(), Some((Point::new(2, 1), Point::new(2, 0), 4))); |
75 | assert_eq!(iter.next(), Some((Point::new(0, 2), Point::new(-2, 2), 8))); |
76 | assert_eq!(iter.next(), Some((Point::new(1, 2), Point::new(0, 2), 4))); |
77 | assert_eq!(iter.next(), Some((Point::new(2, 2), Point::new(2, 2), 8))); |
78 | assert_eq!(iter.next(), None); |
79 | } |
80 | |
81 | #[test ] |
82 | fn distance_iter_empty() { |
83 | let mut iter = DistanceIterator::empty(); |
84 | assert_eq!(iter.next(), None); |
85 | } |
86 | } |
87 | |