diff --git a/geo/src/algorithm/euclidean_distance.rs b/geo/src/algorithm/euclidean_distance.rs index fad521bb7..8748d26be 100644 --- a/geo/src/algorithm/euclidean_distance.rs +++ b/geo/src/algorithm/euclidean_distance.rs @@ -397,59 +397,57 @@ where } } -// ┌─────────────────────────────┐ -// │ Shared implementations │ -// └─────────────────────────────┘ +// ┌────────────────────────────────────────┐ +// │ Implementations for Rect and Triangle │ +// └────────────────────────────────────────┘ -/// Implements EuclideanDistance between Geometry and specific geometry types -/// by using the Geometry's inner type's implementation. -macro_rules! impl_euclidean_distance_to_geometry { - ([$($for:ty),*]) => { +/// Implements Euclidean distance for Triangles and Rects by converting them to polygons. +macro_rules! impl_euclidean_distance_for_polygonlike_geometry { + ($for:ty, [$($target:ty),*]) => { $( - impl EuclideanDistance> for $for + impl EuclideanDistance for $for where - T: GeoFloat + FloatConst + RTreeNum + FloatConst, + T: GeoFloat + Signed + RTreeNum + FloatConst, { - fn euclidean_distance(&self, geom: &Geometry) -> T { - match geom { - Geometry::Point(p) => self.euclidean_distance(p), - Geometry::Line(l) => self.euclidean_distance(l), - Geometry::LineString(ls) => self.euclidean_distance(ls), - Geometry::Polygon(p) => self.euclidean_distance(p), - Geometry::MultiPoint(mp) => self.euclidean_distance(mp), - Geometry::MultiLineString(mls) => self.euclidean_distance(mls), - Geometry::MultiPolygon(mp) => self.euclidean_distance(mp), - Geometry::GeometryCollection(gc) => self.euclidean_distance(gc), - Geometry::Rect(r) => self.euclidean_distance(r), - Geometry::Triangle(t) => self.euclidean_distance(t), - } + fn euclidean_distance(&self, other: &$target) -> T { + other.euclidean_distance(&self.to_polygon()) } } + )* + }; +} - impl EuclideanDistance for Geometry +impl_euclidean_distance_for_polygonlike_geometry!(Triangle, [Point, MultiPoint, Line, LineString, MultiLineString, Polygon, MultiPolygon, GeometryCollection, Rect, Triangle]); +impl_euclidean_distance_for_polygonlike_geometry!(Rect, [Point, MultiPoint, Line, LineString, MultiLineString, Polygon, MultiPolygon, GeometryCollection, Rect, Triangle]); + +/// Implements Euclidean distance for other geometry types to Triangles and Rects by converting the Triangle or Rect to a polygon. +macro_rules! impl_euclidean_distance_to_polygonlike_geometry { + ($for:ty, [$($target:ty),*]) => { + $( + impl EuclideanDistance for $for where - T: GeoFloat + FloatConst + RTreeNum + FloatConst, + T: GeoFloat + Signed + RTreeNum + FloatConst, { - fn euclidean_distance(&self, other: &$for) -> T { - match self { - Geometry::Point(p) => p.euclidean_distance(other), - Geometry::Line(l) => l.euclidean_distance(other), - Geometry::LineString(ls) => ls.euclidean_distance(other), - Geometry::Polygon(p) => p.euclidean_distance(other), - Geometry::MultiPoint(mp) => mp.euclidean_distance(other), - Geometry::MultiLineString(mls) => mls.euclidean_distance(other), - Geometry::MultiPolygon(mp) => mp.euclidean_distance(other), - Geometry::GeometryCollection(gc) => gc.euclidean_distance(other), - Geometry::Rect(r) => r.euclidean_distance(other), - Geometry::Triangle(t) => t.euclidean_distance(other), - } + fn euclidean_distance(&self, other: &$target) -> T { + other.to_polygon().euclidean_distance(self) } } )* }; } -impl_euclidean_distance_to_geometry!([Point, Line, LineString, Polygon, MultiPolygon, Triangle, Rect, GeometryCollection]); +impl_euclidean_distance_to_polygonlike_geometry!(Point, [Rect, Triangle]); +impl_euclidean_distance_to_polygonlike_geometry!(MultiPoint, [Rect, Triangle]); +impl_euclidean_distance_to_polygonlike_geometry!(Line, [Rect, Triangle]); +impl_euclidean_distance_to_polygonlike_geometry!(LineString, [Rect, Triangle]); +impl_euclidean_distance_to_polygonlike_geometry!(MultiLineString, [Rect, Triangle]); +impl_euclidean_distance_to_polygonlike_geometry!(Polygon, [Rect, Triangle]); +impl_euclidean_distance_to_polygonlike_geometry!(MultiPolygon, [Rect, Triangle]); +impl_euclidean_distance_to_polygonlike_geometry!(GeometryCollection, [Rect, Triangle]); + +// ┌───────────────────────────────────────────┐ +// │ Implementations for multi geometry types │ +// └───────────────────────────────────────────┘ /// Euclidean distance implementation for multi geometry types. macro_rules! impl_euclidean_distance_for_iter_geometry { @@ -457,7 +455,7 @@ macro_rules! impl_euclidean_distance_for_iter_geometry { $( impl EuclideanDistance for $for where - T: GeoFloat + FloatConst + RTreeNum + FloatConst, + T: GeoFloat + FloatConst + RTreeNum, { fn euclidean_distance(&self, target: &$target) -> T { self @@ -466,179 +464,100 @@ macro_rules! impl_euclidean_distance_for_iter_geometry { .fold(::max_value(), |accum, val| accum.min(val)) } } - - impl EuclideanDistance for $target - where - T: GeoFloat + FloatConst + RTreeNum + FloatConst, - { - fn euclidean_distance(&self, other: &$for) -> T { - other.euclidean_distance(self) - } - } )* }; - ($for:ty) => { - impl EuclideanDistance for $for - where - T: GeoFloat + FloatConst + RTreeNum + FloatConst, - { - fn euclidean_distance(&self, other: &$for) -> T { - self - .iter() - .map(|g| g.euclidean_distance(other)) - .fold(::max_value(), |accum, val| accum.min(val)) - } - } - }; } -impl_euclidean_distance_for_iter_geometry!(MultiPoint, [Point, Line, LineString, MultiLineString, Polygon, MultiPolygon, GeometryCollection]); -impl_euclidean_distance_for_iter_geometry!(MultiLineString, [Point, Line, LineString, Polygon, MultiPolygon, GeometryCollection]); -impl_euclidean_distance_for_iter_geometry!(MultiPolygon, [Point, Line, LineString, Polygon, GeometryCollection]); -impl_euclidean_distance_for_iter_geometry!(GeometryCollection, [Point, Line, LineString, Polygon]); -impl_euclidean_distance_for_iter_geometry!(MultiPoint); -impl_euclidean_distance_for_iter_geometry!(MultiLineString); -impl_euclidean_distance_for_iter_geometry!(MultiPolygon); -impl_euclidean_distance_for_iter_geometry!(GeometryCollection); +impl_euclidean_distance_for_iter_geometry!(MultiPoint, [Point, MultiPoint, Line, LineString, MultiLineString, Polygon, MultiPolygon, GeometryCollection]); +impl_euclidean_distance_for_iter_geometry!(MultiLineString, [Point, MultiPoint, Line, LineString, MultiLineString, Polygon, MultiPolygon, GeometryCollection]); +impl_euclidean_distance_for_iter_geometry!(MultiPolygon, [Point, MultiPoint, Line, LineString, MultiLineString, Polygon, MultiPolygon, GeometryCollection]); +impl_euclidean_distance_for_iter_geometry!(GeometryCollection, [Point, MultiPoint, Line, LineString, MultiLineString, Polygon, MultiPolygon, GeometryCollection]); -/// Implements Euclidean distance for Triangles and Rects by converting them to polygons. -macro_rules! impl_euclidean_distance_for_polygonlike_geometry { +/// Euclidean distance implementation for other geometry types to multi geometry types, +/// using the multi geometry type's implementation. +macro_rules! impl_euclidean_distance_from_iter_geometry { ($for:ty, [$($target:ty),*]) => { $( - impl EuclideanDistance for $for - where - T: GeoFloat + Signed + RTreeNum + FloatConst, - { - fn euclidean_distance(&self, other: &$target) -> T { - other.euclidean_distance(&self.to_polygon()) - } + impl EuclideanDistance for $for + where + T: GeoFloat + FloatConst + RTreeNum + { + fn euclidean_distance(&self, target: &$target) -> T { + target.euclidean_distance(self) } + } + )* + }; +} - impl EuclideanDistance for $target +// This macro is used to implement EuclideanDistance to multi geometry types for non-multi geometry types. +// Rect and Triangle are omitted here because those implementations are included in the Rect and Triangle section above. +impl_euclidean_distance_from_iter_geometry!(Point, [MultiPoint, MultiLineString, MultiPolygon, GeometryCollection]); +impl_euclidean_distance_from_iter_geometry!(Line, [MultiPoint, MultiLineString, MultiPolygon, GeometryCollection]); +impl_euclidean_distance_from_iter_geometry!(LineString, [MultiPoint, MultiLineString, MultiPolygon, GeometryCollection]); +impl_euclidean_distance_from_iter_geometry!(Polygon, [MultiPoint, MultiLineString, MultiPolygon, GeometryCollection]); + +// ┌─────────────────────────────────────────────────────────┐ +// │ Implementation to Geometry for every geometry type │ +// └─────────────────────────────────────────────────────────┘ + +/// Euclidean distance implementation for every specific Geometry type to Geometry. +macro_rules! impl_euclidean_distance_to_geometry_for_specific { + ([$($for:ty),*]) => { + $( + impl EuclideanDistance> for $for where - T: GeoFloat + Signed + RTreeNum + FloatConst, + T: GeoFloat + FloatConst + RTreeNum, { - fn euclidean_distance(&self, other: &$for) -> T { - self.euclidean_distance(&other.to_polygon()) + fn euclidean_distance(&self, geom: &Geometry) -> T { + match geom { + Geometry::Point(p) => self.euclidean_distance(p), + Geometry::Line(l) => self.euclidean_distance(l), + Geometry::LineString(ls) => self.euclidean_distance(ls), + Geometry::Polygon(p) => self.euclidean_distance(p), + Geometry::MultiPoint(mp) => self.euclidean_distance(mp), + Geometry::MultiLineString(mls) => self.euclidean_distance(mls), + Geometry::MultiPolygon(mp) => self.euclidean_distance(mp), + Geometry::GeometryCollection(gc) => self.euclidean_distance(gc), + Geometry::Rect(r) => self.euclidean_distance(r), + Geometry::Triangle(t) => self.euclidean_distance(t), + } } } )* }; - ($for:ty) => { - impl EuclideanDistance for $for - where - T: GeoFloat + FloatConst + RTreeNum + FloatConst, - { - fn euclidean_distance(&self, other: &$for) -> T { - other.euclidean_distance(&self.to_polygon()) - } - } - }; } -impl_euclidean_distance_for_polygonlike_geometry!(Triangle, [Point, MultiPoint, Line, LineString, MultiLineString, Polygon, MultiPolygon, GeometryCollection, Rect]); -impl_euclidean_distance_for_polygonlike_geometry!(Rect, [Point, MultiPoint, Line, LineString, MultiLineString, Polygon, MultiPolygon, GeometryCollection]); -impl_euclidean_distance_for_polygonlike_geometry!(Triangle); -impl_euclidean_distance_for_polygonlike_geometry!(Rect); +impl_euclidean_distance_to_geometry_for_specific!([Point, MultiPoint, Line, LineString, MultiLineString, Polygon, MultiPolygon, Triangle, Rect, GeometryCollection]); // ┌──────────────────────────────┐ // │ Implementation for Geometry │ // └──────────────────────────────┘ +/// Euclidean distance implementation for Geometry to every specific Geometry type. +macro_rules! impl_euclidean_distance_to_specific_for_geometry { + ([$($for:ty),*]) => { + $( + impl EuclideanDistance for Geometry + where + T: GeoFloat + FloatConst + RTreeNum + { + crate::geometry_delegate_impl! { + fn euclidean_distance(&self, other: &$for) -> T; + } + } + )* + }; +} + +impl_euclidean_distance_to_specific_for_geometry!([Point, MultiPoint, Line, LineString, MultiLineString, Polygon, MultiPolygon, Triangle, Rect, GeometryCollection]); + impl EuclideanDistance for Geometry where T: GeoFloat + FloatConst, { - fn euclidean_distance(&self, other: &Geometry) -> T { - match (self, other) { - (Geometry::GeometryCollection(a), b) | (b, Geometry::GeometryCollection(a)) => { - a.euclidean_distance(b) - } - (Geometry::Point(a), Geometry::Point(b)) => a.euclidean_distance(b), - (Geometry::Point(a), Geometry::Line(b)) | (Geometry::Line(b), Geometry::Point(a)) => { - a.euclidean_distance(b) - } - (Geometry::Point(a), Geometry::LineString(b)) - | (Geometry::LineString(b), Geometry::Point(a)) => a.euclidean_distance(b), - (Geometry::Point(a), Geometry::Polygon(b)) - | (Geometry::Polygon(b), Geometry::Point(a)) => a.euclidean_distance(b), - (Geometry::Point(a), Geometry::MultiPoint(b)) - | (Geometry::MultiPoint(b), Geometry::Point(a)) => a.euclidean_distance(b), - (Geometry::Point(a), Geometry::MultiLineString(b)) - | (Geometry::MultiLineString(b), Geometry::Point(a)) => a.euclidean_distance(b), - (Geometry::Point(a), Geometry::MultiPolygon(b)) - | (Geometry::MultiPolygon(b), Geometry::Point(a)) => a.euclidean_distance(b), - (Geometry::Point(a), Geometry::Rect(b)) | (Geometry::Rect(b), Geometry::Point(a)) => { - a.euclidean_distance(b) - } - (Geometry::Point(a), Geometry::Triangle(b)) - | (Geometry::Triangle(b), Geometry::Point(a)) => a.euclidean_distance(b), - (Geometry::Line(a), Geometry::Line(b)) => a.euclidean_distance(b), - (Geometry::Line(a), Geometry::LineString(b)) - | (Geometry::LineString(b), Geometry::Line(a)) => a.euclidean_distance(b), - (Geometry::Line(a), Geometry::Polygon(b)) - | (Geometry::Polygon(b), Geometry::Line(a)) => a.euclidean_distance(b), - (Geometry::Line(a), Geometry::MultiPoint(b)) - | (Geometry::MultiPoint(b), Geometry::Line(a)) => a.euclidean_distance(b), - (Geometry::Line(a), Geometry::MultiLineString(b)) - | (Geometry::MultiLineString(b), Geometry::Line(a)) => a.euclidean_distance(b), - (Geometry::Line(a), Geometry::MultiPolygon(b)) - | (Geometry::MultiPolygon(b), Geometry::Line(a)) => a.euclidean_distance(b), - (Geometry::Line(a), Geometry::Rect(b)) | (Geometry::Rect(b), Geometry::Line(a)) => { - a.euclidean_distance(b) - } - (Geometry::Line(a), Geometry::Triangle(b)) - | (Geometry::Triangle(b), Geometry::Line(a)) => a.euclidean_distance(b), - (Geometry::LineString(a), Geometry::LineString(b)) => a.euclidean_distance(b), - (Geometry::LineString(a), Geometry::Polygon(b)) - | (Geometry::Polygon(b), Geometry::LineString(a)) => a.euclidean_distance(b), - (Geometry::LineString(a), Geometry::MultiPoint(b)) - | (Geometry::MultiPoint(b), Geometry::LineString(a)) => a.euclidean_distance(b), - (Geometry::LineString(a), Geometry::MultiLineString(b)) - | (Geometry::MultiLineString(b), Geometry::LineString(a)) => a.euclidean_distance(b), - (Geometry::LineString(a), Geometry::MultiPolygon(b)) - | (Geometry::MultiPolygon(b), Geometry::LineString(a)) => a.euclidean_distance(b), - (Geometry::LineString(a), Geometry::Rect(b)) - | (Geometry::Rect(b), Geometry::LineString(a)) => a.euclidean_distance(b), - (Geometry::LineString(a), Geometry::Triangle(b)) - | (Geometry::Triangle(b), Geometry::LineString(a)) => a.euclidean_distance(b), - (Geometry::Polygon(a), Geometry::Polygon(b)) => a.euclidean_distance(b), - (Geometry::Polygon(a), Geometry::MultiPoint(b)) - | (Geometry::MultiPoint(b), Geometry::Polygon(a)) => a.euclidean_distance(b), - (Geometry::Polygon(a), Geometry::MultiLineString(b)) - | (Geometry::MultiLineString(b), Geometry::Polygon(a)) => a.euclidean_distance(b), - (Geometry::Polygon(a), Geometry::MultiPolygon(b)) - | (Geometry::MultiPolygon(b), Geometry::Polygon(a)) => a.euclidean_distance(b), - (Geometry::Polygon(a), Geometry::Rect(b)) - | (Geometry::Rect(b), Geometry::Polygon(a)) => a.euclidean_distance(b), - (Geometry::Polygon(a), Geometry::Triangle(b)) - | (Geometry::Triangle(b), Geometry::Polygon(a)) => a.euclidean_distance(b), - (Geometry::MultiPoint(a), Geometry::MultiPoint(b)) => a.euclidean_distance(b), - (Geometry::MultiPoint(a), Geometry::MultiLineString(b)) - | (Geometry::MultiLineString(b), Geometry::MultiPoint(a)) => a.euclidean_distance(b), - (Geometry::MultiPoint(a), Geometry::MultiPolygon(b)) - | (Geometry::MultiPolygon(b), Geometry::MultiPoint(a)) => a.euclidean_distance(b), - (Geometry::MultiPoint(a), Geometry::Rect(b)) - | (Geometry::Rect(b), Geometry::MultiPoint(a)) => a.euclidean_distance(b), - (Geometry::MultiPoint(a), Geometry::Triangle(b)) - | (Geometry::Triangle(b), Geometry::MultiPoint(a)) => a.euclidean_distance(b), - (Geometry::MultiLineString(a), Geometry::MultiLineString(b)) => a.euclidean_distance(b), - (Geometry::MultiLineString(a), Geometry::MultiPolygon(b)) - | (Geometry::MultiPolygon(b), Geometry::MultiLineString(a)) => a.euclidean_distance(b), - (Geometry::MultiLineString(a), Geometry::Rect(b)) - | (Geometry::Rect(b), Geometry::MultiLineString(a)) => a.euclidean_distance(b), - (Geometry::MultiLineString(a), Geometry::Triangle(b)) - | (Geometry::Triangle(b), Geometry::MultiLineString(a)) => a.euclidean_distance(b), - (Geometry::MultiPolygon(a), Geometry::MultiPolygon(b)) => a.euclidean_distance(b), - (Geometry::MultiPolygon(a), Geometry::Rect(b)) - | (Geometry::Rect(b), Geometry::MultiPolygon(a)) => a.euclidean_distance(b), - (Geometry::MultiPolygon(a), Geometry::Triangle(b)) - | (Geometry::Triangle(b), Geometry::MultiPolygon(a)) => a.euclidean_distance(b), - (Geometry::Rect(a), Geometry::Rect(b)) => a.euclidean_distance(b), - (Geometry::Rect(a), Geometry::Triangle(b)) - | (Geometry::Triangle(b), Geometry::Rect(a)) => a.euclidean_distance(b), - (Geometry::Triangle(a), Geometry::Triangle(b)) => a.euclidean_distance(b), - } + crate::geometry_delegate_impl! { + fn euclidean_distance(&self, other: &Geometry) -> T; } }