geo/algorithm/contains/
mod.rs

1/// Checks if `rhs` is completely contained within `self`.
2/// More formally, the interior of `rhs` has non-empty
3/// (set-theoretic) intersection but neither the interior,
4/// nor the boundary of `rhs` intersects the exterior of
5/// `self`. In other words, the [DE-9IM] intersection matrix
6/// of `(rhs, self)` is `T*F**F***`.
7///
8/// [DE-9IM]: https://en.wikipedia.org/wiki/DE-9IM
9///
10/// # Examples
11///
12/// ```
13/// use geo::Contains;
14/// use geo::{line_string, point, Polygon};
15///
16/// let line_string = line_string![
17///     (x: 0., y: 0.),
18///     (x: 2., y: 0.),
19///     (x: 2., y: 2.),
20///     (x: 0., y: 2.),
21///     (x: 0., y: 0.),
22/// ];
23///
24/// let polygon = Polygon::new(line_string.clone(), vec![]);
25///
26/// // Point in Point
27/// assert!(point!(x: 2., y: 0.).contains(&point!(x: 2., y: 0.)));
28///
29/// // Point in Linestring
30/// assert!(line_string.contains(&point!(x: 2., y: 0.)));
31///
32/// // Point in Polygon
33/// assert!(polygon.contains(&point!(x: 1., y: 1.)));
34/// ```
35///
36/// # Performance Note
37///
38/// The `MultiPolygon.contains(&MultiPoint)` containment check has been optimised for large geometries.
39/// Checking many points against many polygons (or many points against a `MultiPolygon`) will be less
40/// efficient than building `Multi-` versions (if possible) and checking those.
41///
42pub trait Contains<Rhs = Self> {
43    fn contains(&self, rhs: &Rhs) -> bool;
44}
45
46mod coordinate;
47mod geometry;
48mod geometry_collection;
49mod line;
50mod line_string;
51mod point;
52pub(crate) mod polygon;
53mod rect;
54mod triangle;
55
56macro_rules! impl_contains_from_relate {
57    ($for:ty,  [$($target:ty),*]) => {
58        $(
59            impl<T> Contains<$target> for $for
60            where
61                T: GeoFloat
62            {
63                fn contains(&self, target: &$target) -> bool {
64                    use $crate::algorithm::Relate;
65                    self.relate(target).is_contains()
66                }
67            }
68        )*
69    };
70}
71pub(crate) use impl_contains_from_relate;
72
73macro_rules! impl_contains_geometry_for {
74    ($geom_type: ty) => {
75        impl<T> Contains<Geometry<T>> for $geom_type
76        where
77            T: GeoFloat,
78        {
79            fn contains(&self, geometry: &Geometry<T>) -> bool {
80                match geometry {
81                    Geometry::Point(g) => self.contains(g),
82                    Geometry::Line(g) => self.contains(g),
83                    Geometry::LineString(g) => self.contains(g),
84                    Geometry::Polygon(g) => self.contains(g),
85                    Geometry::MultiPoint(g) => self.contains(g),
86                    Geometry::MultiLineString(g) => self.contains(g),
87                    Geometry::MultiPolygon(g) => self.contains(g),
88                    Geometry::GeometryCollection(g) => self.contains(g),
89                    Geometry::Rect(g) => self.contains(g),
90                    Geometry::Triangle(g) => self.contains(g),
91                }
92            }
93        }
94    };
95}
96pub(crate) use impl_contains_geometry_for;
97
98// ┌───────┐
99// │ Tests │
100// └───────┘
101
102#[cfg(test)]
103mod test {
104    use crate::BoundingRect;
105    use crate::Contains;
106    use crate::Relate;
107    use crate::indexed::IntervalTreeMultiPolygon;
108    use crate::line_string;
109    use crate::{Coord, Line, LineString, MultiPolygon, Point, Polygon, Rect, Triangle, coord};
110
111    #[test]
112    // see https://github.com/georust/geo/issues/452
113    fn linestring_contains_point() {
114        let line_string = LineString::from(vec![(0., 0.), (3., 3.)]);
115        let point_on_line = Point::new(1., 1.);
116        assert!(line_string.contains(&point_on_line));
117    }
118    #[test]
119    // V doesn't contain rect because two of its edges intersect with V's exterior boundary
120    fn polygon_does_not_contain_polygon() {
121        let v = Polygon::new(
122            vec![
123                (150., 350.),
124                (100., 350.),
125                (210., 160.),
126                (290., 350.),
127                (250., 350.),
128                (200., 250.),
129                (150., 350.),
130            ]
131            .into(),
132            vec![],
133        );
134        let rect = Polygon::new(
135            vec![
136                (250., 310.),
137                (150., 310.),
138                (150., 280.),
139                (250., 280.),
140                (250., 310.),
141            ]
142            .into(),
143            vec![],
144        );
145        assert!(!v.contains(&rect));
146    }
147    #[test]
148    // V contains rect because all its vertices are contained, and none of its edges intersect with V's boundaries
149    fn polygon_contains_polygon() {
150        let v = Polygon::new(
151            vec![
152                (150., 350.),
153                (100., 350.),
154                (210., 160.),
155                (290., 350.),
156                (250., 350.),
157                (200., 250.),
158                (150., 350.),
159            ]
160            .into(),
161            vec![],
162        );
163        let rect = Polygon::new(
164            vec![
165                (185., 237.),
166                (220., 237.),
167                (220., 220.),
168                (185., 220.),
169                (185., 237.),
170            ]
171            .into(),
172            vec![],
173        );
174        assert!(v.contains(&rect));
175    }
176    #[test]
177    // LineString is fully contained
178    fn linestring_fully_contained_in_polygon() {
179        let poly = Polygon::new(
180            LineString::from(vec![(0., 0.), (5., 0.), (5., 6.), (0., 6.), (0., 0.)]),
181            vec![],
182        );
183        let ls = LineString::from(vec![(3.0, 0.5), (3.0, 3.5)]);
184        assert!(poly.contains(&ls));
185    }
186    /// Tests: Point in LineString
187    #[test]
188    fn empty_linestring_test() {
189        let linestring = LineString::empty();
190        assert!(!linestring.contains(&Point::new(2., 1.)));
191    }
192    #[test]
193    fn linestring_point_is_vertex_test() {
194        let linestring = LineString::from(vec![(0., 0.), (2., 0.), (2., 2.)]);
195        // Note: the end points of a linestring are not
196        // considered to be "contained"
197        assert!(linestring.contains(&Point::new(2., 0.)));
198        assert!(!linestring.contains(&Point::new(0., 0.)));
199        assert!(!linestring.contains(&Point::new(2., 2.)));
200    }
201    #[test]
202    fn linestring_test() {
203        let linestring = LineString::from(vec![(0., 0.), (2., 0.), (2., 2.)]);
204        assert!(linestring.contains(&Point::new(1., 0.)));
205    }
206    /// Tests: Point in Polygon
207    #[test]
208    fn empty_polygon_test() {
209        let poly = Polygon::empty();
210        assert!(!poly.contains(&Point::new(2., 1.)));
211    }
212    #[test]
213    fn polygon_with_one_point_test() {
214        let linestring = LineString::from(vec![(2., 1.)]);
215        let poly = Polygon::new(linestring, Vec::new());
216        assert!(!poly.contains(&Point::new(3., 1.)));
217    }
218    #[test]
219    fn polygon_with_one_point_is_vertex_test() {
220        let linestring = LineString::from(vec![(2., 1.)]);
221        let poly = Polygon::new(linestring, Vec::new());
222        assert!(!poly.contains(&Point::new(2., 1.)));
223    }
224    #[test]
225    fn polygon_with_point_on_boundary_test() {
226        let linestring = LineString::from(vec![(0., 0.), (2., 0.), (2., 2.), (0., 2.), (0., 0.)]);
227        let poly = Polygon::new(linestring, Vec::new());
228        assert!(!poly.contains(&Point::new(1., 0.)));
229        assert!(!poly.contains(&Point::new(2., 1.)));
230        assert!(!poly.contains(&Point::new(1., 2.)));
231        assert!(!poly.contains(&Point::new(0., 1.)));
232    }
233    #[test]
234    fn point_in_polygon_test() {
235        let linestring = LineString::from(vec![(0., 0.), (2., 0.), (2., 2.), (0., 2.), (0., 0.)]);
236        let poly = Polygon::new(linestring, Vec::new());
237        assert!(poly.contains(&Point::new(1., 1.)));
238    }
239    #[test]
240    fn point_in_polygon_with_ray_passing_through_a_vertex_test() {
241        let linestring = LineString::from(vec![(1., 0.), (0., 1.), (-1., 0.), (0., -1.)]);
242        let poly = Polygon::new(linestring, Vec::new());
243        assert!(poly.contains(&Point::new(0., 0.)));
244    }
245    #[test]
246    fn point_in_polygon_with_ray_passing_through_a_vertex_and_not_crossing() {
247        let linestring = LineString::from(vec![
248            (0., 0.),
249            (2., 0.),
250            (3., 1.),
251            (4., 0.),
252            (4., 2.),
253            (0., 2.),
254            (0., 0.),
255        ]);
256        let poly = Polygon::new(linestring, Vec::new());
257        assert!(poly.contains(&Point::new(1., 1.)));
258    }
259    #[test]
260    fn point_out_polygon_test() {
261        let linestring = LineString::from(vec![(0., 0.), (2., 0.), (2., 2.), (0., 2.), (0., 0.)]);
262        let poly = Polygon::new(linestring, Vec::new());
263        assert!(!poly.contains(&Point::new(2.1, 1.)));
264        assert!(!poly.contains(&Point::new(1., 2.1)));
265        assert!(!poly.contains(&Point::new(2.1, 2.1)));
266    }
267    #[test]
268    fn point_polygon_with_inner_test() {
269        let linestring = LineString::from(vec![(0., 0.), (2., 0.), (2., 2.), (0., 2.), (0., 0.)]);
270        let inner_linestring = LineString::from(vec![
271            [0.5, 0.5],
272            [1.5, 0.5],
273            [1.5, 1.5],
274            [0.0, 1.5],
275            [0.0, 0.0],
276        ]);
277        let poly = Polygon::new(linestring, vec![inner_linestring]);
278        assert!(!poly.contains(&Point::new(0.25, 0.25)));
279        assert!(!poly.contains(&Point::new(1., 1.)));
280        assert!(!poly.contains(&Point::new(1.5, 1.5)));
281        assert!(!poly.contains(&Point::new(1.5, 1.)));
282    }
283
284    /// Tests: Point in MultiPolygon
285    #[test]
286    fn empty_multipolygon_test() {
287        let multipoly = MultiPolygon::empty();
288        assert!(!multipoly.contains(&Point::new(2., 1.)));
289    }
290    #[test]
291    fn empty_multipolygon_two_polygons_test() {
292        let poly1 = Polygon::new(
293            LineString::from(vec![(0., 0.), (1., 0.), (1., 1.), (0., 1.), (0., 0.)]),
294            Vec::new(),
295        );
296        let poly2 = Polygon::new(
297            LineString::from(vec![(2., 0.), (3., 0.), (3., 1.), (2., 1.), (2., 0.)]),
298            Vec::new(),
299        );
300        let multipoly = MultiPolygon::new(vec![poly1, poly2]);
301        assert!(multipoly.contains(&Point::new(0.5, 0.5)));
302        assert!(multipoly.contains(&Point::new(2.5, 0.5)));
303        assert!(!multipoly.contains(&Point::new(1.5, 0.5)));
304    }
305    #[test]
306    fn empty_multipolygon_two_polygons_and_inner_test() {
307        let poly1 = Polygon::new(
308            LineString::from(vec![(0., 0.), (5., 0.), (5., 6.), (0., 6.), (0., 0.)]),
309            vec![LineString::from(vec![
310                (1., 1.),
311                (4., 1.),
312                (4., 4.),
313                (1., 1.),
314            ])],
315        );
316        let poly2 = Polygon::new(
317            LineString::from(vec![(9., 0.), (14., 0.), (14., 4.), (9., 4.), (9., 0.)]),
318            Vec::new(),
319        );
320
321        let multipoly = MultiPolygon::new(vec![poly1, poly2]);
322        assert!(multipoly.contains(&Point::new(3., 5.)));
323        assert!(multipoly.contains(&Point::new(12., 2.)));
324        assert!(!multipoly.contains(&Point::new(3., 2.)));
325        assert!(!multipoly.contains(&Point::new(7., 2.)));
326    }
327
328    #[test]
329    fn empty_multipolygon_fast_test() {
330        let multipoly = MultiPolygon::<f64>::new(Vec::new());
331        assert!(!multipoly.contains(&Point::new(2., 1.)));
332    }
333
334    // GEOS gives us 45 points
335    #[test]
336    fn contains_geos() {
337        let zones: MultiPolygon<f64> = geo_test_fixtures::nl_zones();
338        let bound = zones.bounding_rect().unwrap();
339        let mut coords = vec![];
340
341        // Generate a bunch of points inside the zone bounds
342        let size = 20;
343        let mut x = bound.min().x;
344        for _ in 0..=size {
345            let mut y = bound.min().y;
346            for _ in 0..=size {
347                coords.push(Coord { x, y });
348                y += bound.height() / size as f64;
349            }
350
351            x += bound.width() / size as f64;
352        }
353
354        let indexed = IntervalTreeMultiPolygon::new(&zones);
355        let mut inside = 0;
356        for c in &coords {
357            if indexed.contains(c) {
358                inside += 1;
359            }
360        }
361        assert_eq!(inside, 45);
362    }
363
364    #[test]
365    fn multipolygon_two_polygons_fast_test() {
366        let poly1 = Polygon::new(
367            LineString::from(vec![(0., 0.), (1., 0.), (1., 1.), (0., 1.), (0., 0.)]),
368            Vec::new(),
369        );
370        let poly2 = Polygon::new(
371            LineString::from(vec![(2., 0.), (3., 0.), (3., 1.), (2., 1.), (2., 0.)]),
372            Vec::new(),
373        );
374        let multipoly = MultiPolygon::new(vec![poly1, poly2]);
375        assert!(multipoly.contains(&Point::new(0.5, 0.5)));
376        assert!(multipoly.contains(&Point::new(2.5, 0.5)));
377        assert!(!multipoly.contains(&Point::new(1.5, 0.5)));
378    }
379
380    #[test]
381    fn multipolygon_two_polygons_and_inner_fast_test() {
382        let poly1 = Polygon::new(
383            LineString::from(vec![(0., 0.), (5., 0.), (5., 6.), (0., 6.), (0., 0.)]),
384            vec![LineString::from(vec![
385                (1., 1.),
386                (4., 1.),
387                (4., 4.),
388                (1., 1.),
389            ])],
390        );
391        let poly2 = Polygon::new(
392            LineString::from(vec![(9., 0.), (14., 0.), (14., 4.), (9., 4.), (9., 0.)]),
393            Vec::new(),
394        );
395
396        let multipoly = MultiPolygon::new(vec![poly1, poly2]);
397        assert!(multipoly.contains(&Point::new(3., 5.)));
398        assert!(multipoly.contains(&Point::new(12., 2.)));
399        assert!(!multipoly.contains(&Point::new(3., 2.)));
400        assert!(!multipoly.contains(&Point::new(7., 2.)));
401    }
402
403    /// Tests: LineString in Polygon
404    #[test]
405    fn linestring_in_polygon_with_linestring_is_boundary_test() {
406        let linestring = LineString::from(vec![(0., 0.), (2., 0.), (2., 2.), (0., 2.), (0., 0.)]);
407        let poly = Polygon::new(linestring.clone(), Vec::new());
408        assert!(!poly.contains(&linestring));
409        assert!(!poly.contains(&LineString::from(vec![(0., 0.), (2., 0.)])));
410        assert!(!poly.contains(&LineString::from(vec![(2., 0.), (2., 2.)])));
411        assert!(!poly.contains(&LineString::from(vec![(0., 2.), (0., 0.)])));
412    }
413    #[test]
414    fn linestring_outside_polygon_test() {
415        let linestring = LineString::from(vec![(0., 0.), (2., 0.), (2., 2.), (0., 2.), (0., 0.)]);
416        let poly = Polygon::new(linestring, Vec::new());
417        assert!(!poly.contains(&LineString::from(vec![(1., 1.), (3., 0.)])));
418        assert!(!poly.contains(&LineString::from(vec![(3., 0.), (5., 2.)])));
419    }
420    #[test]
421    fn linestring_in_inner_polygon_test() {
422        let poly = Polygon::new(
423            LineString::from(vec![(0., 0.), (5., 0.), (5., 6.), (0., 6.), (0., 0.)]),
424            vec![LineString::from(vec![
425                (1., 1.),
426                (4., 1.),
427                (4., 4.),
428                (1., 4.),
429                (1., 1.),
430            ])],
431        );
432        assert!(!poly.contains(&LineString::from(vec![(2., 2.), (3., 3.)])));
433        assert!(!poly.contains(&LineString::from(vec![(2., 2.), (2., 5.)])));
434        assert!(!poly.contains(&LineString::from(vec![(3., 0.5), (3., 5.)])));
435    }
436    #[test]
437    fn bounding_rect_in_inner_bounding_rect_test() {
438        let bounding_rect_xl =
439            Rect::new(coord! { x: -100., y: -200. }, coord! { x: 100., y: 200. });
440        let bounding_rect_sm = Rect::new(coord! { x: -10., y: -20. }, coord! { x: 10., y: 20. });
441        assert!(bounding_rect_xl.contains(&bounding_rect_sm));
442        assert!(!bounding_rect_sm.contains(&bounding_rect_xl));
443    }
444    #[test]
445    fn point_in_line_test() {
446        let c = |x, y| coord! { x: x, y: y };
447        let p0 = c(2., 4.);
448        // vertical line
449        let line1 = Line::new(c(2., 0.), c(2., 5.));
450        // point on line, but outside line segment
451        let line2 = Line::new(c(0., 6.), c(1.5, 4.5));
452        // point on line
453        let line3 = Line::new(c(0., 6.), c(3., 3.));
454        assert!(line1.contains(&Point::from(p0)));
455        assert!(!line2.contains(&Point::from(p0)));
456        assert!(line3.contains(&Point::from(p0)));
457    }
458    #[test]
459    fn line_in_line_test() {
460        let c = |x, y| coord! { x: x, y: y };
461        let line0 = Line::new(c(0., 1.), c(3., 4.));
462        // first point on line0, second not
463        let line1 = Line::new(c(1., 2.), c(2., 2.));
464        // co-linear, but extends past the end of line0
465        let line2 = Line::new(c(1., 2.), c(4., 5.));
466        // contained in line0
467        let line3 = Line::new(c(1., 2.), c(3., 4.));
468        assert!(!line0.contains(&line1));
469        assert!(!line0.contains(&line2));
470        assert!(line0.contains(&line3));
471    }
472    #[test]
473    fn linestring_in_line_test() {
474        let line = Line::from([(0, 10), (30, 40)]);
475        // linestring0 in line
476        let linestring0 = LineString::from(vec![(1, 11), (10, 20), (15, 25)]);
477        // linestring1 starts and ends in line, but wanders in the middle
478        let linestring1 = LineString::from(vec![(1, 11), (20, 20), (15, 25)]);
479        // linestring2 is co-linear, but extends beyond line
480        let linestring2 = LineString::from(vec![(1, 11), (10, 20), (40, 50)]);
481        // no part of linestring3 is contained in line
482        let linestring3 = LineString::from(vec![(11, 11), (20, 20), (25, 25)]);
483        // a linestring with singleton interior on the boundary of the line
484        let linestring4 = LineString::from(vec![(0, 10), (0, 10), (0, 10)]);
485        // a linestring with singleton interior that is contained in the line
486        let linestring5 = LineString::from(vec![(1, 11), (1, 11), (1, 11)]);
487        assert!(line.contains(&linestring0));
488        assert!(!line.contains(&linestring1));
489        assert!(!line.contains(&linestring2));
490        assert!(!line.contains(&linestring3));
491        assert!(!line.contains(&linestring4));
492        assert!(line.contains(&linestring5));
493    }
494    #[test]
495    fn line_in_polygon_test() {
496        let c = |x, y| coord! { x: x, y: y };
497        let line = Line::new(c(0.0, 10.0), c(30.0, 40.0));
498        let linestring0 = line_string![
499            c(-10.0, 0.0),
500            c(50.0, 0.0),
501            c(50.0, 50.0),
502            c(0.0, 50.0),
503            c(-10.0, 0.0)
504        ];
505        let poly0 = Polygon::new(linestring0, Vec::new());
506        let linestring1 = line_string![
507            c(0.0, 0.0),
508            c(0.0, 20.0),
509            c(20.0, 20.0),
510            c(20.0, 0.0),
511            c(0.0, 0.0)
512        ];
513        let poly1 = Polygon::new(linestring1, Vec::new());
514        assert!(poly0.contains(&line));
515        assert!(!poly1.contains(&line));
516    }
517    #[test]
518    fn line_in_polygon_edgecases_test() {
519        // Some DE-9IM edge cases for checking line is
520        // inside polygon The end points of the line can be
521        // on the boundary of the polygon.
522        let c = |x, y| coord! { x: x, y: y };
523        // A non-convex polygon
524        let linestring0 = line_string![
525            c(0.0, 0.0),
526            c(1.0, 1.0),
527            c(1.0, -1.0),
528            c(-1.0, -1.0),
529            c(-1.0, 1.0)
530        ];
531        let poly = Polygon::new(linestring0, Vec::new());
532
533        assert!(poly.contains(&Line::new(c(0.0, 0.0), c(1.0, -1.0))));
534        assert!(poly.contains(&Line::new(c(-1.0, 1.0), c(1.0, -1.0))));
535        assert!(!poly.contains(&Line::new(c(-1.0, 1.0), c(1.0, 1.0))));
536    }
537    #[test]
538    fn line_in_linestring_edgecases() {
539        let c = |x, y| coord! { x: x, y: y };
540        use crate::line_string;
541        let mut ls = line_string![c(0, 0), c(1, 0), c(0, 1), c(-1, 0)];
542        assert!(!ls.contains(&Line::from([(0, 0), (0, 0)])));
543        ls.close();
544        assert!(ls.contains(&Line::from([(0, 0), (0, 0)])));
545        assert!(ls.contains(&Line::from([(-1, 0), (1, 0)])));
546    }
547    #[test]
548    fn line_in_linestring_test() {
549        let line0 = Line::from([(1., 1.), (2., 2.)]);
550        // line0 is completely contained in the second segment
551        let linestring0 = LineString::from(vec![(0., 0.5), (0.5, 0.5), (3., 3.)]);
552        // line0 is contained in the last three segments
553        let linestring1 = LineString::from(vec![
554            (0., 0.5),
555            (0.5, 0.5),
556            (1.2, 1.2),
557            (1.5, 1.5),
558            (3., 3.),
559        ]);
560        // line0 endpoints are contained in the linestring, but the fourth point is off the line
561        let linestring2 = LineString::from(vec![
562            (0., 0.5),
563            (0.5, 0.5),
564            (1.2, 1.2),
565            (1.5, 0.),
566            (2., 2.),
567            (3., 3.),
568        ]);
569        assert!(linestring0.contains(&line0));
570        assert!(linestring1.contains(&line0));
571        assert!(!linestring2.contains(&line0));
572    }
573
574    #[test]
575    fn integer_bounding_rects() {
576        let p: Point<i32> = Point::new(10, 20);
577        let bounding_rect: Rect<i32> = Rect::new(coord! { x: 0, y: 0 }, coord! { x: 100, y: 100 });
578        assert!(bounding_rect.contains(&p));
579        assert!(!bounding_rect.contains(&Point::new(-10, -10)));
580
581        let smaller_bounding_rect: Rect<i32> =
582            Rect::new(coord! { x: 10, y: 10 }, coord! { x: 20, y: 20 });
583        assert!(bounding_rect.contains(&smaller_bounding_rect));
584    }
585
586    #[test]
587    fn triangle_not_contains_point_on_edge() {
588        let t = Triangle::from([(0.0, 0.0), (2.0, 0.0), (2.0, 2.0)]);
589        let p = Point::new(1.0, 0.0);
590        assert!(!t.contains(&p));
591    }
592
593    #[test]
594    fn triangle_not_contains_point_on_vertex() {
595        let t = Triangle::from([(0.0, 0.0), (2.0, 0.0), (2.0, 2.0)]);
596        let p = Point::new(2.0, 0.0);
597        assert!(!t.contains(&p));
598    }
599
600    #[test]
601    fn triangle_contains_point_inside() {
602        let t = Triangle::from([(0.0, 0.0), (2.0, 0.0), (2.0, 2.0)]);
603        let p = Point::new(1.0, 0.5);
604        assert!(t.contains(&p));
605    }
606
607    #[test]
608    fn triangle_not_contains_point_above() {
609        let t = Triangle::from([(0.0, 0.0), (2.0, 0.0), (2.0, 2.0)]);
610        let p = Point::new(1.0, 1.5);
611        assert!(!t.contains(&p));
612    }
613
614    #[test]
615    fn triangle_not_contains_point_below() {
616        let t = Triangle::from([(0.0, 0.0), (2.0, 0.0), (2.0, 2.0)]);
617        let p = Point::new(-1.0, 0.5);
618        assert!(!t.contains(&p));
619    }
620
621    #[test]
622    fn triangle_contains_neg_point() {
623        let t = Triangle::from([(0.0, 0.0), (-2.0, 0.0), (-2.0, -2.0)]);
624        let p = Point::new(-1.0, -0.5);
625        assert!(t.contains(&p));
626    }
627
628    #[test]
629    // https://github.com/georust/geo/issues/473
630    fn triangle_contains_collinear_points() {
631        let origin: Coord = (0., 0.).into();
632        let tri = Triangle::new(origin, origin, origin);
633        let pt: Point = (0., 1.23456).into();
634        assert!(!tri.contains(&pt));
635        let pt: Point = (0., 0.).into();
636        assert!(!tri.contains(&pt));
637        let origin: Coord = (0., 0.).into();
638        let tri = Triangle::new((1., 1.).into(), origin, origin);
639        let pt: Point = (1., 1.).into();
640        assert!(!tri.contains(&pt));
641        let pt: Point = (0.5, 0.5).into();
642        assert!(!tri.contains(&pt));
643    }
644
645    #[test]
646    fn rect_contains_polygon() {
647        let rect = Rect::new(coord! { x: 90., y: 150. }, coord! { x: 300., y: 360. });
648        let poly = Polygon::new(
649            line_string![
650                (x: 150., y: 350.),
651                (x: 100., y: 350.),
652                (x: 210., y: 160.),
653                (x: 290., y: 350.),
654                (x: 250., y: 350.),
655                (x: 200., y: 250.),
656                (x: 150., y: 350.),
657            ],
658            vec![],
659        );
660        assert_eq!(rect.contains(&poly), rect.relate(&poly).is_contains());
661    }
662
663    #[test]
664    fn rect_contains_touching_polygon() {
665        let rect = Rect::new(coord! { x: 90., y: 150. }, coord! { x: 300., y: 360. });
666        let touching_poly = Polygon::new(
667            line_string![
668                (x: 150., y: 350.),
669                (x: 90.,  y: 350.),
670                (x: 210., y: 160.),
671                (x: 290., y: 350.),
672                (x: 250., y: 350.),
673                (x: 200., y: 250.),
674                (x: 150., y: 350.),
675            ],
676            vec![],
677        );
678        assert_eq!(
679            rect.contains(&touching_poly),
680            rect.relate(&touching_poly).is_contains()
681        );
682
683        let touching_rect = Rect::new(coord! { x: 90., y: 200. }, coord! { x: 200., y: 300. });
684        assert_eq!(
685            rect.contains(&touching_rect),
686            rect.relate(&touching_rect).is_contains()
687        );
688    }
689
690    #[test]
691    fn rect_contains_empty_polygon() {
692        let rect = Rect::new(coord! { x: 90., y: 150. }, coord! { x: 300., y: 360. });
693        let empty_poly = Polygon::empty();
694        assert_eq!(
695            rect.contains(&empty_poly),
696            rect.relate(&empty_poly).is_contains()
697        );
698    }
699
700    #[test]
701    fn rect_contains_polygon_empty_area() {
702        let rect = Rect::new(coord! { x: 90., y: 150. }, coord! { x: 300., y: 360. });
703        let empty_poly = Polygon::new(
704            line_string![
705                (x: 100., y: 200.),
706                (x: 100., y: 200.),
707                (x: 100., y: 200.),
708                (x: 100., y: 200.),
709            ],
710            vec![],
711        );
712        assert_eq!(
713            rect.contains(&empty_poly),
714            rect.relate(&empty_poly).is_contains()
715        );
716    }
717
718    #[test]
719    fn rect_contains_rect_polygon() {
720        let rect = Rect::new(coord! { x: 90., y: 150. }, coord! { x: 300., y: 360. });
721        let rect_poly = rect.to_polygon();
722        assert_eq!(
723            rect.contains(&rect_poly),
724            rect.relate(&rect_poly).is_contains()
725        );
726    }
727
728    #[test]
729    fn rect_contains_polygon_in_boundary() {
730        let rect = Rect::new(coord! { x: 90. , y: 150. }, coord! { x: 300., y: 360. });
731        let poly_one_border =
732            Rect::new(coord! { x: 90. , y: 150. }, coord! { x: 90., y: 360. }).to_polygon();
733        assert_eq!(
734            rect.contains(&poly_one_border),
735            rect.relate(&poly_one_border).is_contains()
736        );
737
738        let poly_two_borders = Polygon::new(
739            line_string![
740                (x: 90., y: 150.),
741                (x: 300., y: 150.),
742                (x: 90., y: 150.),
743                (x: 90., y: 360.),
744                (x: 90., y: 150.),
745            ],
746            vec![],
747        );
748        assert_eq!(
749            rect.contains(&poly_two_borders),
750            rect.relate(&poly_two_borders).is_contains()
751        );
752
753        let poly_two_borders_triangle = Polygon::new(
754            line_string![
755                (x: 90., y: 150.),
756                (x: 300., y: 150.),
757                (x: 90., y: 360.),
758                (x: 90., y: 150.),
759            ],
760            vec![],
761        );
762        assert_eq!(
763            rect.contains(&poly_two_borders_triangle),
764            rect.relate(&poly_two_borders_triangle).is_contains()
765        );
766    }
767
768    #[test]
769    fn rect_contains_polygon_in_boundary_with_hole() {
770        let rect = Rect::new(coord! { x: 90. , y: 150. }, coord! { x: 300., y: 360. });
771        let poly_two_borders_triangle_with_hole = Polygon::new(
772            line_string![
773                (x: 90., y: 150.),
774                (x: 300., y: 150.),
775                (x: 90., y: 360.),
776                (x: 90., y: 150.),
777            ],
778            vec![line_string![
779                (x: 90., y: 150.),
780                (x: 300., y: 150.),
781                (x: 90., y: 360.),
782                (x: 90., y: 150.),
783            ]],
784        );
785        assert_eq!(
786            rect.contains(&poly_two_borders_triangle_with_hole),
787            rect.relate(&poly_two_borders_triangle_with_hole)
788                .is_contains()
789        );
790    }
791
792    #[test]
793    fn rect_empty_contains_polygon() {
794        let rect = Rect::new(coord! { x: 90. , y: 150. }, coord! { x: 90., y: 150. });
795        let poly = Polygon::new(
796            line_string![
797                (x: 150., y: 350.),
798                (x: 100., y: 350.),
799                (x: 210., y: 160.),
800                (x: 290., y: 350.),
801                (x: 250., y: 350.),
802                (x: 200., y: 250.),
803                (x: 150., y: 350.),
804            ],
805            vec![],
806        );
807        assert_eq!(rect.contains(&poly), rect.relate(&poly).is_contains());
808
809        let rect_poly = rect.to_polygon();
810        assert_eq!(
811            rect.contains(&rect_poly),
812            rect.relate(&rect_poly).is_contains()
813        );
814    }
815
816    #[test]
817    fn rect_contains_point() {
818        let rect = Rect::new(coord! { x: 90., y: 150. }, coord! { x: 300., y: 360. });
819
820        let point1 = Point::new(100., 200.);
821        assert_eq!(rect.contains(&point1), rect.relate(&point1).is_contains());
822
823        let point2 = Point::new(90., 200.);
824        assert_eq!(rect.contains(&point2), rect.relate(&point2).is_contains());
825    }
826
827    #[test]
828    fn exhaustive_compile_test() {
829        use geo_types::*;
830        let c = Coord { x: 0., y: 0. };
831        let pt: Point = Point::new(0., 0.);
832        let ls = line_string![(0., 0.).into(), (1., 1.).into()];
833        let multi_ls = MultiLineString::new(vec![ls.clone()]);
834        let ln: Line = Line::new((0., 0.), (1., 1.));
835
836        let poly = Polygon::new(LineString::from(vec![(0., 0.), (1., 1.), (1., 0.)]), vec![]);
837        let rect = Rect::new(coord! { x: 10., y: 20. }, coord! { x: 30., y: 10. });
838        let tri = Triangle::new(
839            coord! { x: 0., y: 0. },
840            coord! { x: 10., y: 20. },
841            coord! { x: 20., y: -10. },
842        );
843        let geom = Geometry::Point(pt);
844        let gc = GeometryCollection::new_from(vec![geom.clone()]);
845        let multi_point = MultiPoint::new(vec![pt]);
846        let multi_poly = MultiPolygon::new(vec![poly.clone()]);
847
848        let _ = c.contains(&c);
849        let _ = c.contains(&pt);
850        let _ = c.contains(&ln);
851        let _ = c.contains(&ls);
852        let _ = c.contains(&poly);
853        let _ = c.contains(&rect);
854        let _ = c.contains(&tri);
855        let _ = c.contains(&geom);
856        let _ = c.contains(&gc);
857        let _ = c.contains(&multi_point);
858        let _ = c.contains(&multi_ls);
859        let _ = c.contains(&multi_poly);
860
861        let _ = pt.contains(&c);
862        let _ = pt.contains(&pt);
863        let _ = pt.contains(&ln);
864        let _ = pt.contains(&ls);
865        let _ = pt.contains(&poly);
866        let _ = pt.contains(&rect);
867        let _ = pt.contains(&tri);
868        let _ = pt.contains(&geom);
869        let _ = pt.contains(&gc);
870        let _ = pt.contains(&multi_point);
871        let _ = pt.contains(&multi_ls);
872        let _ = pt.contains(&multi_poly);
873
874        let _ = ln.contains(&c);
875        let _ = ln.contains(&pt);
876        let _ = ln.contains(&ln);
877        let _ = ln.contains(&ls);
878        let _ = ln.contains(&poly);
879        let _ = ln.contains(&rect);
880        let _ = ln.contains(&tri);
881        let _ = ln.contains(&geom);
882        let _ = ln.contains(&gc);
883        let _ = ln.contains(&multi_point);
884        let _ = ln.contains(&multi_ls);
885        let _ = ln.contains(&multi_poly);
886
887        let _ = ls.contains(&c);
888        let _ = ls.contains(&pt);
889        let _ = ls.contains(&ln);
890        let _ = ls.contains(&ls);
891        let _ = ls.contains(&poly);
892        let _ = ls.contains(&rect);
893        let _ = ls.contains(&tri);
894        let _ = ls.contains(&geom);
895        let _ = ls.contains(&gc);
896        let _ = ls.contains(&multi_point);
897        let _ = ls.contains(&multi_ls);
898        let _ = ls.contains(&multi_poly);
899
900        let _ = poly.contains(&c);
901        let _ = poly.contains(&pt);
902        let _ = poly.contains(&ln);
903        let _ = poly.contains(&ls);
904        let _ = poly.contains(&poly);
905        let _ = poly.contains(&rect);
906        let _ = poly.contains(&tri);
907        let _ = poly.contains(&geom);
908        let _ = poly.contains(&gc);
909        let _ = poly.contains(&multi_point);
910        let _ = poly.contains(&multi_ls);
911        let _ = poly.contains(&multi_poly);
912
913        let _ = rect.contains(&c);
914        let _ = rect.contains(&pt);
915        let _ = rect.contains(&ln);
916        let _ = rect.contains(&ls);
917        let _ = rect.contains(&poly);
918        let _ = rect.contains(&rect);
919        let _ = rect.contains(&tri);
920        let _ = rect.contains(&geom);
921        let _ = rect.contains(&gc);
922        let _ = rect.contains(&multi_point);
923        let _ = rect.contains(&multi_ls);
924        let _ = rect.contains(&multi_poly);
925
926        let _ = tri.contains(&c);
927        let _ = tri.contains(&pt);
928        let _ = tri.contains(&ln);
929        let _ = tri.contains(&ls);
930        let _ = tri.contains(&poly);
931        let _ = tri.contains(&rect);
932        let _ = tri.contains(&tri);
933        let _ = tri.contains(&geom);
934        let _ = tri.contains(&gc);
935        let _ = tri.contains(&multi_point);
936        let _ = tri.contains(&multi_ls);
937        let _ = tri.contains(&multi_poly);
938
939        let _ = geom.contains(&c);
940        let _ = geom.contains(&pt);
941        let _ = geom.contains(&ln);
942        let _ = geom.contains(&ls);
943        let _ = geom.contains(&poly);
944        let _ = geom.contains(&rect);
945        let _ = geom.contains(&tri);
946        let _ = geom.contains(&geom);
947        let _ = geom.contains(&gc);
948        let _ = geom.contains(&multi_point);
949        let _ = geom.contains(&multi_ls);
950        let _ = geom.contains(&multi_poly);
951
952        let _ = gc.contains(&c);
953        let _ = gc.contains(&pt);
954        let _ = gc.contains(&ln);
955        let _ = gc.contains(&ls);
956        let _ = gc.contains(&poly);
957        let _ = gc.contains(&rect);
958        let _ = gc.contains(&tri);
959        let _ = gc.contains(&geom);
960        let _ = gc.contains(&gc);
961        let _ = gc.contains(&multi_point);
962        let _ = gc.contains(&multi_ls);
963        let _ = gc.contains(&multi_poly);
964
965        let _ = multi_point.contains(&c);
966        let _ = multi_point.contains(&pt);
967        let _ = multi_point.contains(&ln);
968        let _ = multi_point.contains(&ls);
969        let _ = multi_point.contains(&poly);
970        let _ = multi_point.contains(&rect);
971        let _ = multi_point.contains(&tri);
972        let _ = multi_point.contains(&geom);
973        let _ = multi_point.contains(&gc);
974        let _ = multi_point.contains(&multi_point);
975        let _ = multi_point.contains(&multi_ls);
976        let _ = multi_point.contains(&multi_poly);
977
978        let _ = multi_ls.contains(&c);
979        let _ = multi_ls.contains(&pt);
980        let _ = multi_ls.contains(&ln);
981        let _ = multi_ls.contains(&ls);
982        let _ = multi_ls.contains(&poly);
983        let _ = multi_ls.contains(&rect);
984        let _ = multi_ls.contains(&tri);
985        let _ = multi_ls.contains(&geom);
986        let _ = multi_ls.contains(&gc);
987        let _ = multi_ls.contains(&multi_point);
988        let _ = multi_ls.contains(&multi_ls);
989        let _ = multi_ls.contains(&multi_poly);
990
991        let _ = multi_poly.contains(&c);
992        let _ = multi_poly.contains(&pt);
993        let _ = multi_poly.contains(&ln);
994        let _ = multi_poly.contains(&ls);
995        let _ = multi_poly.contains(&poly);
996        let _ = multi_poly.contains(&rect);
997        let _ = multi_poly.contains(&tri);
998        let _ = multi_poly.contains(&geom);
999        let _ = multi_poly.contains(&gc);
1000        let _ = multi_poly.contains(&multi_point);
1001        let _ = multi_poly.contains(&multi_ls);
1002        let _ = multi_poly.contains(&multi_poly);
1003    }
1004}