rustbatch 0.4.0

purely game dewelopment crate that offers simple but powerfull 2D rendering and some fast solutions for game world bottle necks
Documentation
use crate::{Vect, Rect, Ray, IntersectionPoints};
use crate::math::Intersection;

/// Circ is what we in geometry call circle. Circle is mainly for collision detection and supports
/// collisions with Ray, Rect and it self. There are also projection methods available.
#[derive(Copy, Clone, Debug)]
pub struct Circ {
    pub c: Vect,
    pub r: f32,
}

impl Circ {
    #[inline]
    pub fn new(x: f32, y: f32, r:f32) -> Self {
        Self { r, c: Vect { x, y } }
    }

    /// returns whether point ic in circle
    #[inline]
    pub fn contains(&self, pos: Vect) -> bool {
        self.c.dist(pos) <= self.r
    }

    /// projects x coordinate to y coordinate that belongs to circle or nan if there is no such y.
    /// mind that even if there are 2 possible solution for one x. If you need both solutions use
    /// precise_prf_x witch is slower but takes second solution to account.
    #[inline]
    pub fn prj_x(&self, x: f32) -> f32 {
        (self.r * self.r - (x - self.c.x).powi(2)).sqrt() - self.c.y
    }

    /// opposite of prj_x
    #[inline]
    pub fn prj_y(&self, y: f32) -> f32 {
        (self.r * self.r - (y - self.c.y).powi(2)).sqrt() - self.c.y
    }

    /// used for other calculations
    #[inline]
    pub fn formula_x(&self, x: f32) -> (f32, f32) {
        (2.0 * self.c.y, self.c.y * self.c.y - self.r * self.r + (x - self.c.x).powi(2))
    }

    /// used for other calculations
    #[inline]
    pub fn formula_y(&self, y: f32) -> (f32, f32) {
        (2.0 * self.c.x, self.c.x * self.c.x - self.r * self.r + (y - self.c.y).powi(2))
    }

    /// used for other calculations
    #[inline]
    pub fn precise_prj(&self, arg: f32, formula: fn(&Self, f32) -> (f32, f32)) -> [Option<f32>; 2] {
        let (b, c) = formula(self, arg);

        let mut dis = b * b - 4.0 * c;
        if dis < 0.0 {
            return [None, None];
        } else if dis == 0.0 {
            return [Some(-b/2.0), None]
        }

        dis = dis.sqrt();
        [Some((-b - dis)/2.0), Some((-b + dis)/2.0)]
    }

    /// projects x coordinate to zero one or two solutions. This method is considerably slower then
    /// prj_x
    #[inline]
    pub fn precise_prj_x(&self, x: f32) -> [Option<f32>; 2] {
        self.precise_prj(x, Self::formula_x)
    }

    /// opposite of precise_prj_x
    #[inline]
    pub fn precise_prj_y(&self, y: f32) -> [Option<f32>; 2] {
        self.precise_prj(y, Self::formula_y)
    }
}

impl Intersection<Circ> for Circ {
    #[inline]
    fn intersects(&self, o: &Circ) -> bool {
        self.c.dist(o.c) < self.r + o.r
    }
}

impl Intersection<Rect> for Circ {
    #[inline]
    fn intersects(&self, o: &Rect) -> bool {
        o.intersects(self)
    }
}

impl Intersection<Ray> for Circ {
    #[inline]
    fn intersects(&self, o: &Ray) -> bool {
        o.intersects(self)
    }
}

impl IntersectionPoints<Ray> for Circ {
    #[inline]
    fn intersects_points(&self, o: &Ray) -> [Option<Vect>; 2] {
        o.intersects_points(self)
    }
}

#[cfg(test)]
mod tests {
    use super::Circ;
    use crate::Vect;
    #[test]
    fn prj_test() {
        let base = circ!(0, 0; 10);
        assert_eq!(0.0 ,base.prj_y(10.0));
        assert_eq!(0.0 ,base.prj_x(10.0));
        assert_eq!(10.0 ,base.prj_y(0.0));
        assert_eq!(10.0 ,base.prj_x(0.0));
    }

    #[test]
    fn precise_pre_test() {
        let base = circ!(0, 0; 10);
        assert_eq!([Some(0.0), None] ,base.precise_prj_y(10.0));
        assert_eq!([Some(0.0), None] ,base.precise_prj_x(10.0));
        assert_eq!([Some(-8.0), Some(8.0)] ,base.precise_prj_y(6.0));
        assert_eq!([Some(-8.0), Some(8.0)] ,base.precise_prj_x(6.0));
    }
}