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

/// Geometry2D - CCW (線分と点の関係)
use crate::geometry2d::line::*;
use crate::geometry2d::point::*;

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum CCW {
    Front,
    Back,
    Right,
    Left,
    On,
}

pub fn ccw(l: LineSegment, p: Point) -> CCW {
    use CCW::*;
    fn equal(x: f64, y: f64) -> bool {
        (x - y).abs() < 0.00001
    }
    let dif = p - l.0;
    let dir = l.1 - l.0;
    if equal(0.0, dir.0) {
        if equal(0.0, dif.0) {
            let k = dif.1 / dir.1;
            if k > 1.0 {
                Front
            } else if k < 0.0 {
                Back
            } else {
                On
            }
        } else if dir.det(&dif) > 0.0 {
            Left
        } else {
            Right
        }
    } else {
        let k = dif.0 / dir.0;
        if equal(dir.1 * k, dif.1) {
            if k > 1.0 {
                Front
            } else if k < 0.0 {
                Back
            } else {
                On
            }
        } else if dir.det(&dif) > 0.0 {
            Left
        } else {
            Right
        }
    }
}

#[cfg(test)]
mod test_ccw {
    use crate::geometry2d::ccw::*;
    use CCW::*;

    #[test]
    fn it_works() {
        let p = Point(1.0, 2.0);
        let q = Point(2.0, 0.0);
        let l = LineSegment::new(p, q);

        assert_eq!(ccw(l, p), On);
        assert_eq!(ccw(l, q), On);
        assert_eq!(ccw(l, Point(1.5, 1.0)), On);
        assert_eq!(ccw(l, Point(3.0, -2.0)), Front);
        assert_eq!(ccw(l, Point(0.0, 4.0)), Back);
        assert_eq!(ccw(l, Point(0.0, 0.0)), Right);
        assert_eq!(ccw(l, Point(10.0, 0.0)), Left);
    }
}