use crate::{FloatingScalar, FloatingVector2, Scalar as _, Vector2};
pub type Scalar<T> = <<T as Circle>::Vector as Vector2>::Scalar;
pub trait Circle: Copy
where
Scalar<Self>: FloatingScalar,
{
type Vector: FloatingVector2;
fn new(center: Self::Vector, radius: Scalar<Self>) -> Self;
fn center(self) -> Self::Vector;
fn radius(self) -> Scalar<Self>;
fn map_into<C>(self) -> C
where
C: Circle,
Scalar<C>: FloatingScalar + From<Scalar<Self>>,
{
C::new(
C::Vector::new(
Scalar::<C>::from(self.center().x()),
Scalar::<C>::from(self.center().y()),
),
Scalar::<C>::from(self.radius()),
)
}
fn map_with<C, F>(self, mut f: F) -> C
where
C: Circle,
Scalar<C>: FloatingScalar,
F: FnMut(Scalar<Self>) -> <<C as Circle>::Vector as Vector2>::Scalar,
{
C::new(
C::Vector::new(f(self.center().x()), f(self.center().y())),
f(self.radius()),
)
}
fn with_center(self, center: Self::Vector) -> Self {
Self::new(center, self.radius())
}
fn with_radius(self, radius: Scalar<Self>) -> Self {
Self::new(self.center(), radius)
}
fn diameter(self) -> Scalar<Self> {
self.radius() * Scalar::<Self>::TWO
}
fn circumference(self) -> Scalar<Self> {
self.radius() * Scalar::<Self>::TAU
}
fn area(self) -> Scalar<Self> {
self.radius().square() * Scalar::<Self>::PI
}
fn translated(self, offset: Self::Vector) -> Self {
self.with_center(self.center().add(offset))
}
fn scaled(self, scale: Scalar<Self>) -> Self {
self.with_radius(self.radius() * scale)
}
fn to_square(self) -> [Scalar<Self>; 4] {
let radius = self.radius();
[
self.center().x() - radius,
self.center().y() - radius,
radius * Scalar::<Self>::TWO,
radius * Scalar::<Self>::TWO,
]
}
fn contains(self, point: Self::Vector) -> bool {
self.center().dist(point) <= self.radius().abs()
}
fn cntains(self, point: Self::Vector) -> bool {
self.contains(point)
}
fn contains_all<I>(self, points: I) -> bool
where
I: IntoIterator<Item = Self::Vector>,
{
points.into_iter().all(|point| self.contains(point))
}
fn contains_any<I>(self, points: I) -> bool
where
I: IntoIterator<Item = Self::Vector>,
{
points.into_iter().any(|point| self.contains(point))
}
}
impl<S, V> Circle for (V, S)
where
S: FloatingScalar,
V: FloatingVector2<Scalar = S>,
{
type Vector = V;
fn new(center: Self::Vector, radius: Scalar<Self>) -> Self {
(center, radius)
}
fn center(self) -> Self::Vector {
self.0
}
fn radius(self) -> Scalar<Self> {
self.1
}
}