geo_traits/
geometry.rs

1use std::marker::PhantomData;
2
3#[cfg(feature = "geo-types")]
4use geo_types::{
5    CoordNum, Geometry, GeometryCollection, Line, LineString, MultiLineString, MultiPoint,
6    MultiPolygon, Point, Polygon, Rect, Triangle,
7};
8
9use crate::{
10    Dimensions, GeometryCollectionTrait, LineStringTrait, LineTrait, MultiLineStringTrait,
11    MultiPointTrait, MultiPolygonTrait, PointTrait, PolygonTrait, RectTrait, TriangleTrait,
12    UnimplementedGeometryCollection, UnimplementedLine, UnimplementedLineString,
13    UnimplementedMultiLineString, UnimplementedMultiPoint, UnimplementedMultiPolygon,
14    UnimplementedPoint, UnimplementedPolygon, UnimplementedRect, UnimplementedTriangle,
15};
16
17/// A trait for accessing data from a generic Geometry.
18#[allow(clippy::type_complexity)]
19pub trait GeometryTrait {
20    /// The coordinate type of this geometry
21    type T;
22
23    /// The type of each underlying Point, which implements [PointTrait]
24    type PointType<'a>: 'a + PointTrait<T = Self::T>
25    where
26        Self: 'a;
27
28    /// The type of each underlying LineString, which implements [LineStringTrait]
29    type LineStringType<'a>: 'a + LineStringTrait<T = Self::T>
30    where
31        Self: 'a;
32
33    /// The type of each underlying Polygon, which implements [PolygonTrait]
34    type PolygonType<'a>: 'a + PolygonTrait<T = Self::T>
35    where
36        Self: 'a;
37
38    /// The type of each underlying MultiPoint, which implements [MultiPointTrait]
39    type MultiPointType<'a>: 'a + MultiPointTrait<T = Self::T>
40    where
41        Self: 'a;
42
43    /// The type of each underlying MultiLineString, which implements [MultiLineStringTrait]
44    type MultiLineStringType<'a>: 'a + MultiLineStringTrait<T = Self::T>
45    where
46        Self: 'a;
47
48    /// The type of each underlying MultiPolygon, which implements [MultiPolygonTrait]
49    type MultiPolygonType<'a>: 'a + MultiPolygonTrait<T = Self::T>
50    where
51        Self: 'a;
52
53    /// The type of each underlying GeometryCollection, which implements [GeometryCollectionTrait]
54    type GeometryCollectionType<'a>: 'a + GeometryCollectionTrait<T = Self::T>
55    where
56        Self: 'a;
57
58    /// The type of each underlying Rect, which implements [RectTrait]
59    type RectType<'a>: 'a + RectTrait<T = Self::T>
60    where
61        Self: 'a;
62
63    /// The type of each underlying Triangle, which implements [TriangleTrait]
64    type TriangleType<'a>: 'a + TriangleTrait<T = Self::T>
65    where
66        Self: 'a;
67
68    /// The type of each underlying Line, which implements [LineTrait]
69    type LineType<'a>: 'a + LineTrait<T = Self::T>
70    where
71        Self: 'a;
72
73    /// The dimension of this geometry
74    fn dim(&self) -> Dimensions;
75
76    /// Cast this geometry to a [`GeometryType`] enum, which allows for downcasting to a specific
77    /// type
78    fn as_type(
79        &self,
80    ) -> GeometryType<
81        '_,
82        Self::PointType<'_>,
83        Self::LineStringType<'_>,
84        Self::PolygonType<'_>,
85        Self::MultiPointType<'_>,
86        Self::MultiLineStringType<'_>,
87        Self::MultiPolygonType<'_>,
88        Self::GeometryCollectionType<'_>,
89        Self::RectType<'_>,
90        Self::TriangleType<'_>,
91        Self::LineType<'_>,
92    >;
93}
94
95/// An enumeration of all geometry types that can be contained inside a [GeometryTrait]. This is
96/// used for extracting concrete geometry types out of a [GeometryTrait].
97#[derive(Debug)]
98pub enum GeometryType<'a, P, LS, Y, MP, ML, MY, GC, R, T, L>
99where
100    P: PointTrait,
101    LS: LineStringTrait,
102    Y: PolygonTrait,
103    MP: MultiPointTrait,
104    ML: MultiLineStringTrait,
105    MY: MultiPolygonTrait,
106    GC: GeometryCollectionTrait,
107    R: RectTrait,
108    T: TriangleTrait,
109    L: LineTrait,
110{
111    /// A Point, which implements [PointTrait]
112    Point(&'a P),
113    /// A LineString, which implements [LineStringTrait]
114    LineString(&'a LS),
115    /// A Polygon, which implements [PolygonTrait]
116    Polygon(&'a Y),
117    /// A MultiPoint, which implements [MultiPointTrait]
118    MultiPoint(&'a MP),
119    /// A MultiLineString, which implements [MultiLineStringTrait]
120    MultiLineString(&'a ML),
121    /// A MultiPolygon, which implements [MultiPolygonTrait]
122    MultiPolygon(&'a MY),
123    /// A GeometryCollection, which implements [GeometryCollectionTrait]
124    GeometryCollection(&'a GC),
125    /// A Rect, which implements [RectTrait]
126    Rect(&'a R),
127    /// A Triangle, which implements [TriangleTrait]
128    Triangle(&'a T),
129    /// A Line, which implements [LineTrait]
130    Line(&'a L),
131}
132
133#[cfg(feature = "geo-types")]
134impl<T: CoordNum> GeometryTrait for Geometry<T> {
135    type T = T;
136    type PointType<'b>
137        = Point<Self::T>
138    where
139        Self: 'b;
140    type LineStringType<'b>
141        = LineString<Self::T>
142    where
143        Self: 'b;
144    type PolygonType<'b>
145        = Polygon<Self::T>
146    where
147        Self: 'b;
148    type MultiPointType<'b>
149        = MultiPoint<Self::T>
150    where
151        Self: 'b;
152    type MultiLineStringType<'b>
153        = MultiLineString<Self::T>
154    where
155        Self: 'b;
156    type MultiPolygonType<'b>
157        = MultiPolygon<Self::T>
158    where
159        Self: 'b;
160    type GeometryCollectionType<'b>
161        = GeometryCollection<Self::T>
162    where
163        Self: 'b;
164    type RectType<'b>
165        = Rect<Self::T>
166    where
167        Self: 'b;
168    type TriangleType<'b>
169        = Triangle<Self::T>
170    where
171        Self: 'b;
172    type LineType<'b>
173        = Line<Self::T>
174    where
175        Self: 'b;
176
177    fn dim(&self) -> Dimensions {
178        Dimensions::Xy
179    }
180
181    fn as_type(
182        &self,
183    ) -> GeometryType<
184        '_,
185        Point<T>,
186        LineString<T>,
187        Polygon<T>,
188        MultiPoint<T>,
189        MultiLineString<T>,
190        MultiPolygon<T>,
191        GeometryCollection<T>,
192        Rect<T>,
193        Triangle<T>,
194        Line<T>,
195    > {
196        match self {
197            Geometry::Point(p) => GeometryType::Point(p),
198            Geometry::LineString(p) => GeometryType::LineString(p),
199            Geometry::Polygon(p) => GeometryType::Polygon(p),
200            Geometry::MultiPoint(p) => GeometryType::MultiPoint(p),
201            Geometry::MultiLineString(p) => GeometryType::MultiLineString(p),
202            Geometry::MultiPolygon(p) => GeometryType::MultiPolygon(p),
203            Geometry::GeometryCollection(p) => GeometryType::GeometryCollection(p),
204            Geometry::Rect(p) => GeometryType::Rect(p),
205            Geometry::Triangle(p) => GeometryType::Triangle(p),
206            Geometry::Line(p) => GeometryType::Line(p),
207        }
208    }
209}
210
211#[cfg(feature = "geo-types")]
212impl<'a, T: CoordNum + 'a> GeometryTrait for &'a Geometry<T> {
213    type T = T;
214    type PointType<'b>
215        = Point<Self::T>
216    where
217        Self: 'b;
218    type LineStringType<'b>
219        = LineString<Self::T>
220    where
221        Self: 'b;
222    type PolygonType<'b>
223        = Polygon<Self::T>
224    where
225        Self: 'b;
226    type MultiPointType<'b>
227        = MultiPoint<Self::T>
228    where
229        Self: 'b;
230    type MultiLineStringType<'b>
231        = MultiLineString<Self::T>
232    where
233        Self: 'b;
234    type MultiPolygonType<'b>
235        = MultiPolygon<Self::T>
236    where
237        Self: 'b;
238    type GeometryCollectionType<'b>
239        = GeometryCollection<Self::T>
240    where
241        Self: 'b;
242    type RectType<'b>
243        = Rect<Self::T>
244    where
245        Self: 'b;
246    type TriangleType<'b>
247        = Triangle<Self::T>
248    where
249        Self: 'b;
250    type LineType<'b>
251        = Line<Self::T>
252    where
253        Self: 'b;
254
255    fn dim(&self) -> Dimensions {
256        Dimensions::Xy
257    }
258
259    fn as_type(
260        &self,
261    ) -> GeometryType<
262        '_,
263        Point<T>,
264        LineString<T>,
265        Polygon<T>,
266        MultiPoint<T>,
267        MultiLineString<T>,
268        MultiPolygon<T>,
269        GeometryCollection<T>,
270        Rect<T>,
271        Triangle<T>,
272        Line<T>,
273    > {
274        match self {
275            Geometry::Point(p) => GeometryType::Point(p),
276            Geometry::LineString(p) => GeometryType::LineString(p),
277            Geometry::Polygon(p) => GeometryType::Polygon(p),
278            Geometry::MultiPoint(p) => GeometryType::MultiPoint(p),
279            Geometry::MultiLineString(p) => GeometryType::MultiLineString(p),
280            Geometry::MultiPolygon(p) => GeometryType::MultiPolygon(p),
281            Geometry::GeometryCollection(p) => GeometryType::GeometryCollection(p),
282            Geometry::Rect(p) => GeometryType::Rect(p),
283            Geometry::Triangle(p) => GeometryType::Triangle(p),
284            Geometry::Line(p) => GeometryType::Line(p),
285        }
286    }
287}
288
289// Specialized implementations on each geo-types concrete type.
290
291macro_rules! impl_specialization {
292    ($geometry_type:ident) => {
293        #[cfg(feature = "geo-types")]
294        impl<T: CoordNum> GeometryTrait for $geometry_type<T> {
295            type T = T;
296            type PointType<'b>
297                = Point<Self::T>
298            where
299                Self: 'b;
300            type LineStringType<'b>
301                = LineString<Self::T>
302            where
303                Self: 'b;
304            type PolygonType<'b>
305                = Polygon<Self::T>
306            where
307                Self: 'b;
308            type MultiPointType<'b>
309                = MultiPoint<Self::T>
310            where
311                Self: 'b;
312            type MultiLineStringType<'b>
313                = MultiLineString<Self::T>
314            where
315                Self: 'b;
316            type MultiPolygonType<'b>
317                = MultiPolygon<Self::T>
318            where
319                Self: 'b;
320            type GeometryCollectionType<'b>
321                = GeometryCollection<Self::T>
322            where
323                Self: 'b;
324            type RectType<'b>
325                = Rect<Self::T>
326            where
327                Self: 'b;
328            type TriangleType<'b>
329                = Triangle<Self::T>
330            where
331                Self: 'b;
332            type LineType<'b>
333                = Line<Self::T>
334            where
335                Self: 'b;
336
337            fn dim(&self) -> Dimensions {
338                Dimensions::Xy
339            }
340
341            fn as_type(
342                &self,
343            ) -> GeometryType<
344                '_,
345                Point<T>,
346                LineString<T>,
347                Polygon<T>,
348                MultiPoint<T>,
349                MultiLineString<T>,
350                MultiPolygon<T>,
351                GeometryCollection<T>,
352                Rect<T>,
353                Triangle<T>,
354                Line<T>,
355            > {
356                GeometryType::$geometry_type(self)
357            }
358        }
359
360        #[cfg(feature = "geo-types")]
361        impl<'a, T: CoordNum + 'a> GeometryTrait for &'a $geometry_type<T> {
362            type T = T;
363            type PointType<'b>
364                = Point<Self::T>
365            where
366                Self: 'b;
367            type LineStringType<'b>
368                = LineString<Self::T>
369            where
370                Self: 'b;
371            type PolygonType<'b>
372                = Polygon<Self::T>
373            where
374                Self: 'b;
375            type MultiPointType<'b>
376                = MultiPoint<Self::T>
377            where
378                Self: 'b;
379            type MultiLineStringType<'b>
380                = MultiLineString<Self::T>
381            where
382                Self: 'b;
383            type MultiPolygonType<'b>
384                = MultiPolygon<Self::T>
385            where
386                Self: 'b;
387            type GeometryCollectionType<'b>
388                = GeometryCollection<Self::T>
389            where
390                Self: 'b;
391            type RectType<'b>
392                = Rect<Self::T>
393            where
394                Self: 'b;
395            type TriangleType<'b>
396                = Triangle<Self::T>
397            where
398                Self: 'b;
399            type LineType<'b>
400                = Line<Self::T>
401            where
402                Self: 'b;
403
404            fn dim(&self) -> Dimensions {
405                Dimensions::Xy
406            }
407
408            fn as_type(
409                &self,
410            ) -> GeometryType<
411                '_,
412                Point<T>,
413                LineString<T>,
414                Polygon<T>,
415                MultiPoint<T>,
416                MultiLineString<T>,
417                MultiPolygon<T>,
418                GeometryCollection<T>,
419                Rect<T>,
420                Triangle<T>,
421                Line<T>,
422            > {
423                GeometryType::$geometry_type(self)
424            }
425        }
426    };
427}
428
429impl_specialization!(Point);
430impl_specialization!(LineString);
431impl_specialization!(Polygon);
432impl_specialization!(MultiPoint);
433impl_specialization!(MultiLineString);
434impl_specialization!(MultiPolygon);
435impl_specialization!(GeometryCollection);
436impl_specialization!(Rect);
437impl_specialization!(Triangle);
438impl_specialization!(Line);
439
440/// An empty struct that implements [GeometryTrait].
441///
442/// This is used internally for [`UnimplementedGeometryCollection`], so that
443/// `UnimplementedGeometryCollection` can be used as the `GeometryCollectionType` of the
444/// `GeometryTrait` by implementations that don't have a GeometryCollection concept
445pub struct UnimplementedGeometry<T>(PhantomData<T>);
446
447impl<T> GeometryTrait for UnimplementedGeometry<T> {
448    type T = T;
449    type PointType<'b>
450        = UnimplementedPoint<T>
451    where
452        Self: 'b;
453    type LineStringType<'b>
454        = UnimplementedLineString<Self::T>
455    where
456        Self: 'b;
457    type PolygonType<'b>
458        = UnimplementedPolygon<Self::T>
459    where
460        Self: 'b;
461    type MultiPointType<'b>
462        = UnimplementedMultiPoint<Self::T>
463    where
464        Self: 'b;
465    type MultiLineStringType<'b>
466        = UnimplementedMultiLineString<Self::T>
467    where
468        Self: 'b;
469    type MultiPolygonType<'b>
470        = UnimplementedMultiPolygon<Self::T>
471    where
472        Self: 'b;
473    type GeometryCollectionType<'b>
474        = UnimplementedGeometryCollection<Self::T>
475    where
476        Self: 'b;
477    type RectType<'b>
478        = UnimplementedRect<Self::T>
479    where
480        Self: 'b;
481    type TriangleType<'b>
482        = UnimplementedTriangle<Self::T>
483    where
484        Self: 'b;
485    type LineType<'b>
486        = UnimplementedLine<Self::T>
487    where
488        Self: 'b;
489
490    fn dim(&self) -> Dimensions {
491        unimplemented!()
492    }
493
494    fn as_type(
495        &self,
496    ) -> GeometryType<
497        '_,
498        Self::PointType<'_>,
499        Self::LineStringType<'_>,
500        Self::PolygonType<'_>,
501        Self::MultiPointType<'_>,
502        Self::MultiLineStringType<'_>,
503        Self::MultiPolygonType<'_>,
504        Self::GeometryCollectionType<'_>,
505        Self::RectType<'_>,
506        Self::TriangleType<'_>,
507        Self::LineType<'_>,
508    > {
509        unimplemented!()
510    }
511}
512
513// Specialized implementations on each unimplemented type.
514
515macro_rules! impl_unimplemented_specialization {
516    ($geometry_type:ident, $variant:expr) => {
517        impl<T> GeometryTrait for $geometry_type<T> {
518            type T = T;
519            type PointType<'b>
520                = UnimplementedPoint<Self::T>
521            where
522                Self: 'b;
523            type LineStringType<'b>
524                = UnimplementedLineString<Self::T>
525            where
526                Self: 'b;
527            type PolygonType<'b>
528                = UnimplementedPolygon<Self::T>
529            where
530                Self: 'b;
531            type MultiPointType<'b>
532                = UnimplementedMultiPoint<Self::T>
533            where
534                Self: 'b;
535            type MultiLineStringType<'b>
536                = UnimplementedMultiLineString<Self::T>
537            where
538                Self: 'b;
539            type MultiPolygonType<'b>
540                = UnimplementedMultiPolygon<Self::T>
541            where
542                Self: 'b;
543            type GeometryCollectionType<'b>
544                = UnimplementedGeometryCollection<Self::T>
545            where
546                Self: 'b;
547            type RectType<'b>
548                = UnimplementedRect<Self::T>
549            where
550                Self: 'b;
551            type TriangleType<'b>
552                = UnimplementedTriangle<Self::T>
553            where
554                Self: 'b;
555            type LineType<'b>
556                = UnimplementedLine<Self::T>
557            where
558                Self: 'b;
559
560            fn dim(&self) -> Dimensions {
561                unimplemented!()
562            }
563
564            fn as_type(
565                &self,
566            ) -> GeometryType<
567                '_,
568                Self::PointType<'_>,
569                Self::LineStringType<'_>,
570                Self::PolygonType<'_>,
571                Self::MultiPointType<'_>,
572                Self::MultiLineStringType<'_>,
573                Self::MultiPolygonType<'_>,
574                Self::GeometryCollectionType<'_>,
575                Self::RectType<'_>,
576                Self::TriangleType<'_>,
577                Self::LineType<'_>,
578            > {
579                $variant(self)
580            }
581        }
582
583        impl<'a, T> GeometryTrait for &'a $geometry_type<T> {
584            type T = T;
585            type PointType<'b>
586                = UnimplementedPoint<Self::T>
587            where
588                Self: 'b;
589            type LineStringType<'b>
590                = UnimplementedLineString<Self::T>
591            where
592                Self: 'b;
593            type PolygonType<'b>
594                = UnimplementedPolygon<Self::T>
595            where
596                Self: 'b;
597            type MultiPointType<'b>
598                = UnimplementedMultiPoint<Self::T>
599            where
600                Self: 'b;
601            type MultiLineStringType<'b>
602                = UnimplementedMultiLineString<Self::T>
603            where
604                Self: 'b;
605            type MultiPolygonType<'b>
606                = UnimplementedMultiPolygon<Self::T>
607            where
608                Self: 'b;
609            type GeometryCollectionType<'b>
610                = UnimplementedGeometryCollection<Self::T>
611            where
612                Self: 'b;
613            type RectType<'b>
614                = UnimplementedRect<Self::T>
615            where
616                Self: 'b;
617            type TriangleType<'b>
618                = UnimplementedTriangle<Self::T>
619            where
620                Self: 'b;
621            type LineType<'b>
622                = UnimplementedLine<Self::T>
623            where
624                Self: 'b;
625
626            fn dim(&self) -> Dimensions {
627                unimplemented!()
628            }
629
630            fn as_type(
631                &self,
632            ) -> GeometryType<
633                '_,
634                Self::PointType<'_>,
635                Self::LineStringType<'_>,
636                Self::PolygonType<'_>,
637                Self::MultiPointType<'_>,
638                Self::MultiLineStringType<'_>,
639                Self::MultiPolygonType<'_>,
640                Self::GeometryCollectionType<'_>,
641                Self::RectType<'_>,
642                Self::TriangleType<'_>,
643                Self::LineType<'_>,
644            > {
645                $variant(self)
646            }
647        }
648    };
649}
650
651impl_unimplemented_specialization!(UnimplementedPoint, GeometryType::Point);
652impl_unimplemented_specialization!(UnimplementedLineString, GeometryType::LineString);
653impl_unimplemented_specialization!(UnimplementedPolygon, GeometryType::Polygon);
654impl_unimplemented_specialization!(UnimplementedMultiPoint, GeometryType::MultiPoint);
655impl_unimplemented_specialization!(UnimplementedMultiLineString, GeometryType::MultiLineString);
656impl_unimplemented_specialization!(UnimplementedMultiPolygon, GeometryType::MultiPolygon);
657impl_unimplemented_specialization!(
658    UnimplementedGeometryCollection,
659    GeometryType::GeometryCollection
660);
661impl_unimplemented_specialization!(UnimplementedRect, GeometryType::Rect);
662impl_unimplemented_specialization!(UnimplementedTriangle, GeometryType::Triangle);
663impl_unimplemented_specialization!(UnimplementedLine, GeometryType::Line);
664
665#[cfg(test)]
666mod test {
667    // Ensures that all geo-types implement the GeometryTrait
668    #[test]
669    #[cfg(feature = "geo-types")]
670    fn geo_types_implement_geometry_trait() {
671        use geo_types::{
672            coord, Geometry, GeometryCollection, Line, LineString, MultiLineString, MultiPoint,
673            MultiPolygon, Point, Polygon, Rect, Triangle,
674        };
675
676        use crate::GeometryTrait;
677
678        fn requires_geometry_trait<G: GeometryTrait>(_geometry: &G) {}
679
680        let point: Point = Point::new(0.0, 0.0);
681        requires_geometry_trait(&point);
682
683        let line: Line = Line::new(coord! { x: 0.0, y: 0.0 }, coord! { x: 1.0, y: 1.0 });
684        requires_geometry_trait(&line);
685
686        let line_string: LineString =
687            LineString::from(vec![coord! { x: 0.0, y: 0.0 }, coord! { x: 1.0, y: 1.0 }]);
688        requires_geometry_trait(&line_string);
689
690        let polygon: Polygon = Polygon::new(line_string.clone(), vec![]);
691        requires_geometry_trait(&polygon);
692
693        let multi_point: MultiPoint = MultiPoint::from(vec![point]);
694        requires_geometry_trait(&multi_point);
695
696        let multi_line_string: MultiLineString = MultiLineString(vec![line_string.clone()]);
697        requires_geometry_trait(&multi_line_string);
698
699        let multi_polygon: MultiPolygon = MultiPolygon::from(vec![polygon.clone()]);
700        requires_geometry_trait(&multi_polygon);
701
702        let geometry_collection: GeometryCollection =
703            GeometryCollection::from(vec![Geometry::Point(point)]);
704        requires_geometry_trait(&geometry_collection);
705
706        let rect: Rect = Rect::new(coord! { x: 0.0, y: 0.0 }, coord! { x: 1.0, y: 1.0 });
707        requires_geometry_trait(&rect);
708
709        let triangle: Triangle = Triangle::new(
710            coord! { x: 0.0, y: 0.0 },
711            coord! { x: 1.0, y: 0.0 },
712            coord! { x: 0.0, y: 1.0 },
713        );
714        requires_geometry_trait(&triangle);
715
716        let geometry: Geometry = Geometry::Point(point);
717        requires_geometry_trait(&geometry);
718    }
719}