use super::point::Point;
use super::rect::Rect;
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct Circle {
pub center: Point,
pub radius: f32,
}
impl Circle {
#[inline]
pub const fn new(center: Point, radius: f32) -> Self {
Self { center, radius }
}
#[inline]
pub const fn from_coords(cx: f32, cy: f32, radius: f32) -> Self {
Self {
center: Point::new(cx, cy),
radius,
}
}
#[inline]
pub fn bounds(&self) -> Rect {
Rect {
left: self.center.x - self.radius,
top: self.center.y - self.radius,
right: self.center.x + self.radius,
bottom: self.center.y + self.radius,
}
}
#[inline]
pub fn diameter(&self) -> f32 {
self.radius * 2.0
}
#[inline]
pub fn circumference(&self) -> f32 {
2.0 * std::f32::consts::PI * self.radius
}
#[inline]
pub fn area(&self) -> f32 {
std::f32::consts::PI * self.radius * self.radius
}
#[inline]
pub fn contains(&self, p: Point) -> bool {
self.center.distance_squared_to(p) <= self.radius * self.radius
}
#[inline]
pub fn intersects(&self, other: &Circle) -> bool {
let max_dist = self.radius + other.radius;
self.center.distance_squared_to(other.center) <= max_dist * max_dist
}
#[inline]
pub fn translate(self, dx: f32, dy: f32) -> Self {
Self {
center: self.center.translate(dx, dy),
radius: self.radius,
}
}
#[inline]
pub fn scale(self, factor: f32) -> Self {
Self {
center: self.center,
radius: self.radius * factor,
}
}
}
pub fn inscribed_circle(rect: &Rect) -> Circle {
let center = rect.center();
let radius = rect.width().min(rect.height()) / 2.0;
Circle::new(center, radius)
}
pub fn circumscribed_circle(rect: &Rect) -> Circle {
let center = rect.center();
let radius = center.distance_to(rect.top_left());
Circle::new(center, radius)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_circle_basic() {
let c = Circle::from_coords(0.0, 0.0, 10.0);
assert_eq!(c.diameter(), 20.0);
assert!((c.circumference() - 62.83).abs() < 0.1);
assert!((c.area() - 314.16).abs() < 0.1);
}
#[test]
fn test_circle_contains() {
let c = Circle::from_coords(0.0, 0.0, 10.0);
assert!(c.contains(Point::new(0.0, 0.0)));
assert!(c.contains(Point::new(5.0, 5.0)));
assert!(!c.contains(Point::new(10.0, 10.0)));
}
#[test]
fn test_circle_bounds() {
let c = Circle::from_coords(10.0, 20.0, 5.0);
let b = c.bounds();
assert_eq!(b.left, 5.0);
assert_eq!(b.top, 15.0);
assert_eq!(b.right, 15.0);
assert_eq!(b.bottom, 25.0);
}
}