Skip to main content

plotchart/drawing/rasterizer/
circle.rs

1use crate::drawing::backend::{BackendCoord, BackendStyle, DrawingErrorKind};
2use crate::drawing::DrawingBackend;
3
4use crate::style::Color;
5
6pub fn draw_circle<B: DrawingBackend, S: BackendStyle>(
7    b: &mut B,
8    center: BackendCoord,
9    radius: u32,
10    style: &S,
11    fill: bool,
12) -> Result<(), DrawingErrorKind<B::ErrorType>> {
13    if style.as_color().alpha() == 0.0 {
14        return Ok(());
15    }
16
17    if !fill && style.stroke_width() != 1 {
18        // FIXME: We are currently ignore the stroke width for circles
19    }
20
21    let min = (f64::from(radius) * (1.0 - (2f64).sqrt() / 2.0)).ceil() as i32;
22    let max = (f64::from(radius) * (1.0 + (2f64).sqrt() / 2.0)).floor() as i32;
23
24    let range = min..=max;
25
26    let (up, down) = (
27        range.start() + center.1 - radius as i32,
28        range.end() + center.1 - radius as i32,
29    );
30
31    for dy in range {
32        let dy = dy - radius as i32;
33        let y = center.1 + dy;
34
35        let lx = (f64::from(radius) * f64::from(radius)
36            - (f64::from(dy) * f64::from(dy)).max(1e-5))
37        .sqrt();
38
39        let left = center.0 - lx.floor() as i32;
40        let right = center.0 + lx.floor() as i32;
41
42        let v = lx - lx.floor();
43
44        let x = center.0 + dy;
45        let top = center.1 - lx.floor() as i32;
46        let bottom = center.1 + lx.floor() as i32;
47
48        if fill {
49            check_result!(b.draw_line((left, y), (right, y), &style.as_color()));
50            check_result!(b.draw_line((x, top), (x, up), &style.as_color()));
51            check_result!(b.draw_line((x, down), (x, bottom), &style.as_color()));
52        } else {
53            check_result!(b.draw_pixel((left, y), &style.as_color().mix(1.0 - v)));
54            check_result!(b.draw_pixel((right, y), &style.as_color().mix(1.0 - v)));
55
56            check_result!(b.draw_pixel((x, top), &style.as_color().mix(1.0 - v)));
57            check_result!(b.draw_pixel((x, bottom), &style.as_color().mix(1.0 - v)));
58        }
59
60        check_result!(b.draw_pixel((left - 1, y), &style.as_color().mix(v)));
61        check_result!(b.draw_pixel((right + 1, y), &style.as_color().mix(v)));
62        check_result!(b.draw_pixel((x, top - 1), &style.as_color().mix(v)));
63        check_result!(b.draw_pixel((x, bottom + 1), &style.as_color().mix(v)));
64    }
65
66    Ok(())
67}