1use 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))]
19pub struct DistanceIterator {
20 center_2x: Point,
21 points: rectangle::Points,
22}
23
24impl 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
45impl 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)]
59mod 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