• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::{BackendCoord, BackendStyle, DrawingBackend, DrawingErrorKind};
2 
draw_part_a< B: DrawingBackend, Draw: FnMut(i32, (f64, f64)) -> Result<(), DrawingErrorKind<B::ErrorType>>, >( height: f64, radius: u32, mut draw: Draw, ) -> Result<(), DrawingErrorKind<B::ErrorType>>3 fn draw_part_a<
4     B: DrawingBackend,
5     Draw: FnMut(i32, (f64, f64)) -> Result<(), DrawingErrorKind<B::ErrorType>>,
6 >(
7     height: f64,
8     radius: u32,
9     mut draw: Draw,
10 ) -> Result<(), DrawingErrorKind<B::ErrorType>> {
11     let half_width = (radius as f64 * radius as f64
12         - (radius as f64 - height) * (radius as f64 - height))
13         .sqrt();
14 
15     let x0 = (-half_width).ceil() as i32;
16     let x1 = half_width.floor() as i32;
17 
18     let y0 = (radius as f64 - height).ceil();
19 
20     for x in x0..=x1 {
21         let y1 = (radius as f64 * radius as f64 - x as f64 * x as f64).sqrt();
22         check_result!(draw(x, (y0, y1)));
23     }
24 
25     Ok(())
26 }
27 
draw_part_b< B: DrawingBackend, Draw: FnMut(i32, (f64, f64)) -> Result<(), DrawingErrorKind<B::ErrorType>>, >( from: f64, size: f64, mut draw: Draw, ) -> Result<(), DrawingErrorKind<B::ErrorType>>28 fn draw_part_b<
29     B: DrawingBackend,
30     Draw: FnMut(i32, (f64, f64)) -> Result<(), DrawingErrorKind<B::ErrorType>>,
31 >(
32     from: f64,
33     size: f64,
34     mut draw: Draw,
35 ) -> Result<(), DrawingErrorKind<B::ErrorType>> {
36     let from = from.floor();
37     for x in (from - size).floor() as i32..=from as i32 {
38         check_result!(draw(x, (-x as f64, x as f64)));
39     }
40     Ok(())
41 }
42 
draw_part_c< B: DrawingBackend, Draw: FnMut(i32, (f64, f64)) -> Result<(), DrawingErrorKind<B::ErrorType>>, >( r: i32, r_limit: i32, mut draw: Draw, ) -> Result<(), DrawingErrorKind<B::ErrorType>>43 fn draw_part_c<
44     B: DrawingBackend,
45     Draw: FnMut(i32, (f64, f64)) -> Result<(), DrawingErrorKind<B::ErrorType>>,
46 >(
47     r: i32,
48     r_limit: i32,
49     mut draw: Draw,
50 ) -> Result<(), DrawingErrorKind<B::ErrorType>> {
51     let half_size = r as f64 / (2f64).sqrt();
52 
53     let (x0, x1) = ((-half_size).ceil() as i32, half_size.floor() as i32);
54 
55     for x in x0..x1 {
56         let outer_y0 = ((r_limit as f64) * (r_limit as f64) - x as f64 * x as f64).sqrt();
57         let inner_y0 = r as f64 - 1.0;
58         let mut y1 = outer_y0.min(inner_y0);
59         let y0 = ((r as f64) * (r as f64) - x as f64 * x as f64).sqrt();
60 
61         if y0 > y1 {
62             y1 = y0.ceil();
63             if y1 >= r as f64 {
64                 continue;
65             }
66         }
67 
68         check_result!(draw(x, (y0, y1)));
69     }
70 
71     for x in x1 + 1..r {
72         let outer_y0 = ((r_limit as f64) * (r_limit as f64) - x as f64 * x as f64).sqrt();
73         let inner_y0 = r as f64 - 1.0;
74         let y0 = outer_y0.min(inner_y0);
75         let y1 = x as f64;
76 
77         if y1 < y0 {
78             check_result!(draw(x, (y0, y1 + 1.0)));
79             check_result!(draw(-x, (y0, y1 + 1.0)));
80         }
81     }
82 
83     Ok(())
84 }
85 
draw_sweep_line<B: DrawingBackend, S: BackendStyle>( b: &mut B, style: &S, (x0, y0): BackendCoord, (dx, dy): (i32, i32), p0: i32, (s, e): (f64, f64), ) -> Result<(), DrawingErrorKind<B::ErrorType>>86 fn draw_sweep_line<B: DrawingBackend, S: BackendStyle>(
87     b: &mut B,
88     style: &S,
89     (x0, y0): BackendCoord,
90     (dx, dy): (i32, i32),
91     p0: i32,
92     (s, e): (f64, f64),
93 ) -> Result<(), DrawingErrorKind<B::ErrorType>> {
94     let mut s = if dx < 0 || dy < 0 { -s } else { s };
95     let mut e = if dx < 0 || dy < 0 { -e } else { e };
96     if s > e {
97         std::mem::swap(&mut s, &mut e);
98     }
99 
100     let vs = s.ceil() - s;
101     let ve = e - e.floor();
102 
103     if dx == 0 {
104         check_result!(b.draw_line(
105             (p0 + x0, s.ceil() as i32 + y0),
106             (p0 + x0, e.floor() as i32 + y0),
107             &style.color()
108         ));
109         check_result!(b.draw_pixel((p0 + x0, s.ceil() as i32 + y0 - 1), style.color().mix(vs)));
110         check_result!(b.draw_pixel((p0 + x0, e.floor() as i32 + y0 + 1), style.color().mix(ve)));
111     } else {
112         check_result!(b.draw_line(
113             (s.ceil() as i32 + x0, p0 + y0),
114             (e.floor() as i32 + x0, p0 + y0),
115             &style.color()
116         ));
117         check_result!(b.draw_pixel((s.ceil() as i32 + x0 - 1, p0 + y0), style.color().mix(vs)));
118         check_result!(b.draw_pixel((e.floor() as i32 + x0 + 1, p0 + y0), style.color().mix(ve)));
119     }
120 
121     Ok(())
122 }
123 
draw_annulus<B: DrawingBackend, S: BackendStyle>( b: &mut B, center: BackendCoord, radius: (u32, u32), style: &S, ) -> Result<(), DrawingErrorKind<B::ErrorType>>124 fn draw_annulus<B: DrawingBackend, S: BackendStyle>(
125     b: &mut B,
126     center: BackendCoord,
127     radius: (u32, u32),
128     style: &S,
129 ) -> Result<(), DrawingErrorKind<B::ErrorType>> {
130     let a0 = ((radius.0 - radius.1) as f64).min(radius.0 as f64 * (1.0 - 1.0 / (2f64).sqrt()));
131     let a1 = (radius.0 as f64 - a0 - radius.1 as f64).max(0.0);
132 
133     check_result!(draw_part_a::<B, _>(a0, radius.0, |p, r| draw_sweep_line(
134         b,
135         style,
136         center,
137         (0, 1),
138         p,
139         r
140     )));
141     check_result!(draw_part_a::<B, _>(a0, radius.0, |p, r| draw_sweep_line(
142         b,
143         style,
144         center,
145         (0, -1),
146         p,
147         r
148     )));
149     check_result!(draw_part_a::<B, _>(a0, radius.0, |p, r| draw_sweep_line(
150         b,
151         style,
152         center,
153         (1, 0),
154         p,
155         r
156     )));
157     check_result!(draw_part_a::<B, _>(a0, radius.0, |p, r| draw_sweep_line(
158         b,
159         style,
160         center,
161         (-1, 0),
162         p,
163         r
164     )));
165 
166     if a1 > 0.0 {
167         check_result!(draw_part_b::<B, _>(
168             radius.0 as f64 - a0,
169             a1.floor(),
170             |h, (f, t)| {
171                 let f = f as i32;
172                 let t = t as i32;
173                 check_result!(b.draw_line(
174                     (center.0 + h, center.1 + f),
175                     (center.0 + h, center.1 + t),
176                     &style.color()
177                 ));
178                 check_result!(b.draw_line(
179                     (center.0 - h, center.1 + f),
180                     (center.0 - h, center.1 + t),
181                     &style.color()
182                 ));
183 
184                 check_result!(b.draw_line(
185                     (center.0 + f + 1, center.1 + h),
186                     (center.0 + t - 1, center.1 + h),
187                     &style.color()
188                 ));
189                 check_result!(b.draw_line(
190                     (center.0 + f + 1, center.1 - h),
191                     (center.0 + t - 1, center.1 - h),
192                     &style.color()
193                 ));
194 
195                 Ok(())
196             }
197         ));
198     }
199 
200     check_result!(draw_part_c::<B, _>(
201         radius.1 as i32,
202         radius.0 as i32,
203         |p, r| draw_sweep_line(b, style, center, (0, 1), p, r)
204     ));
205     check_result!(draw_part_c::<B, _>(
206         radius.1 as i32,
207         radius.0 as i32,
208         |p, r| draw_sweep_line(b, style, center, (0, -1), p, r)
209     ));
210     check_result!(draw_part_c::<B, _>(
211         radius.1 as i32,
212         radius.0 as i32,
213         |p, r| draw_sweep_line(b, style, center, (1, 0), p, r)
214     ));
215     check_result!(draw_part_c::<B, _>(
216         radius.1 as i32,
217         radius.0 as i32,
218         |p, r| draw_sweep_line(b, style, center, (-1, 0), p, r)
219     ));
220 
221     let d_inner = ((radius.1 as f64) / (2f64).sqrt()) as i32;
222     let d_outer = (((radius.0 as f64) / (2f64).sqrt()) as i32).min(radius.1 as i32 - 1);
223     let d_outer_actually = (radius.1 as i32).min(
224         (radius.0 as f64 * radius.0 as f64 - radius.1 as f64 * radius.1 as f64 / 2.0)
225             .sqrt()
226             .ceil() as i32,
227     );
228 
229     check_result!(b.draw_line(
230         (center.0 - d_inner, center.1 - d_inner),
231         (center.0 - d_outer, center.1 - d_outer),
232         &style.color()
233     ));
234     check_result!(b.draw_line(
235         (center.0 + d_inner, center.1 - d_inner),
236         (center.0 + d_outer, center.1 - d_outer),
237         &style.color()
238     ));
239     check_result!(b.draw_line(
240         (center.0 - d_inner, center.1 + d_inner),
241         (center.0 - d_outer, center.1 + d_outer),
242         &style.color()
243     ));
244     check_result!(b.draw_line(
245         (center.0 + d_inner, center.1 + d_inner),
246         (center.0 + d_outer, center.1 + d_outer),
247         &style.color()
248     ));
249 
250     check_result!(b.draw_line(
251         (center.0 - d_inner, center.1 + d_inner),
252         (center.0 - d_outer_actually, center.1 + d_inner),
253         &style.color()
254     ));
255     check_result!(b.draw_line(
256         (center.0 + d_inner, center.1 - d_inner),
257         (center.0 + d_inner, center.1 - d_outer_actually),
258         &style.color()
259     ));
260     check_result!(b.draw_line(
261         (center.0 + d_inner, center.1 + d_inner),
262         (center.0 + d_inner, center.1 + d_outer_actually),
263         &style.color()
264     ));
265     check_result!(b.draw_line(
266         (center.0 + d_inner, center.1 + d_inner),
267         (center.0 + d_outer_actually, center.1 + d_inner),
268         &style.color()
269     ));
270 
271     Ok(())
272 }
273 
draw_circle<B: DrawingBackend, S: BackendStyle>( b: &mut B, center: BackendCoord, mut radius: u32, style: &S, mut fill: bool, ) -> Result<(), DrawingErrorKind<B::ErrorType>>274 pub fn draw_circle<B: DrawingBackend, S: BackendStyle>(
275     b: &mut B,
276     center: BackendCoord,
277     mut radius: u32,
278     style: &S,
279     mut fill: bool,
280 ) -> Result<(), DrawingErrorKind<B::ErrorType>> {
281     if style.color().alpha == 0.0 {
282         return Ok(());
283     }
284 
285     if !fill && style.stroke_width() != 1 {
286         let inner_radius = radius - (style.stroke_width() / 2).min(radius);
287         radius += style.stroke_width() / 2;
288         if inner_radius > 0 {
289             return draw_annulus(b, center, (radius, inner_radius), style);
290         } else {
291             fill = true;
292         }
293     }
294 
295     let min = (f64::from(radius) * (1.0 - (2f64).sqrt() / 2.0)).ceil() as i32;
296     let max = (f64::from(radius) * (1.0 + (2f64).sqrt() / 2.0)).floor() as i32;
297 
298     let range = min..=max;
299 
300     let (up, down) = (
301         range.start() + center.1 - radius as i32,
302         range.end() + center.1 - radius as i32,
303     );
304 
305     for dy in range {
306         let dy = dy - radius as i32;
307         let y = center.1 + dy;
308 
309         let lx = (f64::from(radius) * f64::from(radius)
310             - (f64::from(dy) * f64::from(dy)).max(1e-5))
311         .sqrt();
312 
313         let left = center.0 - lx.floor() as i32;
314         let right = center.0 + lx.floor() as i32;
315 
316         let v = lx - lx.floor();
317 
318         let x = center.0 + dy;
319         let top = center.1 - lx.floor() as i32;
320         let bottom = center.1 + lx.floor() as i32;
321 
322         if fill {
323             check_result!(b.draw_line((left, y), (right, y), &style.color()));
324             check_result!(b.draw_line((x, top), (x, up - 1), &style.color()));
325             check_result!(b.draw_line((x, down + 1), (x, bottom), &style.color()));
326         } else {
327             check_result!(b.draw_pixel((left, y), style.color().mix(1.0 - v)));
328             check_result!(b.draw_pixel((right, y), style.color().mix(1.0 - v)));
329 
330             check_result!(b.draw_pixel((x, top), style.color().mix(1.0 - v)));
331             check_result!(b.draw_pixel((x, bottom), style.color().mix(1.0 - v)));
332         }
333 
334         check_result!(b.draw_pixel((left - 1, y), style.color().mix(v)));
335         check_result!(b.draw_pixel((right + 1, y), style.color().mix(v)));
336         check_result!(b.draw_pixel((x, top - 1), style.color().mix(v)));
337         check_result!(b.draw_pixel((x, bottom + 1), style.color().mix(v)));
338     }
339 
340     Ok(())
341 }
342