galileo_types/cartesian/traits/
polygon.rs

1use crate::cartesian::traits::cartesian_point::CartesianPoint2d;
2use crate::cartesian::Point2;
3use crate::contour::ClosedContour;
4use crate::polygon::Polygon;
5use crate::segment::Segment;
6
7/// Polygon in 2d cartesian coordinates. This trait is auto-implemented for all illegible types.
8pub trait CartesianPolygon {
9    /// Type of the points of the polygon.
10    type Point: CartesianPoint2d;
11
12    /// Returns true if the `point` lies inside or on one of the polygon's sides.
13    fn contains_point<P>(&self, point: &P) -> bool
14    where
15        P: CartesianPoint2d<Num = <Self::Point as CartesianPoint2d>::Num>;
16}
17
18impl<P, C, T> CartesianPolygon for T
19where
20    P: CartesianPoint2d + Copy,
21    C: ClosedContour<Point = P>,
22    T: Polygon<Contour = C>,
23{
24    type Point = P;
25
26    fn contains_point<Point: CartesianPoint2d<Num = P::Num>>(&self, point: &Point) -> bool {
27        let mut wn = 0i64;
28        let x = point.x();
29        let y = point.y();
30
31        for segment in self.iter_segments() {
32            if segment.0.x() < x && segment.1.x() < x {
33                continue;
34            }
35
36            let is_to_right = segment.0.x() > x && segment.1.x() > x || {
37                let x_max = if segment.0.x() > segment.1.x() {
38                    segment.0.x()
39                } else {
40                    segment.1.x()
41                };
42                let ray_p1 = Point2::new(x, y);
43                let ray_p2 = Point2::new(x_max, y);
44                let ray = Segment(ray_p1, ray_p2);
45
46                segment.intersects(&ray)
47            };
48
49            if is_to_right {
50                if segment.0.y() < y && segment.1.y() >= y {
51                    wn += 1;
52                } else if segment.0.y() > y && segment.1.y() <= y {
53                    wn -= 1;
54                }
55            }
56        }
57
58        wn != 0
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use crate::cartesian::traits::polygon::*;
65
66    #[test]
67    fn contains_point() {
68        let polygon = crate::impls::Polygon {
69            outer_contour: crate::impls::ClosedContour {
70                points: vec![
71                    Point2::new(0.0, 0.0),
72                    Point2::new(1.0, 1.0),
73                    Point2::new(1.0, 0.0),
74                ],
75            },
76            inner_contours: vec![],
77        };
78
79        assert!(polygon.contains_point(&Point2::new(0.0, 0.0)));
80        assert!(polygon.contains_point(&Point2::new(1.0, 1.0)));
81        assert!(polygon.contains_point(&Point2::new(0.5, 0.0)));
82        assert!(polygon.contains_point(&Point2::new(0.2, 0.1)));
83        assert!(!polygon.contains_point(&Point2::new(0.2, 0.3)));
84        assert!(!polygon.contains_point(&Point2::new(0.2, -0.3)));
85        assert!(!polygon.contains_point(&Point2::new(1.1, 0.0)));
86    }
87}