1use crate::prelude::Point;
2
3pub struct BresenhamCircle {
7 x: i32,
8 y: i32,
9 center: Point,
10 radius: i32,
11 error: i32,
12 quadrant: u8,
13}
14
15impl BresenhamCircle {
16 #[inline]
23 #[allow(dead_code)]
24 pub fn new(center: Point, radius: i32) -> Self {
25 Self {
26 center,
27 radius,
28 x: -radius,
29 y: 0,
30 error: 2 - 2 * radius,
31 quadrant: 1,
32 }
33 }
34}
35
36impl Iterator for BresenhamCircle {
37 type Item = Point;
38
39 #[inline]
40 fn next(&mut self) -> Option<Self::Item> {
41 if self.x < 0 {
42 let point = match self.quadrant {
43 1 => (self.center.x - self.x, self.center.y + self.y),
44 2 => (self.center.x - self.y, self.center.y - self.x),
45 3 => (self.center.x + self.x, self.center.y - self.y),
46 4 => (self.center.x + self.y, self.center.y + self.x),
47 _ => unreachable!(),
48 };
49
50 if self.quadrant == 4 {
52 self.radius = self.error;
53
54 if self.radius <= self.y {
55 self.y += 1;
56 self.error += self.y * 2 + 1;
57 }
58
59 if self.radius > self.x || self.error > self.y {
60 self.x += 1;
61 self.error += self.x * 2 + 1;
62 }
63 }
64
65 self.quadrant = self.quadrant % 4 + 1;
66
67 Some(Point::from_tuple(point))
68 } else {
69 None
70 }
71 }
72}
73
74pub struct BresenhamCircleNoDiag {
76 x: i32,
77 y: i32,
78 center: Point,
79 error: i32,
81 quadrant: u8,
82}
83
84impl BresenhamCircleNoDiag {
85 #[inline]
92 #[allow(dead_code)]
93 pub fn new(center: Point, radius: i32) -> Self {
94 Self {
95 center,
96 x: -radius,
97 y: 0,
98 error: 0,
99 quadrant: 1,
100 }
101 }
102}
103
104impl Iterator for BresenhamCircleNoDiag {
105 type Item = Point;
106
107 #[inline]
108 fn next(&mut self) -> Option<Self::Item> {
109 if self.x < 0 {
110 let point = match self.quadrant {
111 1 => (self.center.x - self.x, self.center.y + self.y),
112 2 => (self.center.x - self.y, self.center.y - self.x),
113 3 => (self.center.x + self.x, self.center.y - self.y),
114 4 => (self.center.x + self.y, self.center.y + self.x),
115 _ => unreachable!(),
116 };
117
118 if self.quadrant == 4 {
120 if (self.error + 2 * self.x + 1).abs() <= (self.error + 2 * self.y + 1).abs() {
122 self.error += self.x * 2 + 1;
123 self.x += 1;
124 } else {
125 self.error += self.y * 2 + 1;
126 self.y += 1;
127 }
128 }
129
130 self.quadrant = self.quadrant % 4 + 1;
131
132 Some(Point::from_tuple(point))
133 } else {
134 None
135 }
136 }
137}
138
139#[cfg(test)]
140mod tests {
141 use crate::prelude::{BresenhamCircle, BresenhamCircleNoDiag, Point};
142
143 #[test]
144 fn circle_test_radius1() {
145 let circle = BresenhamCircle::new(Point::new(0, 0), 1);
146 let points: Vec<Point> = circle.collect();
147 assert_eq!(
148 points,
149 vec![
150 Point::new(1, 0),
151 Point::new(0, 1),
152 Point::new(-1, 0),
153 Point::new(0, -1)
154 ]
155 );
156 }
157
158 #[test]
159 fn circle_test_radius3() {
160 let circle = BresenhamCircle::new(Point::new(0, 0), 3);
161 let points: Vec<Point> = circle.collect();
162 assert_eq!(
163 points,
164 vec![
165 Point { x: 3, y: 0 },
166 Point { x: 0, y: 3 },
167 Point { x: -3, y: 0 },
168 Point { x: 0, y: -3 },
169 Point { x: 3, y: 1 },
170 Point { x: -1, y: 3 },
171 Point { x: -3, y: -1 },
172 Point { x: 1, y: -3 },
173 Point { x: 2, y: 2 },
174 Point { x: -2, y: 2 },
175 Point { x: -2, y: -2 },
176 Point { x: 2, y: -2 },
177 Point { x: 1, y: 3 },
178 Point { x: -3, y: 1 },
179 Point { x: -1, y: -3 },
180 Point { x: 3, y: -1 }
181 ]
182 );
183 }
184
185 #[test]
186 fn circle_nodiag_test_radius3() {
187 let circle = BresenhamCircleNoDiag::new(Point::new(0, 0), 3);
188 let points: Vec<Point> = circle.collect();
189 assert_eq!(
190 points,
191 vec![
192 Point { x: 3, y: 0 },
193 Point { x: 0, y: 3 },
194 Point { x: -3, y: 0 },
195 Point { x: 0, y: -3 },
196 Point { x: 3, y: 1 },
197 Point { x: -1, y: 3 },
198 Point { x: -3, y: -1 },
199 Point { x: 1, y: -3 },
200 Point { x: 2, y: 1 },
201 Point { x: -1, y: 2 },
202 Point { x: -2, y: -1 },
203 Point { x: 1, y: -2 },
204 Point { x: 2, y: 2 },
205 Point { x: -2, y: 2 },
206 Point { x: -2, y: -2 },
207 Point { x: 2, y: -2 },
208 Point { x: 1, y: 2 },
209 Point { x: -2, y: 1 },
210 Point { x: -1, y: -2 },
211 Point { x: 2, y: -1 },
212 Point { x: 1, y: 3 },
213 Point { x: -3, y: 1 },
214 Point { x: -1, y: -3 },
215 Point { x: 3, y: -1 }
216 ]
217 );
218 }
219}