diff --git a/geo-benches/src/contains_properly.rs b/geo-benches/src/contains_properly.rs index 410968434..1fa6cf190 100644 --- a/geo-benches/src/contains_properly.rs +++ b/geo-benches/src/contains_properly.rs @@ -1,10 +1,77 @@ use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main}; use geo::PreparedGeometry; -use geo::algorithm::{ContainsProperly, Convert, Relate}; +use geo::algorithm::{Contains, ContainsProperly, Convert, Relate}; use geo::wkt; use geo::{coord, geometry::*}; use std::iter::once; +fn coord_in_line(c: &mut Criterion) { + { + let mut group = c.benchmark_group("multipoint"); + let line = Line::new(coord! {x:10.,y:10.}, coord! {x:0.,y:0.}); + let point: MultiPoint = MultiPoint::new( + std::iter::successors(Some((0.1, 0.1)), |(x, y)| Some((x + 0.1, y + 0.1))) + .take_while(|(x, _y)| *x < 10.0) + .map(|(x, y)| Point::new(x, y)) + .collect::>(), + ); + + group.bench_function("contains multipoint (Trait)", |bencher| { + bencher.iter(|| { + assert!(criterion::black_box(&line).contains(criterion::black_box(&point))); + }); + }); + group.bench_function("contains_properly multipoint (Trait)", |bencher| { + bencher.iter(|| { + assert!( + criterion::black_box(&line).contains_properly(criterion::black_box(&point)) + ); + }); + }); + group.finish(); + } + { + let mut group = c.benchmark_group("mid"); + let line = Line::new(coord! {x:0.,y:0.}, coord! {x:10.,y:10.}); + let c = coord! {x:5.,y:5.}; + let point = Point::new(5., 5.); + + group.bench_function("contains pt (Trait)", |bencher| { + bencher.iter(|| { + assert!(criterion::black_box(&line).contains(criterion::black_box(&c))); + }); + }); + group.bench_function("contains_properly pt (Trait)", |bencher| { + bencher.iter(|| { + assert!( + criterion::black_box(&line).contains_properly(criterion::black_box(&point)) + ); + }); + }); + group.finish(); + } + { + let mut group = c.benchmark_group("end"); + let line = Line::new(coord! {x:0.,y:0.}, coord! {x:10.,y:10.}); + let c = coord! {x:5.,y:5.}; + let point = Point::new(5., 5.); + + group.bench_function("contains pt (Trait)", |bencher| { + bencher.iter(|| { + assert!(criterion::black_box(&line).contains(criterion::black_box(&c))); + }); + }); + group.bench_function("contains_properly pt (Trait)", |bencher| { + bencher.iter(|| { + assert!( + criterion::black_box(&line).contains_properly(criterion::black_box(&point)) + ); + }); + }); + group.finish(); + } +} + fn compare_simple_in_complex(c: &mut Criterion) { c.bench_function( "complex polygon contains_properly polygon (Trait)", @@ -192,7 +259,12 @@ fn polygon_polygon_scaling(c: &mut Criterion) { } } -criterion_group!(benches, compare_simple_in_complex, compare_poly_in_poly,); +criterion_group!( + benches, + compare_simple_in_complex, + compare_poly_in_poly, + coord_in_line +); criterion_group!(benches_scaling, polygon_polygon_scaling); criterion_main!(benches, benches_scaling); diff --git a/geo/src/algorithm/contains_properly/geometry.rs b/geo/src/algorithm/contains_properly/geometry.rs index aabc4c8b4..c6e8f940c 100644 --- a/geo/src/algorithm/contains_properly/geometry.rs +++ b/geo/src/algorithm/contains_properly/geometry.rs @@ -26,7 +26,7 @@ where impl_contains_properly_geometry_for!(Point); impl_contains_properly_geometry_for!(MultiPoint); -impl_contains_properly_geometry_for!(Line); +// impl_contains_properly_geometry_for!(Line); impl_contains_properly_geometry_for!(LineString); impl_contains_properly_geometry_for!(MultiLineString); diff --git a/geo/src/algorithm/contains_properly/line.rs b/geo/src/algorithm/contains_properly/line.rs index 85dc3e6f1..771cd8b57 100644 --- a/geo/src/algorithm/contains_properly/line.rs +++ b/geo/src/algorithm/contains_properly/line.rs @@ -1,11 +1,34 @@ -use super::{ContainsProperly, impl_contains_properly_from_relate}; -use crate::GeoFloat; +use super::{ContainsProperly, value_in_range_exclusive}; +use crate::algorithm::kernels::Kernel; use crate::geometry::*; +use crate::{BoundingRect, CoordsIter, GeoNum, HasDimensions, Orientation}; -impl_contains_properly_from_relate!(Line, [ -Point,MultiPoint, -Line, LineString, MultiLineString, -Polygon,MultiPolygon, -GeometryCollection, -Rect,Triangle -]); +impl ContainsProperly for Line +where + T: GeoNum, + G: CoordsIter + HasDimensions + BoundingRect, +{ + fn contains_properly(&self, rhs: &G) -> bool { + if HasDimensions::is_empty(rhs) { + return false; + } + + // orient the bounds once + let x_bound = if self.start.x < self.end.x { + (self.start.x, self.end.x) + } else { + (self.end.x, self.start.x) + }; + let y_bound = if self.start.y < self.end.y { + (self.start.y, self.end.y) + } else { + (self.end.y, self.start.y) + }; + + rhs.coords_iter().all(|c| { + value_in_range_exclusive(c.x, x_bound.0, x_bound.1) + && value_in_range_exclusive(c.y, y_bound.0, y_bound.1) + && T::Ker::orient2d(self.start, self.end, c) == Orientation::Collinear + }) + } +} diff --git a/geo/src/algorithm/contains_properly/mod.rs b/geo/src/algorithm/contains_properly/mod.rs index 6dae60ec4..a4a8822cc 100644 --- a/geo/src/algorithm/contains_properly/mod.rs +++ b/geo/src/algorithm/contains_properly/mod.rs @@ -96,6 +96,16 @@ macro_rules! impl_contains_properly_geometry_for { } use impl_contains_properly_geometry_for; +// Helper function to check value lies between min and max. +// Only makes sense if min <= max (or always false) +#[inline] +fn value_in_range_exclusive(value: T, min: T, max: T) -> bool +where + T: std::cmp::PartialOrd, +{ + value > min && value < max +} + #[cfg(test)] mod test { use super::*;