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
10pub trait Polygon {
15 type Contour: Contour;
17
18 fn outer_contour(&self) -> &Self::Contour;
20 fn inner_contours(&self) -> impl Iterator<Item = &'_ Self::Contour>;
22
23 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 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}