diff --git a/geo/benches/prepared_geometry.rs b/geo/benches/prepared_geometry.rs index e9d9b6b675..a9e0e83cc2 100644 --- a/geo/benches/prepared_geometry.rs +++ b/geo/benches/prepared_geometry.rs @@ -1,13 +1,48 @@ -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; use geo::algorithm::Relate; use geo::PreparedGeometry; use geo_types::MultiPolygon; fn criterion_benchmark(c: &mut Criterion) { - c.bench_function("relate prepared polygons", |bencher| { - let plot_polygons: MultiPolygon = geo_test_fixtures::nl_plots_wgs84(); - let zone_polygons = geo_test_fixtures::nl_zones(); + let plot_polygons: MultiPolygon = geo_test_fixtures::nl_plots_wgs84(); + let zone_polygons = geo_test_fixtures::nl_zones(); + c.bench_function("build prepared polygons", |bencher| { + bencher.iter(|| { + let plot_polygons = plot_polygons + .iter() + .map(PreparedGeometry::from) + .collect::>(); + + let zone_polygons = zone_polygons + .iter() + .map(PreparedGeometry::from) + .collect::>(); + + black_box((&plot_polygons, &zone_polygons)); + }); + }); + + c.bench_function("relate already prepared polygons", |bencher| { + let plot_polygons = plot_polygons + .iter() + .map(PreparedGeometry::from) + .collect::>(); + + let zone_polygons = zone_polygons + .iter() + .map(PreparedGeometry::from) + .collect::>(); + + bencher.iter(|| { + for a in &plot_polygons { + for b in &zone_polygons { + black_box(a.relate(b).is_intersects()); + } + } + }); + }); + c.bench_function("build and relate prepared polygons", |bencher| { bencher.iter(|| { let mut intersects = 0; let mut non_intersects = 0; @@ -24,7 +59,7 @@ fn criterion_benchmark(c: &mut Criterion) { for a in &plot_polygons { for b in &zone_polygons { - if criterion::black_box(a.relate(b).is_intersects()) { + if black_box(a.relate(b).is_intersects()) { intersects += 1; } else { non_intersects += 1; @@ -37,7 +72,9 @@ fn criterion_benchmark(c: &mut Criterion) { }); }); - c.bench_function("relate unprepared polygons", |bencher| { + let mut slow_group = c.benchmark_group("unprepared polygons"); + slow_group.sample_size(10); + slow_group.bench_function("relate unprepared polygons", |bencher| { let plot_polygons: MultiPolygon = geo_test_fixtures::nl_plots_wgs84(); let zone_polygons = geo_test_fixtures::nl_zones(); @@ -47,7 +84,7 @@ fn criterion_benchmark(c: &mut Criterion) { for a in &plot_polygons { for b in &zone_polygons { - if criterion::black_box(a.relate(b).is_intersects()) { + if black_box(a.relate(b).is_intersects()) { intersects += 1; } else { non_intersects += 1; diff --git a/geo/src/algorithm/relate/geomgraph/index/prepared_geometry.rs b/geo/src/algorithm/relate/geomgraph/index/prepared_geometry.rs index dfc01cf0e0..1663ac53bd 100644 --- a/geo/src/algorithm/relate/geomgraph/index/prepared_geometry.rs +++ b/geo/src/algorithm/relate/geomgraph/index/prepared_geometry.rs @@ -41,19 +41,8 @@ where { let mut geometry_graph = GeometryGraph::new(0, geometry.clone().into()); let r_tree = geometry_graph.build_tree(); - let envelope = r_tree.root().envelope(); - - // geo and rstar have different conventions for how to represet an empty bounding boxes - let bounding_rect: Option> = if envelope == rstar::AABB::new_empty() { - None - } else { - Some(Rect::new(envelope.lower(), envelope.upper())) - }; - // They should be equal - but we can save the computation in the `--release` case - // by using the bounding_rect from the RTree - debug_assert_eq!(bounding_rect, geometry_graph.geometry().bounding_rect()); - geometry_graph.set_tree(Rc::new(r_tree)); + let bounding_rect = geometry_graph.geometry().bounding_rect(); // TODO: don't pass in line intersector here - in theory we'll want pluggable line intersectors // and the type (Robust) shouldn't be hard coded here. @@ -124,7 +113,7 @@ where mod tests { use super::*; use crate::algorithm::Relate; - use crate::polygon; + use crate::{polygon, wkt}; #[test] fn relate() { @@ -172,4 +161,44 @@ mod tests { assert_eq!(&poly, prepared_geom.geometry()); assert_eq!(poly, prepared_geom.into_geometry()); } + + #[test] + fn zero_dimensional_point() { + let poly = polygon![(x: 0.0, y: 0.0), (x: 2.0, y: 0.0), (x: 1.0, y: 2.0)]; + let prepared_poly = PreparedGeometry::from(&poly); + let point = crate::point!(x: 1.0, y: 1.0); + let prepared_point = PreparedGeometry::from(&point); + + let im = poly.relate(&point); + assert!(im.matches("0F2FF1FF2").unwrap(), "got {im:?}"); + + let im = prepared_poly.relate(&point); + assert!(im.matches("0F2FF1FF2").unwrap(), "got {im:?}"); + + let im = poly.relate(&prepared_point); + assert!(im.matches("0F2FF1FF2").unwrap(), "got {im:?}"); + + let im = prepared_poly.relate(&prepared_point); + assert!(im.matches("0F2FF1FF2").unwrap(), "got {im:?}"); + } + + #[test] + fn zero_dimensional_multipoint() { + let poly = polygon![(x: 0.0, y: 0.0), (x: 2.0, y: 0.0), (x: 1.0, y: 2.0)]; + let prepared_poly = PreparedGeometry::from(&poly); + let multi_point = wkt!(MULTIPOINT(1. 1.)); + let prepared_multi_point = PreparedGeometry::from(&multi_point); + + let im = poly.relate(&multi_point); + assert!(im.matches("0F2FF1FF2").unwrap(), "got {im:?}"); + + let im = prepared_poly.relate(&multi_point); + assert!(im.matches("0F2FF1FF2").unwrap(), "got {im:?}"); + + let im = poly.relate(&prepared_multi_point); + assert!(im.matches("0F2FF1FF2").unwrap(), "got {im:?}"); + + let im = prepared_poly.relate(&prepared_multi_point); + assert!(im.matches("0F2FF1FF2").unwrap(), "got {im:?}"); + } }