Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Contains edge cases for EMPTY geometries #1227

Merged
merged 2 commits into from
Oct 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions geo/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
* <https://github.com/georust/geo/pull/1216>
* Change IntersectionMatrix::is_equal_topo to now consider empty geometries as equal.
* <https://github.com/georust/geo/pull/1223>
* Fix `(LINESTRING EMPTY).contains(LINESTRING EMPTY)` and `(MULTIPOLYGON EMPTY).contains(MULTIPOINT EMPTY)` which previously
reported true
* <https://github.com/georust/geo/pull/1227>

## 0.28.0

Expand Down
96 changes: 94 additions & 2 deletions geo/benches/contains.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use criterion::{criterion_group, criterion_main, Criterion};
use geo::contains::Contains;
use geo::{coord, point, polygon, Line, Point, Polygon, Rect, Triangle};
use geo::algorithm::{Contains, Convert, Relate};
use geo::geometry::*;
use geo::{coord, point, polygon};

fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("point in simple polygon", |bencher| {
Expand Down Expand Up @@ -145,6 +146,97 @@ fn criterion_benchmark(c: &mut Criterion) {
assert!(criterion::black_box(&rect).contains(criterion::black_box(&polygon)));
});
});

c.bench_function(
"LineString not contains LineString (Contains trait)",
|bencher| {
let ls_1: geo::LineString<f64> = geo_test_fixtures::poly1();
let ls_2: geo::LineString<f64> = geo_test_fixtures::poly2();

bencher.iter(|| {
assert!(!ls_1.contains(&ls_2));
});
},
);

c.bench_function(
"LineString not contains LineString (Relate trait)",
|bencher| {
let ls_1: geo::LineString<f64> = geo_test_fixtures::poly1();
let ls_2: geo::LineString<f64> = geo_test_fixtures::poly2();

bencher.iter(|| {
assert!(!ls_1.relate(&ls_2).is_contains());
});
},
);

c.bench_function(
"LineString contains LineString (Contains trait)",
|bencher| {
let ls_1: LineString<f64> = geo_test_fixtures::poly1();
let mut ls_2 = LineString::new(ls_1.0[1..].to_vec());
ls_2.0.pop();

bencher.iter(|| {
assert!(ls_1.contains(&ls_2));
});
},
);

c.bench_function("LineString contains LineString (Relate trait)", |bencher| {
let ls_1: geo::LineString<f64> = geo_test_fixtures::poly1();
let mut ls_2 = LineString::new(ls_1.0[1..].to_vec());
ls_2.0.pop();

bencher.iter(|| {
assert!(ls_1.relate(&ls_2).is_contains());
});
});

c.bench_function("MultiPolygon contains MultiPoint (Contains trait)", |bencher| {
let p_1: Polygon<f64> = Polygon::new(geo_test_fixtures::poly1(), vec![]);
let p_2: Polygon<f64> = Polygon::new(geo_test_fixtures::poly2(), vec![]);
let multi_poly = MultiPolygon(vec![p_1, p_2]);
let multi_point: MultiPoint<f64> = geo::wkt!(MULTIPOINT (-60 10,-60 -70,-120 -70,-120 10,-40 80,30 80,30 10,-40 10,100 210,100 120,30 120,30 210,-185 -135,-100 -135,-100 -230,-185 -230)).convert();

bencher.iter(|| {
assert!(multi_poly.contains(&multi_point));
});
});

c.bench_function("MultiPolygon contains MultiPoint (Relate trait)", |bencher| {
let p_1: Polygon<f64> = Polygon::new(geo_test_fixtures::poly1(), vec![]);
let p_2: Polygon<f64> = Polygon::new(geo_test_fixtures::poly2(), vec![]);
let multi_poly = MultiPolygon(vec![p_1, p_2]);
let multi_point: MultiPoint<f64> = geo::wkt!(MULTIPOINT (-60 10,-60 -70,-120 -70,-120 10,-40 80,30 80,30 10,-40 10,100 210,100 120,30 120,30 210,-185 -135,-100 -135,-100 -230,-185 -230)).convert();

bencher.iter(|| {
assert!(multi_poly.relate(&multi_point).is_contains());
});
});

c.bench_function("MultiPolygon not contains MultiPoint (Contains trait)", |bencher| {
let p_1: Polygon<f64> = Polygon::new(geo_test_fixtures::poly1(), vec![]);
let p_2: Polygon<f64> = Polygon::new(geo_test_fixtures::poly2(), vec![]);
let multi_poly = MultiPolygon(vec![p_1, p_2]);
let multi_point: MultiPoint<f64> = geo::wkt!(MULTIPOINT (-160 10,-60 -70,-120 -70,-120 10,-40 80,30 80,30 10,-40 10,100 210,100 120,30 120,30 210,-185 -135,-100 -135,-100 -230,-185 -230)).convert();

bencher.iter(|| {
assert!(multi_poly.contains(&multi_point));
});
});

c.bench_function("MultiPolygon not contains MultiPoint (Relate trait)", |bencher| {
let p_1: Polygon<f64> = Polygon::new(geo_test_fixtures::poly1(), vec![]);
let p_2: Polygon<f64> = Polygon::new(geo_test_fixtures::poly2(), vec![]);
let multi_poly = MultiPolygon(vec![p_1, p_2]);
let multi_point: MultiPoint<f64> = geo::wkt!(MULTIPOINT (-160 10,-60 -70,-120 -70,-120 10,-40 80,30 80,30 10,-40 10,100 210,100 120,30 120,30 210,-185 -135,-100 -135,-100 -230,-185 -230)).convert();

bencher.iter(|| {
assert!(multi_poly.relate(&multi_point).is_contains());
});
});
}

criterion_group!(benches, criterion_benchmark);
Expand Down
5 changes: 4 additions & 1 deletion geo/src/algorithm/contains/line_string.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::{impl_contains_from_relate, impl_contains_geometry_for, Contains};
use crate::algorithm::Intersects;
use crate::geometry::*;
use crate::{CoordNum, GeoFloat, GeoNum};
use crate::{CoordNum, GeoFloat, GeoNum, HasDimensions};

// ┌────────────────────────────────┐
// │ Implementations for LineString │
Expand Down Expand Up @@ -110,6 +110,9 @@ where
T: GeoNum,
{
fn contains(&self, rhs: &LineString<T>) -> bool {
if self.is_empty() || rhs.is_empty() {
return false;
}
rhs.lines().all(|l| self.contains(&l))
}
}
Expand Down
5 changes: 4 additions & 1 deletion geo/src/algorithm/contains/polygon.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::{impl_contains_from_relate, impl_contains_geometry_for, Contains};
use crate::geometry::*;
use crate::Relate;
use crate::{GeoFloat, GeoNum};
use crate::{HasDimensions, Relate};

// ┌─────────────────────────────┐
// │ Implementations for Polygon │
Expand Down Expand Up @@ -53,6 +53,9 @@ where

impl<T: GeoNum> Contains<MultiPoint<T>> for MultiPolygon<T> {
fn contains(&self, rhs: &MultiPoint<T>) -> bool {
if self.is_empty() || rhs.is_empty() {
return false;
}
rhs.iter().all(|point| self.contains(point))
}
}
Expand Down
Loading
Loading