二次元ユークリッド幾何 - 円と円との接触判定

例題

実装

/// Geometry2D - Check Circle vs Circle Intersection
use crate::almost_equal;
use crate::geometry2d::circle::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CircleIntersection {
    Equal,
    Sub,              // self is contained by the other
    Sup,              // self contains the other
    Intersect(usize), // intersection with `n` points
    Outer,            // no join
}

impl Circle {
    pub fn intersection(&self, other: &Circle) -> CircleIntersection {
        use CircleIntersection::*;
        let d = (self.center - other.center).norm();
        let d2 = (self.center - other.center).quadrance();
        let r2 = (self.radius + other.radius).powi(2);
        let l2 = (self.radius - other.radius).powi(2);
        if self == other {
            Equal
        } else if almost_equal!(d2, r2) || almost_equal!(d2, l2) {
            Intersect(1)
        } else if d + self.radius < other.radius {
            Sub
        } else if self.radius > d + other.radius {
            Sup
        } else if d < self.radius + other.radius {
            Intersect(2)
        } else {
            Outer
        }
    }
}

#[cfg(test)]
mod test_circle_intersection {
    use crate::geometry2d::circle_intersection::*;
    use crate::geometry2d::point::*;

    #[test]
    fn it_works() {
        let c = Circle::new(Point(0., 0.), 5.);
        let d = Circle::new(Point(7., 0.), 2.);
        assert_eq!(c.intersection(&d), CircleIntersection::Intersect(1));
        assert_eq!(d.intersection(&c), CircleIntersection::Intersect(1));

        let c = Circle::new(Point(0., 0.), 5.);
        let d = Circle::new(Point(7., 0.), 1.);
        assert_eq!(c.intersection(&d), CircleIntersection::Outer);
        assert_eq!(d.intersection(&c), CircleIntersection::Outer);

        let c = Circle::new(Point(0., 0.), 6.);
        let d = Circle::new(Point(7., 0.), 2.);
        assert_eq!(c.intersection(&d), CircleIntersection::Intersect(2));
        assert_eq!(d.intersection(&c), CircleIntersection::Intersect(2));

        let c = Circle::new(Point(0., 0.), 10.);
        let d = Circle::new(Point(7., 0.), 2.);
        assert_eq!(c.intersection(&d), CircleIntersection::Sup);
        assert_eq!(d.intersection(&c), CircleIntersection::Sub);

        let c = Circle::new(Point(-4., 3.), 5.);
        let d = Circle::new(Point(4., -3.), 5.);
        assert_eq!(c.intersection(&d), CircleIntersection::Intersect(1));
        assert_eq!(d.intersection(&c), CircleIntersection::Intersect(1));

        let c = Circle::new(Point(0., 10.), 5.);
        let d = Circle::new(Point(0., 12.), 3.);
        assert_eq!(c.intersection(&d), CircleIntersection::Intersect(1));
        assert_eq!(d.intersection(&c), CircleIntersection::Intersect(1));

        let c = Circle::new(Point(0., 10.), 5.);
        let d = Circle::new(Point(0., 12.), 4.);
        assert_eq!(c.intersection(&d), CircleIntersection::Intersect(2));
        assert_eq!(d.intersection(&c), CircleIntersection::Intersect(2));

        let c = Circle::new(Point(0., 10.), 5.);
        let d = Circle::new(Point(0., 12.), 2.);
        assert_eq!(c.intersection(&d), CircleIntersection::Sup);
        assert_eq!(d.intersection(&c), CircleIntersection::Sub);
    }
}