microcad_core/geo2d/
circle.rs

1// Copyright © 2024-2025 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! 2D Geometry
5
6use crate::*;
7
8/// Circle with offset.
9#[derive(Debug, Clone)]
10pub struct Circle {
11    /// Radius of the circle.
12    pub radius: Scalar,
13
14    /// Offset.
15    pub offset: Vec2,
16}
17
18impl FetchBounds2D for Circle {
19    fn fetch_bounds_2d(&self) -> Bounds2D {
20        use geo::Coord;
21
22        if self.radius > 0.0 {
23            let r = Vec2::new(self.radius, self.radius);
24            let min: (Scalar, Scalar) = (self.offset - r).into();
25            let max: (Scalar, Scalar) = (self.offset + r).into();
26
27            Some(Rect::new(Coord::from(min), Coord::from(max)))
28        } else {
29            None
30        }
31        .into()
32    }
33}
34
35impl FetchPoints2D for Circle {
36    fn fetch_points_2d(&self) -> Vec<Vec2> {
37        vec![self.offset]
38    }
39}
40
41impl RenderToMultiPolygon for Circle {
42    fn render_to_polygon(&self, resolution: &RenderResolution) -> Option<Polygon> {
43        use std::f64::consts::PI;
44
45        let n = (self.radius / resolution.linear * PI * 0.5).max(3.0);
46        let n = 2_u32.pow(n.log2().ceil() as u32).min(1024);
47
48        let points = (0..n)
49            .map(|i| {
50                let angle = 2.0 * PI * (i as f64) / (n as f64);
51                geo::coord!(x: self.offset.x + self.radius * angle.cos(), y: self.offset.y + self.radius * angle.sin())
52            })
53            .collect();
54
55        Some(Polygon::new(LineString::new(points), vec![]))
56    }
57}