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

update euclidean distance #676

Closed
wants to merge 1 commit into from
Closed
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
309 changes: 171 additions & 138 deletions src/algorithm/geo/euclidean_distance.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
use crate::algorithm::native::Binary;
use crate::array::*;
use crate::scalar::*;
use crate::trait_::GeometryArrayAccessor;
use crate::datatypes::{Dimension, GeoDataType};
use crate::error::Result;
use crate::trait_::{GeometryArrayTrait, GeometryScalarTrait};
use arrow_array::builder::Float64Builder;
use arrow_array::{Float64Array, OffsetSizeTrait};
use geo::EuclideanDistance as _EuclideanDistance;

pub trait EuclideanDistance<Rhs> {
// ┌────────────────────────────────┐
// │ Implementations for RHS arrays │
// └────────────────────────────────┘

pub trait EuclideanDistance<Rhs = Self> {
type Output;

/// Returns the distance between two geometries
///
/// If a `Point` is contained by a `Polygon`, the distance is `0.0`
Expand Down Expand Up @@ -84,7 +90,7 @@ pub trait EuclideanDistance<Rhs> {
///
/// assert_relative_eq!(distance, 1.1313708498984762);
/// ```
fn euclidean_distance(&self, rhs: &Rhs) -> Float64Array;
fn euclidean_distance(&self, rhs: &Rhs) -> Self::Output;
}

// ┌────────────────────────────────┐
Expand All @@ -93,175 +99,202 @@ pub trait EuclideanDistance<Rhs> {

// Note: this implementation is outside the macro because it is not generic over O
impl EuclideanDistance<PointArray<2>> for PointArray<2> {
/// Minimum distance between two Points
fn euclidean_distance(&self, other: &PointArray<2>) -> Float64Array {
assert_eq!(self.len(), other.len());
let mut output_array = Float64Builder::with_capacity(self.len());

self.iter_geo()
.zip(other.iter_geo())
.for_each(|(first, second)| match (first, second) {
(Some(first), Some(second)) => {
output_array.append_value(first.euclidean_distance(&second))
}
_ => output_array.append_null(),
});
type Output = Result<Float64Array>;

output_array.finish()
/// Minimum distance between two Points
fn euclidean_distance(&self, rhs: &PointArray<2>) -> Self::Output {
self.try_binary_primitive(rhs, |left, right| {
Ok(left.to_geo().euclidean_distance(&right.to_geo()))
})
}
}

/// Implementation that iterates over geo objects
macro_rules! iter_geo_impl {
($first:ty, $second:ty) => {
impl<'a, O: OffsetSizeTrait> EuclideanDistance<$second> for $first {
fn euclidean_distance(&self, other: &$second) -> Float64Array {
assert_eq!(self.len(), other.len());
let mut output_array = Float64Builder::with_capacity(self.len());

self.iter_geo()
.zip(other.iter_geo())
.for_each(|(first, second)| match (first, second) {
(Some(first), Some(second)) => {
output_array.append_value(first.euclidean_distance(&second))
}
_ => output_array.append_null(),
});
type Output = Result<Float64Array>;

output_array.finish()
fn euclidean_distance(&self, rhs: &$second) -> Self::Output {
self.try_binary_primitive(rhs, |left, right| {
Ok(left.to_geo().euclidean_distance(&right.to_geo()))
})
}
}
};
}

// Implementations on PointArray
iter_geo_impl!(PointArray<2>, LineStringArray<O, 2>);
iter_geo_impl!(PointArray<2>, PolygonArray<O, 2>);
iter_geo_impl!(PointArray<2>, MultiPointArray<O, 2>);
iter_geo_impl!(PointArray<2>, MultiLineStringArray<O, 2>);
iter_geo_impl!(PointArray<2>, MultiPolygonArray<O, 2>);
iter_geo_impl!(PointArray<2>, LineStringArray<O,2 >);
iter_geo_impl!(PointArray<2>, PolygonArray<O,2 >);
iter_geo_impl!(PointArray<2>, MultiPointArray<O,2 >);
iter_geo_impl!(PointArray<2>, MultiLineStringArray<O,2 >);
iter_geo_impl!(PointArray<2>, MultiPolygonArray<O,2 >);
iter_geo_impl!(PointArray<2>, MixedGeometryArray<O,2 >);
iter_geo_impl!(PointArray<2>, GeometryCollectionArray<O,2 >);

// Implementations on LineStringArray
iter_geo_impl!(LineStringArray<O, 2>, PointArray<2>);
iter_geo_impl!(LineStringArray<O, 2>, LineStringArray<O, 2>);
iter_geo_impl!(LineStringArray<O, 2>, PolygonArray<O, 2>);
// iter_geo_impl!(LineStringArray<O, 2>, MultiPointArray<O, 2>);
// iter_geo_impl!(LineStringArray<O, 2>, MultiLineStringArray<O, 2>);
// iter_geo_impl!(LineStringArray<O, 2>, MultiPolygonArray<O, 2>);
iter_geo_impl!(LineStringArray<O,2 >, PointArray<2>);
iter_geo_impl!(LineStringArray<O,2 >, LineStringArray<O,2 >);
iter_geo_impl!(LineStringArray<O,2 >, PolygonArray<O,2 >);
iter_geo_impl!(LineStringArray<O,2 >, MultiPointArray<O,2 >);
iter_geo_impl!(LineStringArray<O,2 >, MultiLineStringArray<O,2 >);
iter_geo_impl!(LineStringArray<O,2 >, MultiPolygonArray<O,2 >);
iter_geo_impl!(LineStringArray<O,2 >, MixedGeometryArray<O,2 >);
iter_geo_impl!(LineStringArray<O,2 >, GeometryCollectionArray<O,2 >);

// Implementations on PolygonArray
iter_geo_impl!(PolygonArray<O, 2>, PointArray<2>);
iter_geo_impl!(PolygonArray<O, 2>, LineStringArray<O, 2>);
iter_geo_impl!(PolygonArray<O, 2>, PolygonArray<O, 2>);
// iter_geo_impl!(PolygonArray<O, 2>, MultiPointArray<O, 2>);
// iter_geo_impl!(PolygonArray<O, 2>, MultiLineStringArray<O, 2>);
// iter_geo_impl!(PolygonArray<O, 2>, MultiPolygonArray<O, 2>);
iter_geo_impl!(PolygonArray<O,2 >, PointArray<2>);
iter_geo_impl!(PolygonArray<O,2 >, LineStringArray<O,2 >);
iter_geo_impl!(PolygonArray<O,2 >, PolygonArray<O,2 >);
iter_geo_impl!(PolygonArray<O,2 >, MultiPointArray<O,2 >);
iter_geo_impl!(PolygonArray<O,2 >, MultiLineStringArray<O,2 >);
iter_geo_impl!(PolygonArray<O,2 >, MultiPolygonArray<O,2 >);

// Implementations on MultiPointArray
iter_geo_impl!(MultiPointArray<O, 2>, PointArray<2>);
// iter_geo_impl!(MultiPointArray<O, 2>, LineStringArray<O, 2>);
// iter_geo_impl!(MultiPointArray<O, 2>, PolygonArray<O, 2>);
// iter_geo_impl!(MultiPointArray<O, 2>, MultiPointArray<O, 2>);
// iter_geo_impl!(MultiPointArray<O, 2>, MultiLineStringArray<O, 2>);
// iter_geo_impl!(MultiPointArray<O, 2>, MultiPolygonArray<O, 2>);
iter_geo_impl!(MultiPointArray<O,2 >, PointArray<2>);
iter_geo_impl!(MultiPointArray<O,2 >, LineStringArray<O,2 >);
iter_geo_impl!(MultiPointArray<O,2 >, PolygonArray<O,2 >);
iter_geo_impl!(MultiPointArray<O,2 >, MultiPointArray<O,2 >);
iter_geo_impl!(MultiPointArray<O,2 >, MultiLineStringArray<O,2 >);
iter_geo_impl!(MultiPointArray<O,2 >, MultiPolygonArray<O,2 >);

// Implementations on MultiLineStringArray
iter_geo_impl!(MultiLineStringArray<O, 2>, PointArray<2>);
// iter_geo_impl!(MultiLineStringArray<O, 2>, LineStringArray<O, 2>);
// iter_geo_impl!(MultiLineStringArray<O, 2>, PolygonArray<O, 2>);
// iter_geo_impl!(MultiLineStringArray<O, 2>, MultiPointArray<O, 2>);
// iter_geo_impl!(MultiLineStringArray<O, 2>, MultiLineStringArray<O, 2>);
// iter_geo_impl!(MultiLineStringArray<O, 2>, MultiPolygonArray<O, 2>);
iter_geo_impl!(MultiLineStringArray<O,2 >, PointArray<2>);
iter_geo_impl!(MultiLineStringArray<O,2 >, LineStringArray<O,2 >);
iter_geo_impl!(MultiLineStringArray<O,2 >, PolygonArray<O,2 >);
iter_geo_impl!(MultiLineStringArray<O,2 >, MultiPointArray<O,2 >);
iter_geo_impl!(MultiLineStringArray<O,2 >, MultiLineStringArray<O,2 >);
iter_geo_impl!(MultiLineStringArray<O,2 >, MultiPolygonArray<O,2 >);

// Implementations on MultiPolygonArray
iter_geo_impl!(MultiPolygonArray<O, 2>, PointArray<2>);
// iter_geo_impl!(MultiPolygonArray<O, 2>, LineStringArray<O, 2>);
// iter_geo_impl!(MultiPolygonArray<O, 2>, PolygonArray<O, 2>);
// iter_geo_impl!(MultiPolygonArray<O, 2>, MultiPointArray<O, 2>);
// iter_geo_impl!(MultiPolygonArray<O, 2>, MultiLineStringArray<O, 2>);
// iter_geo_impl!(MultiPolygonArray<O, 2>, MultiPolygonArray<O, 2>);
iter_geo_impl!(MultiPolygonArray<O,2 >, PointArray<2>);
iter_geo_impl!(MultiPolygonArray<O,2 >, LineStringArray<O,2 >);
iter_geo_impl!(MultiPolygonArray<O,2 >, PolygonArray<O,2 >);
iter_geo_impl!(MultiPolygonArray<O,2 >, MultiPointArray<O,2 >);
iter_geo_impl!(MultiPolygonArray<O,2 >, MultiLineStringArray<O,2 >);
iter_geo_impl!(MultiPolygonArray<O,2 >, MultiPolygonArray<O,2 >);

// ┌─────────────────────────────────┐
// │ Implementations for RHS scalars │
// └─────────────────────────────────┘
impl EuclideanDistance for &dyn GeometryArrayTrait {
type Output = Result<Float64Array>;

// Note: this implementation is outside the macro because it is not generic over O
impl<'a> EuclideanDistance<Point<'a, 2>> for PointArray<2> {
/// Minimum distance between two Points
fn euclidean_distance(&self, other: &Point<'a, 2>) -> Float64Array {
let mut output_array = Float64Builder::with_capacity(self.len());

self.iter_geo().for_each(|maybe_point| {
let output = maybe_point.map(|point| point.euclidean_distance(&other.to_geo()));
output_array.append_option(output)
});
fn euclidean_distance(&self, rhs: &Self) -> Self::Output {
use GeoDataType::*;
match (self.data_type(), rhs.data_type()) {
(Point(_, Dimension::XY), Point(_, Dimension::XY)) => {
self.as_point_2d().euclidean_distance(rhs.as_point_2d())
}
(Point(_, Dimension::XY), LineString(_, Dimension::XY)) => self
.as_point_2d()
.euclidean_distance(rhs.as_line_string_2d()),
(Point(_, Dimension::XY), LargeLineString(_, Dimension::XY)) => self
.as_point_2d()
.euclidean_distance(rhs.as_line_string_2d()),
(Point(_, Dimension::XY), Polygon(_, Dimension::XY)) => {
self.as_point_2d().euclidean_distance(rhs.as_polygon_2d())
}
(Point(_, Dimension::XY), MultiPoint(_, Dimension::XY)) => self
.as_point_2d()
.euclidean_distance(rhs.as_multi_point_2d()),
(Point(_, Dimension::XY), MultiLineString(_, Dimension::XY)) => self
.as_point_2d()
.euclidean_distance(rhs.as_multi_line_string_2d()),
(Point(_, Dimension::XY), MultiPolygon(_, Dimension::XY)) => self
.as_point_2d()
.euclidean_distance(rhs.as_multi_polygon_2d()),
(Point(_, Dimension::XY), Mixed(_, Dimension::XY)) => {
self.as_point_2d().euclidean_distance(rhs.as_mixed_2d())
}
(Point(_, Dimension::XY), GeometryCollection(_, Dimension::XY)) => self
.as_point_2d()
.euclidean_distance(rhs.as_geometry_collection_2d()),

output_array.finish()
_ => todo!(),
}
}
}

/// Implementation that iterates over geo objects
macro_rules! iter_geo_impl_scalar {
($first:ty, $second:ty) => {
impl<'a, O: OffsetSizeTrait> EuclideanDistance<$second> for $first {
fn euclidean_distance(&self, other: &$second) -> Float64Array {
let mut output_array = Float64Builder::with_capacity(self.len());
let other_geo = other.to_geo();
// // ┌─────────────────────────────────┐
// // │ Implementations for RHS scalars │
// // └─────────────────────────────────┘

self.iter_geo().for_each(|maybe_geom| {
let output = maybe_geom.map(|geom| geom.euclidean_distance(&other_geo));
output_array.append_option(output)
});
// // Note: this implementation is outside the macro because it is not generic over O
// impl<'a> EuclideanDistance<Point<'a>> for PointArray {
// /// Minimum distance between two Points
// fn euclidean_distance(&self, other: &Point<'a>) -> Float64Array {
// let mut output_array = Float64Builder::with_capacity(self.len());

output_array.finish()
}
}
};
}
// self.iter_geo().for_each(|maybe_point| {
// let output = maybe_point.map(|point| point.euclidean_distance(&other.to_geo()));
// output_array.append_option(output)
// });

// Implementations on PointArray
iter_geo_impl_scalar!(PointArray<2>, LineString<'a, O, 2>);
iter_geo_impl_scalar!(PointArray<2>, Polygon<'a, O, 2>);
iter_geo_impl_scalar!(PointArray<2>, MultiPoint<'a, O, 2>);
iter_geo_impl_scalar!(PointArray<2>, MultiLineString<'a, O, 2>);
iter_geo_impl_scalar!(PointArray<2>, MultiPolygon<'a, O, 2>);
// output_array.finish()
// }
// }

// Implementations on LineStringArray
iter_geo_impl_scalar!(LineStringArray<O, 2>, Point<'a, 2>);
iter_geo_impl_scalar!(LineStringArray<O, 2>, LineString<'a, O, 2>);
iter_geo_impl_scalar!(LineStringArray<O, 2>, Polygon<'a, O, 2>);
// iter_geo_impl_scalar!(LineStringArray<O, 2>, MultiPoint<'a, O, 2>);
// iter_geo_impl_scalar!(LineStringArray<O, 2>, MultiLineString<'a, O, 2>);
// iter_geo_impl_scalar!(LineStringArray<O, 2>, MultiPolygon<'a, O, 2>);
// /// Implementation that iterates over geo objects
// macro_rules! iter_geo_impl_scalar {
// ($first:ty, $second:ty) => {
// impl<'a, O: OffsetSizeTrait> EuclideanDistance<$second> for $first {
// fn euclidean_distance(&self, other: &$second) -> Float64Array {
// let mut output_array = Float64Builder::with_capacity(self.len());
// let other_geo = other.to_geo();

// Implementations on PolygonArray
iter_geo_impl_scalar!(PolygonArray<O, 2>, Point<'a, 2>);
iter_geo_impl_scalar!(PolygonArray<O, 2>, LineString<'a, O, 2>);
iter_geo_impl_scalar!(PolygonArray<O, 2>, Polygon<'a, O, 2>);
// iter_geo_impl_scalar!(PolygonArray<O, 2>, MultiPoint<'a, O, 2>);
// iter_geo_impl_scalar!(PolygonArray<O, 2>, MultiLineString<'a, O, 2>);
// iter_geo_impl_scalar!(PolygonArray<O, 2>, MultiPolygon<'a, O, 2>);
// self.iter_geo().for_each(|maybe_geom| {
// let output = maybe_geom.map(|geom| geom.euclidean_distance(&other_geo));
// output_array.append_option(output)
// });

// Implementations on MultiPointArray
iter_geo_impl_scalar!(MultiPointArray<O, 2>, Point<'a, 2>);
// iter_geo_impl_scalar!(MultiPointArray<O, 2>, LineString<'a, O, 2>);
// iter_geo_impl_scalar!(MultiPointArray<O, 2>, Polygon<'a, O, 2>);
// iter_geo_impl_scalar!(MultiPointArray<O, 2>, MultiPoint<'a, O, 2>);
// iter_geo_impl_scalar!(MultiPointArray<O, 2>, MultiLineString<'a, O, 2>);
// iter_geo_impl_scalar!(MultiPointArray<O, 2>, MultiPolygon<'a, O, 2>);
// output_array.finish()
// }
// }
// };
// }

// Implementations on MultiLineStringArray
iter_geo_impl_scalar!(MultiLineStringArray<O, 2>, Point<'a, 2>);
// iter_geo_impl_scalar!(MultiLineStringArray<O, 2>, LineString<'a, O, 2>);
// iter_geo_impl_scalar!(MultiLineStringArray<O, 2>, Polygon<'a, O, 2>);
// iter_geo_impl_scalar!(MultiLineStringArray<O, 2>, MultiPoint<'a, O, 2>);
// iter_geo_impl_scalar!(MultiLineStringArray<O, 2>, MultiLineString<'a, O, 2>);
// iter_geo_impl_scalar!(MultiLineStringArray<O, 2>, MultiPolygon<'a, O, 2>);
// // Implementations on PointArray
// iter_geo_impl_scalar!(PointArray, LineString<'a, O>);
// iter_geo_impl_scalar!(PointArray, Polygon<'a, O>);
// iter_geo_impl_scalar!(PointArray, MultiPoint<'a, O>);
// iter_geo_impl_scalar!(PointArray, MultiLineString<'a, O>);
// iter_geo_impl_scalar!(PointArray, MultiPolygon<'a, O>);

// Implementations on MultiPolygonArray
iter_geo_impl_scalar!(MultiPolygonArray<O, 2>, Point<'a, 2>);
// iter_geo_impl_scalar!(MultiPolygonArray<O, 2>, LineString<'a, O, 2>);
// iter_geo_impl_scalar!(MultiPolygonArray<O, 2>, Polygon<'a, O, 2>);
// iter_geo_impl_scalar!(MultiPolygonArray<O, 2>, MultiPoint<'a, O, 2>);
// iter_geo_impl_scalar!(MultiPolygonArray<O, 2>, MultiLineString<'a, O, 2>);
// iter_geo_impl_scalar!(MultiPolygonArray<O, 2>, MultiPolygon<'a, O, 2>);
// // Implementations on LineStringArray
// iter_geo_impl_scalar!(LineStringArray<O>, Point<'a>);
// iter_geo_impl_scalar!(LineStringArray<O>, LineString<'a, O>);
// iter_geo_impl_scalar!(LineStringArray<O>, Polygon<'a, O>);
// // iter_geo_impl_scalar!(LineStringArray<O>, MultiPoint<'a, O>);
// // iter_geo_impl_scalar!(LineStringArray<O>, MultiLineString<'a, O>);
// // iter_geo_impl_scalar!(LineStringArray<O>, MultiPolygon<'a, O>);

// // Implementations on PolygonArray
// iter_geo_impl_scalar!(PolygonArray<O>, Point<'a>);
// iter_geo_impl_scalar!(PolygonArray<O>, LineString<'a, O>);
// iter_geo_impl_scalar!(PolygonArray<O>, Polygon<'a, O>);
// // iter_geo_impl_scalar!(PolygonArray<O>, MultiPoint<'a, O>);
// // iter_geo_impl_scalar!(PolygonArray<O>, MultiLineString<'a, O>);
// // iter_geo_impl_scalar!(PolygonArray<O>, MultiPolygon<'a, O>);

// // Implementations on MultiPointArray
// iter_geo_impl_scalar!(MultiPointArray<O>, Point<'a>);
// // iter_geo_impl_scalar!(MultiPointArray<O>, LineString<'a, O>);
// // iter_geo_impl_scalar!(MultiPointArray<O>, Polygon<'a, O>);
// // iter_geo_impl_scalar!(MultiPointArray<O>, MultiPoint<'a, O>);
// // iter_geo_impl_scalar!(MultiPointArray<O>, MultiLineString<'a, O>);
// // iter_geo_impl_scalar!(MultiPointArray<O>, MultiPolygon<'a, O>);

// // Implementations on MultiLineStringArray
// iter_geo_impl_scalar!(MultiLineStringArray<O>, Point<'a>);
// // iter_geo_impl_scalar!(MultiLineStringArray<O>, LineString<'a, O>);
// // iter_geo_impl_scalar!(MultiLineStringArray<O>, Polygon<'a, O>);
// // iter_geo_impl_scalar!(MultiLineStringArray<O>, MultiPoint<'a, O>);
// // iter_geo_impl_scalar!(MultiLineStringArray<O>, MultiLineString<'a, O>);
// // iter_geo_impl_scalar!(MultiLineStringArray<O>, MultiPolygon<'a, O>);

// // Implementations on MultiPolygonArray
// iter_geo_impl_scalar!(MultiPolygonArray<O>, Point<'a>);
// // iter_geo_impl_scalar!(MultiPolygonArray<O>, LineString<'a, O>);
// // iter_geo_impl_scalar!(MultiPolygonArray<O>, Polygon<'a, O>);
// // iter_geo_impl_scalar!(MultiPolygonArray<O>, MultiPoint<'a, O>);
// // iter_geo_impl_scalar!(MultiPolygonArray<O>, MultiLineString<'a, O>);
// // iter_geo_impl_scalar!(MultiPolygonArray<O>, MultiPolygon<'a, O>);
Loading