1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use crate::{Abs, FloatingScalar, FloatingVector2, Pow, Vector2, ZeroOneTwo};

/// Trait for manipulating circles
pub trait Circle: Copy {
    /// The scalar type
    type Scalar: FloatingScalar;
    /// The vector type
    type Vector: FloatingVector2<Scalar = Self::Scalar>;
    /// Create a new circle from a center coordinate and a radius
    fn new(center: Self::Vector, radius: Self::Scalar) -> Self;
    /// Get the circle's center
    fn center(self) -> Self::Vector;
    /// Get the circle's radius
    fn radius(self) -> Self::Scalar;
    /// Map this circle to a circle of another type
    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()),
        )
    }
    /// Map this circle to a circle of another type using a function
    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()),
        )
    }
    /// Transform the circle into one with a different top-left corner position
    fn with_center(self, center: Self::Vector) -> Self {
        Self::new(center, self.radius())
    }
    /// Transform the circle into one with a different size
    fn with_radius(self, radius: Self::Scalar) -> Self {
        Self::new(self.center(), radius)
    }
    /// Get the circle's diameter
    fn diameter(self) -> Self::Scalar {
        self.radius() * Self::Scalar::TWO
    }
    /// Get the circle's circumference
    fn circumference(self) -> Self::Scalar {
        self.radius() * Self::Scalar::TAU
    }
    /// Get the circle's area
    fn area(self) -> Self::Scalar {
        self.radius().pow(Self::Scalar::TWO) * Self::Scalar::pi()
    }
    /// Get the circle that is this one translated by some vector
    fn translated(self, offset: Self::Vector) -> Self {
        self.with_center(self.center().add(offset))
    }
    /// Get the circle that is this one with a scalar-scaled size
    fn scaled(self, scale: Self::Scalar) -> Self {
        self.with_radius(self.radius() * scale)
    }
    /// Get the smallest square that this circle fits inside
    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,
        ]
    }
    /// Check that the circle contains the given point
    fn contains(self, point: Self::Vector) -> bool {
        self.center().dist(point) <= self.radius().abs()
    }
    /// Alias for `Rectangle::contains`
    ///
    /// Useful when `contains` is ambiguous
    fn cntains(self, point: Self::Vector) -> bool {
        self.contains(point)
    }
    /// Check that the circle contains all points
    fn contains_all<I>(self, points: I) -> bool
    where
        I: IntoIterator<Item = Self::Vector>,
    {
        points.into_iter().all(|point| self.contains(point))
    }
    /// Check that the circle contains any 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
    }
}