embedded_graphics/primitives/circle/
points.rs1use core::ops::Range;
2
3use crate::{
4 geometry::{Dimensions, Point, PointExt},
5 primitives::{circle::Circle, common::Scanline},
6};
7
8#[derive(Clone, Eq, PartialEq, Hash, Debug)]
10#[cfg_attr(feature = "defmt", derive(::defmt::Format))]
11pub struct Points {
12 scanlines: Scanlines,
13 current_scanline: Scanline,
14}
15
16impl Points {
17 pub(in crate::primitives) fn new(circle: &Circle) -> Self {
18 Self {
19 scanlines: Scanlines::new(circle),
20 current_scanline: Scanline::new_empty(0),
21 }
22 }
23}
24
25impl Iterator for Points {
26 type Item = Point;
27
28 fn next(&mut self) -> Option<Self::Item> {
29 self.current_scanline.next().or_else(|| {
30 self.current_scanline = self.scanlines.next()?;
31 self.current_scanline.next()
32 })
33 }
34}
35
36#[derive(Clone, Eq, PartialEq, Hash, Debug)]
37#[cfg_attr(feature = "defmt", derive(::defmt::Format))]
38pub struct Scanlines {
39 rows: Range<i32>,
40 columns: Range<i32>,
41 pub(super) center_2x: Point,
42 threshold: u32,
43}
44
45impl Scanlines {
46 pub fn new(circle: &Circle) -> Self {
47 let bounding_box = circle.bounding_box();
48
49 Self {
50 rows: bounding_box.rows(),
51 columns: bounding_box.columns(),
52 center_2x: circle.center_2x(),
53 threshold: circle.threshold(),
54 }
55 }
56}
57
58impl Iterator for Scanlines {
59 type Item = Scanline;
60
61 fn next(&mut self) -> Option<Self::Item> {
62 let y = self.rows.next()?;
63
64 self.columns
65 .clone()
66 .find(|x| {
68 let delta = Point::new(*x, y) * 2 - self.center_2x;
69 (delta.length_squared() as u32) < self.threshold
70 })
71 .map(|x| Scanline::new(y, x..self.columns.end - (x - self.columns.start)))
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use crate::{
80 geometry::Point, mock_display::MockDisplay, pixelcolor::BinaryColor, primitives::PointsIter,
81 };
82
83 fn test_circle(diameter: u32, pattern: &[&str]) {
84 let display = MockDisplay::from_points(
85 Circle::new(Point::new(0, 0), diameter).points(),
86 BinaryColor::On,
87 );
88
89 display.assert_pattern(pattern);
90 }
91
92 #[test]
93 fn circle_1() {
94 #[rustfmt::skip]
95 test_circle(1, &[
96 "#",
97 ],);
98 }
99
100 #[test]
101 fn circle_2() {
102 #[rustfmt::skip]
103 test_circle(2, &[
104 "##",
105 "##",
106 ],);
107 }
108
109 #[test]
110 fn circle_3() {
111 #[rustfmt::skip]
112 test_circle(3, &[
113 " # ",
114 "###",
115 " # ",
116 ],);
117 }
118
119 #[test]
120 fn circle_4() {
121 #[rustfmt::skip]
122 test_circle(4, &[
123 " ## ",
124 "####",
125 "####",
126 " ## ",
127 ],);
128 }
129
130 #[test]
131 fn circle_5() {
132 #[rustfmt::skip]
133 test_circle(5, &[
134 " ### ",
135 "#####",
136 "#####",
137 "#####",
138 " ### ",
139 ],);
140 }
141
142 #[test]
143 fn circle_6() {
144 #[rustfmt::skip]
145 test_circle(6, &[
146 " #### ",
147 "######",
148 "######",
149 "######",
150 "######",
151 " #### ",
152 ],);
153 }
154
155 #[test]
156 fn circle_7() {
157 #[rustfmt::skip]
158 test_circle(7, &[
159 " ### ",
160 " ##### ",
161 "#######",
162 "#######",
163 "#######",
164 " ##### ",
165 " ### ",
166 ],);
167 }
168
169 #[test]
170 fn circle_8() {
171 #[rustfmt::skip]
172 test_circle(8, &[
173 " #### ",
174 " ###### ",
175 "########",
176 "########",
177 "########",
178 "########",
179 " ###### ",
180 " #### ",
181 ],);
182 }
183
184 #[test]
185 fn circle_9() {
186 #[rustfmt::skip]
187 test_circle(9, &[
188 " ##### ",
189 " ####### ",
190 "#########",
191 "#########",
192 "#########",
193 "#########",
194 "#########",
195 " ####### ",
196 " ##### ",
197 ],);
198 }
199}