use crate::{Abs, FloatingScalar, FloatingVector2, Pow, Vector2, ZeroOneTwo};
pub trait Circle: Copy {
type Scalar: FloatingScalar;
type Vector: FloatingVector2<Scalar = Self::Scalar>;
fn new(center: Self::Vector, radius: Self::Scalar) -> Self;
fn center(self) -> Self::Vector;
fn radius(self) -> Self::Scalar;
fn map_into<C>(self) -> C
where
C: Circle,
C::Scalar: From<Self::Scalar>,
{
C::new(
C::Vector::new(
C::Scalar::from(self.center().x()),
C::Scalar::from(self.center().y()),
),
C::Scalar::from(self.radius()),
)
}
fn map_with<C, F>(self, mut f: F) -> C
where
C: Circle,
F: FnMut(Self::Scalar) -> <<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: Self::Scalar) -> Self {
Self::new(self.center(), radius)
}
fn diameter(self) -> Self::Scalar {
self.radius() * Self::Scalar::TWO
}
fn circumference(self) -> Self::Scalar {
self.radius() * Self::Scalar::TAU
}
fn area(self) -> Self::Scalar {
self.radius().pow(Self::Scalar::TWO) * Self::Scalar::pi()
}
fn translated(self, offset: Self::Vector) -> Self {
self.with_center(self.center().add(offset))
}
fn scaled(self, scale: Self::Scalar) -> Self {
self.with_radius(self.radius() * scale)
}
fn to_square(self) -> [Self::Scalar; 4] {
let radius = self.radius();
[
self.center().x() - radius,
self.center().y() - radius,
radius * Self::Scalar::TWO,
radius * Self::Scalar::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 Scalar = S;
type Vector = V;
fn new(center: Self::Vector, radius: Self::Scalar) -> Self {
(center, radius)
}
fn center(self) -> Self::Vector {
self.0
}
fn radius(self) -> Self::Scalar {
self.1
}
}