galileo_types/
polygon.rs

1use crate::cartesian::{CartesianPoint2d, CartesianPolygon, Rect};
2use crate::contour::Contour;
3use crate::geo::Projection;
4use crate::geometry::{
5    CartesianGeometry2d, CartesianGeometry2dSpecialization, Geom, Geometry, GeometrySpecialization,
6};
7use crate::geometry_type::{CartesianSpace2d, GeometryType, PolygonGeometryType};
8use crate::segment::Segment;
9
10/// Polygon geometry. Polygon consists of one outer contour, and zero or more inner contours.
11///
12/// Zero contours represent *holes* in a polygon. If one inner contour is inside another inner contour, it represents
13/// non-hole area inside a hole.
14pub trait Polygon {
15    /// Contour type.
16    type Contour: Contour;
17
18    /// Outer contour of the polygon.
19    fn outer_contour(&self) -> &Self::Contour;
20    /// iterates over inner contours.
21    fn inner_contours(&self) -> impl Iterator<Item = &'_ Self::Contour>;
22
23    /// Iterates over all contours of the polygon starting with the outer one.
24    fn iter_contours(&self) -> impl Iterator<Item = &'_ Self::Contour> {
25        Box::new(std::iter::once(self.outer_contour()).chain(self.inner_contours()))
26    }
27
28    /// Iterates over all segments of the polygon contour lines.
29    fn iter_segments(&self) -> impl Iterator<Item = Segment<<Self::Contour as Contour>::Point>>
30    where
31        <Self::Contour as Contour>::Point: Copy,
32    {
33        Box::new(self.iter_contours().flat_map(Self::Contour::iter_segments))
34    }
35}
36
37impl<Poly, Space> GeometrySpecialization<PolygonGeometryType, Space> for Poly
38where
39    Poly: Polygon + GeometryType<Type = PolygonGeometryType, Space = Space>,
40    Poly::Contour: Geometry,
41{
42    type Point = <Poly::Contour as Geometry>::Point;
43
44    fn project_spec<Proj>(&self, projection: &Proj) -> Option<Geom<Proj::OutPoint>>
45    where
46        Proj: Projection<InPoint = Self::Point> + ?Sized,
47    {
48        let Geom::Contour(outer_contour) = self.outer_contour().project(projection)? else {
49            return None;
50        };
51        let inner_contours = self
52            .inner_contours()
53            .map(|c| {
54                c.project(projection).and_then(|c| match c {
55                    Geom::Contour(contour) => contour.into_closed(),
56                    _ => None,
57                })
58            })
59            .collect::<Option<Vec<crate::impls::ClosedContour<Proj::OutPoint>>>>()?;
60        Some(Geom::Polygon(crate::impls::Polygon {
61            outer_contour: outer_contour.into_closed()?,
62            inner_contours,
63        }))
64    }
65}
66
67impl<P, Poly> CartesianGeometry2dSpecialization<P, PolygonGeometryType> for Poly
68where
69    P: CartesianPoint2d + Copy,
70    Poly: Polygon
71        + CartesianPolygon<Point = P>
72        + GeometryType<Type = PolygonGeometryType, Space = CartesianSpace2d>
73        + Geometry<Point = P>,
74    Poly::Contour: Contour<Point = P> + CartesianGeometry2d<P>,
75{
76    fn is_point_inside_spec<Other: CartesianPoint2d<Num = P::Num>>(
77        &self,
78        point: &Other,
79        _tolerance: P::Num,
80    ) -> bool {
81        self.contains_point(point)
82    }
83
84    fn bounding_rectangle_spec(&self) -> Option<Rect<P::Num>> {
85        self.iter_contours()
86            .filter_map(|c| c.bounding_rectangle())
87            .collect()
88    }
89}