Skip to content

Commit bfee118

Browse files
Polygon in Rect performance improvements
1 parent af7b2bd commit bfee118

File tree

4 files changed

+207
-3
lines changed

4 files changed

+207
-3
lines changed

geo/CHANGES.md

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
* <https://github.com/georust/geo/pull/1159>
77
* Fix issue in Debug impl for AffineTransform where yoff is shown instead of xoff
88
* <https://github.com/georust/geo/pull/1191>
9+
* `Polygon` in `Rect` performance improvements.
10+
* <https://github.com/georust/geo/pull/1192>
911

1012
## 0.28.0
1113

geo/benches/contains.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use criterion::{criterion_group, criterion_main, Criterion};
22
use geo::contains::Contains;
3-
use geo::{point, polygon, Line, Point, Polygon, Triangle};
3+
use geo::{coord, point, polygon, Line, Point, Polygon, Rect, Triangle};
44

55
fn criterion_benchmark(c: &mut Criterion) {
66
c.bench_function("point in simple polygon", |bencher| {
@@ -128,6 +128,23 @@ fn criterion_benchmark(c: &mut Criterion) {
128128
assert!(!criterion::black_box(&triangle).contains(criterion::black_box(&point)));
129129
});
130130
});
131+
132+
c.bench_function("Rect contains polygon", |bencher| {
133+
let polygon = polygon![
134+
(x: 150., y: 350.),
135+
(x: 100., y: 350.),
136+
(x: 210., y: 160.),
137+
(x: 290., y: 350.),
138+
(x: 250., y: 350.),
139+
(x: 200., y: 250.),
140+
(x: 150., y: 350.),
141+
];
142+
let rect = Rect::new(coord! { x: 90., y: 150. }, coord! { x: 300., y: 360. });
143+
144+
bencher.iter(|| {
145+
assert!(criterion::black_box(&rect).contains(criterion::black_box(&polygon)));
146+
});
147+
});
131148
}
132149

133150
criterion_group!(benches, criterion_benchmark);

geo/src/algorithm/contains/mod.rs

+145
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ pub(crate) use impl_contains_geometry_for;
9595
mod test {
9696
use crate::line_string;
9797
use crate::Contains;
98+
use crate::Relate;
9899
use crate::{coord, Coord, Line, LineString, MultiPolygon, Point, Polygon, Rect, Triangle};
99100

100101
#[test]
@@ -555,4 +556,148 @@ mod test {
555556
let pt: Point = (0.5, 0.5).into();
556557
assert!(!tri.contains(&pt));
557558
}
559+
560+
#[test]
561+
fn rect_contains_polygon() {
562+
let rect = Rect::new(coord! { x: 90., y: 150. }, coord! { x: 300., y: 360. });
563+
let poly = Polygon::new(
564+
line_string![
565+
(x: 150., y: 350.),
566+
(x: 100., y: 350.),
567+
(x: 210., y: 160.),
568+
(x: 290., y: 350.),
569+
(x: 250., y: 350.),
570+
(x: 200., y: 250.),
571+
(x: 150., y: 350.),
572+
],
573+
vec![],
574+
);
575+
assert_eq!(rect.contains(&poly), rect.relate(&poly).is_contains());
576+
}
577+
578+
#[test]
579+
fn rect_contains_touching_polygon() {
580+
let rect = Rect::new(coord! { x: 90., y: 150. }, coord! { x: 300., y: 360. });
581+
let touching_poly = Polygon::new(
582+
line_string![
583+
(x: 150., y: 350.),
584+
(x: 90., y: 350.),
585+
(x: 210., y: 160.),
586+
(x: 290., y: 350.),
587+
(x: 250., y: 350.),
588+
(x: 200., y: 250.),
589+
(x: 150., y: 350.),
590+
],
591+
vec![],
592+
);
593+
assert_eq!(
594+
rect.contains(&touching_poly),
595+
rect.relate(&touching_poly).is_contains()
596+
);
597+
598+
let touching_rect = Rect::new(coord! { x: 90., y: 200. }, coord! { x: 200., y: 300. });
599+
assert_eq!(
600+
rect.contains(&touching_rect),
601+
rect.relate(&touching_rect).is_contains()
602+
);
603+
}
604+
605+
#[test]
606+
fn rect_contains_empty_polygon() {
607+
let rect = Rect::new(coord! { x: 90., y: 150. }, coord! { x: 300., y: 360. });
608+
let empty_poly = Polygon::new(line_string![], vec![]);
609+
assert_eq!(
610+
rect.contains(&empty_poly),
611+
rect.relate(&empty_poly).is_contains()
612+
);
613+
}
614+
615+
#[test]
616+
fn rect_contains_polygon_empty_area() {
617+
let rect = Rect::new(coord! { x: 90., y: 150. }, coord! { x: 300., y: 360. });
618+
let empty_poly = Polygon::new(
619+
line_string![
620+
(x: 100., y: 200.),
621+
(x: 100., y: 200.),
622+
(x: 100., y: 200.),
623+
(x: 100., y: 200.),
624+
],
625+
vec![],
626+
);
627+
assert_eq!(
628+
rect.contains(&empty_poly),
629+
rect.relate(&empty_poly).is_contains()
630+
);
631+
}
632+
633+
#[test]
634+
fn rect_contains_rect_polygon() {
635+
let rect = Rect::new(coord! { x: 90., y: 150. }, coord! { x: 300., y: 360. });
636+
let rect_poly = rect.clone().to_polygon();
637+
assert_eq!(
638+
rect.contains(&rect_poly),
639+
rect.relate(&rect_poly).is_contains()
640+
);
641+
}
642+
643+
#[test]
644+
fn rect_contains_polygon_in_boundary() {
645+
let rect = Rect::new(coord! { x: 90. , y: 150. }, coord! { x: 300., y: 360. });
646+
let poly_one_border =
647+
Rect::new(coord! { x: 90. , y: 150. }, coord! { x: 90., y: 360. }).to_polygon();
648+
assert_eq!(
649+
rect.contains(&poly_one_border),
650+
rect.relate(&poly_one_border).is_contains()
651+
);
652+
653+
let poly_two_borders = Polygon::new(
654+
line_string![
655+
(x: 90., y: 150.),
656+
(x: 300., y: 150.),
657+
(x: 90., y: 150.),
658+
(x: 90., y: 360.),
659+
(x: 90., y: 150.),
660+
],
661+
vec![],
662+
);
663+
assert_eq!(
664+
rect.contains(&poly_two_borders),
665+
rect.relate(&poly_two_borders).is_contains()
666+
);
667+
}
668+
669+
#[test]
670+
fn rect_empty_contains_polygon() {
671+
let rect = Rect::new(coord! { x: 90. , y: 150. }, coord! { x: 90., y: 150. });
672+
let poly = Polygon::new(
673+
line_string![
674+
(x: 150., y: 350.),
675+
(x: 100., y: 350.),
676+
(x: 210., y: 160.),
677+
(x: 290., y: 350.),
678+
(x: 250., y: 350.),
679+
(x: 200., y: 250.),
680+
(x: 150., y: 350.),
681+
],
682+
vec![],
683+
);
684+
assert_eq!(rect.contains(&poly), rect.relate(&poly).is_contains());
685+
686+
let rect_poly = rect.clone().to_polygon();
687+
assert_eq!(
688+
rect.contains(&rect_poly),
689+
rect.relate(&rect_poly).is_contains()
690+
);
691+
}
692+
693+
#[test]
694+
fn rect_contains_point() {
695+
let rect = Rect::new(coord! { x: 90., y: 150. }, coord! { x: 300., y: 360. });
696+
697+
let point1 = Point::new(100., 200.);
698+
assert_eq!(rect.contains(&point1), rect.relate(&point1).is_contains());
699+
700+
let point2 = Point::new(90., 200.);
701+
assert_eq!(rect.contains(&point2), rect.relate(&point2).is_contains());
702+
}
558703
}

geo/src/algorithm/contains/rect.rs

+42-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
use geo_types::CoordFloat;
2+
13
use super::{impl_contains_from_relate, impl_contains_geometry_for, Contains};
2-
use crate::geometry::*;
4+
use crate::{geometry::*, Area, CoordsIter, HasDimensions};
35
use crate::{CoordNum, GeoFloat};
46

57
// ┌──────────────────────────┐
@@ -41,5 +43,43 @@ where
4143
}
4244
}
4345

44-
impl_contains_from_relate!(Rect<T>, [Line<T>, LineString<T>, Polygon<T>, MultiPoint<T>, MultiLineString<T>, MultiPolygon<T>, GeometryCollection<T>, Triangle<T>]);
46+
impl<T> Contains<Polygon<T>> for Rect<T>
47+
where
48+
T: CoordFloat,
49+
{
50+
fn contains(&self, rhs: &Polygon<T>) -> bool {
51+
// the polygon must not be empty
52+
if rhs.is_empty() {
53+
return false;
54+
}
55+
56+
// none of the polygon's points may lie outside the rectangle
57+
let mut points_inside = 0;
58+
for c in rhs.exterior_coords_iter() {
59+
if c.x < self.min().x || c.x > self.max().x || c.y < self.min().y || c.y > self.max().y
60+
{
61+
return false;
62+
}
63+
if c.x > self.min().x && c.x < self.max().x && c.y > self.min().y && c.y < self.max().y
64+
{
65+
points_inside += 1;
66+
}
67+
}
68+
69+
// The polygon must not lie completely inside the rectangle's boundary.
70+
// In other words: at least one point of the interior of the polygon
71+
// must lie in the interior of the rectangle. Since we know that the
72+
// rectangle is concave, we just need make sure that either at least
73+
// one point of the polygon lies inside the rectangle's interior or
74+
// that the polygon's interior is not empty, in which case it will
75+
// definitely intersect with the rectangle's interior.
76+
if points_inside == 0 && rhs.signed_area().is_zero() {
77+
return false;
78+
}
79+
80+
true
81+
}
82+
}
83+
84+
impl_contains_from_relate!(Rect<T>, [Line<T>, LineString<T>, MultiPoint<T>, MultiLineString<T>, MultiPolygon<T>, GeometryCollection<T>, Triangle<T>]);
4585
impl_contains_geometry_for!(Rect<T>);

0 commit comments

Comments
 (0)