Coverage Report

Created: 2025-12-28 06:31

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