1use crate::Shape;
2
3pub struct Arc {
4 pub x1: f32,
5 pub y1: f32,
6 pub x2: f32,
7 pub y2: f32,
8 pub radius: f32,
9 pub sweep_flag: bool,
10}
11
12impl Arc {
13 pub fn new(
14 x1: f32,
15 y1: f32,
16 x2: f32,
17 y2: f32,
18 radius: f32,
19 sweep_flag: bool,
20 ) -> Self {
21 Arc {
22 x1,
23 y1,
24 x2,
25 y2,
26 radius,
27 sweep_flag,
28 }
29 }
30
31 pub fn center(&self) -> (f32, f32) {
33 let q = ((self.x2 - self.x1).powf(2.0) + (self.y2 - self.y1).powf(2.0))
34 .sqrt();
35 let y3 = (self.y1 + self.y2) / 2.0;
36 let x3 = (self.x1 + self.x2) / 2.0;
37
38 let rr_q22 = (self.radius.powf(2.0) - (q / 2.0).powf(2.0)).sqrt();
39
40 let base_x = rr_q22 * (self.y1 - self.y2) / q;
41 let base_y = rr_q22 * (self.x2 - self.x1) / q;
42
43 if self.sweep_flag {
44 let cx = x3 + base_x;
45 let cy = y3 + base_y;
46 (cx, cy)
47 } else {
48 let cx = x3 - base_x;
49 let cy = y3 - base_y;
50 (cx, cy)
51 }
52 }
53
54 fn octant(&self) -> (u8, u8) {
56 let (cx, cy) = self.center();
57 let o1 = Self::line_octant(cx, cy, self.x1, self.y1);
58 let o2 = Self::line_octant(cx, cy, self.x2, self.y2);
59 (o1 + 1, o2)
60 }
61
62 fn line_octant(x1: f32, y1: f32, x2: f32, y2: f32) -> u8 {
64 let mut dx = x2 - x1;
65 let mut dy = -(y2 * 2.0 - y1 * 2.0);
66
67 let mut octant = 0;
68
69 if dy < 0.0 {
70 dx = -dx;
71 dy = -dy;
72 octant += 4;
73 }
74
75 if dx < 0.0 {
76 let tmp = dx;
77 dx = dy;
78 dy = -tmp;
79 octant += 2
80 }
81
82 if dx < dy {
83 octant += 1
84 }
85 octant
86 }
87}
88
89impl<'a> Shape<'a> for Arc {
90 fn points(&'a self) -> Box<dyn Iterator<Item = (f32, f32)> + 'a> {
91 let mut x = self.radius;
92 let mut y = 0.0;
93 let mut err = 0.0;
94
95 let inc = 0.25;
96
97 let mut points = vec![];
98
99 let (cx, cy) = self.center();
100 let (o1, o2) = self.octant();
101
102 while x >= y {
103 if (o1..=o2).contains(&7) {
104 points.push((cx + x, cy + y));
105 }
106 if (o1..=o2).contains(&6) {
107 points.push((cx + y, cy + x));
108 }
109 if (o1..=o2).contains(&5) {
110 points.push((cx - y, cy + x));
111 }
112 if (o1..=o2).contains(&4) {
113 points.push((cx - x, cy + y));
114 }
115 if (o1..=o2).contains(&3) {
116 points.push((cx - x, cy - y));
117 }
118 if (o1..=o2).contains(&2) {
119 points.push((cx - y, cy - x));
120 }
121 if (o1..=o2).contains(&1) {
122 points.push((cx + y, cy - x));
123 }
124 if (o1..=o2).contains(&0) {
125 points.push((cx + x, cy - y));
126 }
127
128 if err <= 0.0 {
129 y += inc;
130 err += 2.0 * y + inc;
131 }
132
133 if err > 0.0 {
134 x -= inc;
135 err -= 2.0 * x + inc;
136 }
137 }
138 Box::new(points.into_iter())
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145 use crate::*;
146
147 #[test]
148 fn arc_center() {
149 let arc = Arc {
150 x1: 0.0,
151 y1: 0.0,
152 x2: 10.0,
153 y2: 10.0,
154 radius: 10.0,
155 sweep_flag: false,
156 };
157
158 let center = arc.center();
159 assert_eq!(center, (10.0, 0.0));
160 }
161
162 #[test]
163 fn arc_center2() {
164 let arc = Arc {
165 x1: 0.0,
166 y1: 0.0,
167 x2: 10.0,
168 y2: 10.0,
169 radius: 10.0,
170 sweep_flag: true,
171 };
172
173 let center = arc.center();
174 assert_eq!(center, (0.0, 10.0));
175 }
176
177 #[test]
178 fn draw_arc() {
179 let width = 11.0;
180 let height = 11.0;
181 let mut context = Context::new(width, height);
182 let arc = Arc {
183 x1: 0.0,
184 y1: 0.0,
185 x2: 10.0,
186 y2: 10.0,
187 radius: 10.0,
188 sweep_flag: false,
189 };
190
191 context.draw(&arc);
192
193 let result = context.to_string();
194 println!("{}", result);
195 let expected = [
196 "⢱ ",
197 "⢸ ",
198 " ⡇ ",
199 " ⠸⡀ ",
200 " ⠱⡀ ",
201 " ⠑⡄ ",
202 " ⠈⠢⡀ ",
203 " ⠈⠢⡀ ",
204 " ⠈⠑⠤⣀ ",
205 " ⠉⠒⠢⠤⢄⣀⣀⣀ ",
206 " ⠁ ",
207 ];
208 let expected = expected.join("\n");
209 assert_eq!(result, expected);
210 }
211
212 #[test]
213 fn draw_arc2() {
214 let width = 22.0;
215 let height = 22.0;
216 let mut context = Context::new(width, height);
217 let arc = Arc {
218 x1: 10.0,
219 y1: 0.0,
220 x2: 10.0,
221 y2: 20.0,
222 radius: 10.0,
223 sweep_flag: false,
224 };
225
226 context.draw(&arc);
227
228 let result = context.to_string();
229 println!("{}", result);
230 let expected = [
231 " ⣀⡠⠤⠔⠒⠒⠒⠁ ",
232 " ⢀⠤⠒⠉ ",
233 " ⡠⠊⠁ ",
234 " ⡠⠊ ",
235 " ⢀⠎ ",
236 " ⢠⠃ ",
237 " ⢠⠃ ",
238 " ⡎ ",
239 "⢰⠁ ",
240 "⢸ ",
241 "⢱ ",
242 "⢸ ",
243 " ⡇ ",
244 " ⠸⡀ ",
245 " ⠱⡀ ",
246 " ⠑⡄ ",
247 " ⠈⠢⡀ ",
248 " ⠈⠢⡀ ",
249 " ⠈⠑⠤⣀ ",
250 " ⠉⠒⠢⠤⢄⣀⣀⣀ ",
251 " ⠁ ",
252 " ",
253 ];
254 let expected = expected.join("\n");
255 assert_eq!(result, expected);
256 }
257}