use super::{Float, Intersect, Line2, Shape, Triangle, Vec2, PointIntersection};
pub struct Circle {
pub center: Vec2,
pub radius: Float,
}
impl Circle {
pub fn new(center: Vec2, radius: Float) -> Self {
Self { center, radius }
}
pub fn from_triangle(triangle: Triangle) -> Option<Self> {
let p1 = triangle.a;
let p2 = triangle.b;
let p3 = triangle.c;
let c1 = p3.x * p3.x + p3.y * p3.y - p1.x * p1.x - p1.y * p1.y;
let c2 = p3.x * p3.x + p3.y * p3.y - p2.x * p2.x - p2.y * p2.y;
let a1 = -2.0 * (p1.x - p3.x);
let a2 = -2.0 * (p2.x - p3.x);
let b1 = -2.0 * (p1.y - p3.y);
let b2 = -2.0 * (p2.y - p3.y);
let numer = c1 * a2 - c2 * a1;
let denom = b1 * a2 - b2 * a1;
if denom == 0.0 {
return None;
}
let y_cen = numer / denom;
let x_cen = if a2 != 0.0 {
(c2 - b2 * y_cen) / a2
} else {
(c1 - b1 * y_cen) / a1
};
let center = Vec2::new(x_cen, y_cen);
let radius = center.distance(p1);
Some(Self { center, radius })
}
}
impl Shape for Circle {
fn bounds(&self) -> super::Rect {
let r = Vec2::splat(self.radius);
super::Rect::new(self.center - r, self.center + r)
}
fn x_range(&self) -> super::Line1 {
super::Line1::new(self.center.x - self.radius, self.center.x + self.radius)
}
fn y_range(&self) -> super::Line1 {
super::Line1::new(self.center.y - self.radius, self.center.y + self.radius)
}
fn contains_point(&self, p: Vec2) -> bool {
self.center.distance_squared(p) <= self.radius * self.radius
}
fn center(&self) -> Vec2 {
self.center
}
}
impl Intersect<Circle, PointIntersection> for Circle {
fn intersects(&self, other: &Circle) -> bool {
self.center.distance_squared(other.center)
<= (self.radius + other.radius) * (self.radius + other.radius)
}
fn intersection(&self, _other: &Circle) -> Option<PointIntersection> {
todo!();
}
}
impl Intersect<Line2, PointIntersection> for Circle {
fn intersects(&self, other: &Line2) -> bool {
other.intersects(self)
}
fn intersection(&self, other: &Line2) -> Option<PointIntersection> {
other.intersection(self)
}
}