| 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 | |