galileo_types/cartesian/traits/
polygon.rs1use crate::cartesian::traits::cartesian_point::CartesianPoint2d;
2use crate::cartesian::Point2;
3use crate::contour::ClosedContour;
4use crate::polygon::Polygon;
5use crate::segment::Segment;
6
7pub trait CartesianPolygon {
9 type Point: CartesianPoint2d;
11
12 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}