From 318c6b985e0fe2fbbf85577c84aef7f79f6a59b4 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Mon, 9 Dec 2024 22:04:54 -0500 Subject: [PATCH 1/2] Implement geos bool ops --- rust/geoarrow/src/algorithm/geos/bool_ops.rs | 149 ++++++++++++++++++ rust/geoarrow/src/algorithm/geos/mod.rs | 2 + rust/geoarrow/src/algorithm/native/binary.rs | 40 ++++- rust/geoarrow/src/algorithm/native/unary.rs | 33 +++- .../src/io/geos/scalar/coord/combined.rs | 68 +++++--- rust/geoarrow/src/io/geos/scalar/coord/mod.rs | 14 ++ rust/geoarrow/src/io/geos/scalar/geometry.rs | 26 +++ .../src/io/geos/scalar/geometrycollection.rs | 18 ++- .../geoarrow/src/io/geos/scalar/linestring.rs | 18 ++- rust/geoarrow/src/io/geos/scalar/mod.rs | 1 + .../src/io/geos/scalar/multilinestring.rs | 20 ++- .../geoarrow/src/io/geos/scalar/multipoint.rs | 19 ++- .../src/io/geos/scalar/multipolygon.rs | 19 ++- rust/geoarrow/src/io/geos/scalar/point.rs | 20 ++- rust/geoarrow/src/io/geos/scalar/polygon.rs | 27 ++-- 15 files changed, 407 insertions(+), 67 deletions(-) create mode 100644 rust/geoarrow/src/algorithm/geos/bool_ops.rs diff --git a/rust/geoarrow/src/algorithm/geos/bool_ops.rs b/rust/geoarrow/src/algorithm/geos/bool_ops.rs new file mode 100644 index 00000000..e461d9d7 --- /dev/null +++ b/rust/geoarrow/src/algorithm/geos/bool_ops.rs @@ -0,0 +1,149 @@ +use arrow_array::BooleanArray; +use geo_traits::GeometryTrait; +use geos::Geom; + +use crate::algorithm::native::{Binary, Unary}; +use crate::array::GeometryArray; +use crate::error::{GeoArrowError, Result}; +use crate::io::geos::scalar::{to_geos_geometry, GEOSGeometry}; +use crate::trait_::NativeScalar; + +pub trait BooleanOps { + fn intersects(&self, rhs: &Rhs) -> Result; + fn crosses(&self, rhs: &Rhs) -> Result; + fn disjoint(&self, rhs: &Rhs) -> Result; + fn touches(&self, rhs: &Rhs) -> Result; + fn overlaps(&self, rhs: &Rhs) -> Result; + fn within(&self, rhs: &Rhs) -> Result; + fn equals(&self, rhs: &Rhs) -> Result; + fn equals_exact(&self, rhs: &Rhs, precision: f64) -> Result; + fn covers(&self, rhs: &Rhs) -> Result; + fn covered_by(&self, rhs: &Rhs) -> Result; + fn contains(&self, rhs: &Rhs) -> Result; + + fn difference(&self, rhs: &Rhs) -> Result; + fn sym_difference(&self, rhs: &Rhs) -> Result; + fn union(&self, rhs: &Rhs) -> Result; + fn intersection(&self, rhs: &Rhs) -> Result; +} + +macro_rules! impl_method { + ($method_name:ident) => { + fn $method_name(&self, rhs: &GeometryArray) -> Result { + self.try_binary_boolean(rhs, |left, right| { + Ok(left.to_geos()?.$method_name(&right.to_geos()?)?) + }) + } + }; +} + +macro_rules! impl_method_geometry { + ($method_name:ident) => { + fn $method_name(&self, rhs: &GeometryArray) -> Result { + self.try_binary_geometry( + rhs, + |left, right| { + let left = to_geos_geometry(&left)?; + let right = to_geos_geometry(&right)?; + let out = left.difference(&right)?; + Ok(GEOSGeometry::new(out)) + }, + false, + ) + } + }; +} + +impl BooleanOps for GeometryArray { + impl_method!(intersects); + impl_method!(crosses); + impl_method!(disjoint); + impl_method!(touches); + impl_method!(overlaps); + impl_method!(within); + impl_method!(equals); + impl_method!(covers); + impl_method!(covered_by); + impl_method!(contains); + + fn equals_exact(&self, rhs: &GeometryArray, precision: f64) -> Result { + self.try_binary_boolean(rhs, |left, right| { + Ok(left.to_geos()?.equals_exact(&right.to_geos()?, precision)?) + }) + } + + impl_method_geometry!(difference); + impl_method_geometry!(sym_difference); + impl_method_geometry!(union); + impl_method_geometry!(intersection); +} + +pub trait BooleanOpsScalar { + fn intersects(&self, rhs: &Rhs) -> Result; + fn crosses(&self, rhs: &Rhs) -> Result; + fn disjoint(&self, rhs: &Rhs) -> Result; + fn touches(&self, rhs: &Rhs) -> Result; + fn overlaps(&self, rhs: &Rhs) -> Result; + fn within(&self, rhs: &Rhs) -> Result; + fn equals(&self, rhs: &Rhs) -> Result; + fn equals_exact(&self, rhs: &Rhs, precision: f64) -> Result; + fn covers(&self, rhs: &Rhs) -> Result; + fn covered_by(&self, rhs: &Rhs) -> Result; + fn contains(&self, rhs: &Rhs) -> Result; + + fn difference(&self, rhs: &Rhs) -> Result; + fn sym_difference(&self, rhs: &Rhs) -> Result; + fn union(&self, rhs: &Rhs) -> Result; + fn intersection(&self, rhs: &Rhs) -> Result; +} + +macro_rules! impl_method_scalar { + ($method_name:ident) => { + fn $method_name(&self, rhs: &G) -> Result { + let rhs = to_geos_geometry(rhs)?; + self.try_unary_boolean::<_, GeoArrowError>(|geom| { + Ok(geom.to_geos()?.$method_name(&rhs)?) + }) + } + }; +} + +macro_rules! impl_method_geometry_scalar { + ($method_name:ident) => { + fn $method_name(&self, rhs: &G) -> Result { + let rhs = to_geos_geometry(rhs)?; + self.try_unary_geometry( + |geom| { + let geom = to_geos_geometry(&geom)?; + let out = geom.$method_name(&rhs)?; + Ok(GEOSGeometry::new(out)) + }, + false, + ) + } + }; +} +impl> BooleanOpsScalar for GeometryArray { + impl_method_scalar!(intersects); + impl_method_scalar!(crosses); + impl_method_scalar!(disjoint); + impl_method_scalar!(touches); + impl_method_scalar!(overlaps); + impl_method_scalar!(within); + impl_method_scalar!(equals); + impl_method_scalar!(covers); + impl_method_scalar!(covered_by); + impl_method_scalar!(contains); + + fn equals_exact(&self, rhs: &G, precision: f64) -> Result { + let rhs = to_geos_geometry(rhs)?; + self.try_unary_boolean::<_, GeoArrowError>(|geom| { + Ok(geom.to_geos()?.equals_exact(&rhs, precision)?) + }) + } + + impl_method_geometry_scalar!(difference); + impl_method_geometry_scalar!(sym_difference); + impl_method_geometry_scalar!(union); + impl_method_geometry_scalar!(intersection); +} diff --git a/rust/geoarrow/src/algorithm/geos/mod.rs b/rust/geoarrow/src/algorithm/geos/mod.rs index 036e6726..973c6fb0 100644 --- a/rust/geoarrow/src/algorithm/geos/mod.rs +++ b/rust/geoarrow/src/algorithm/geos/mod.rs @@ -1,6 +1,7 @@ //! Bindings to the [`geos`] crate for geometry operations. mod area; +mod bool_ops; mod buffer; mod is_empty; mod is_ring; @@ -10,6 +11,7 @@ mod length; mod util; pub use area::Area; +pub use bool_ops::{BooleanOps, BooleanOpsScalar}; pub use buffer::Buffer; pub use is_empty::IsEmpty; pub use is_ring::IsRing; diff --git a/rust/geoarrow/src/algorithm/native/binary.rs b/rust/geoarrow/src/algorithm/native/binary.rs index d4ff3b77..30165a7e 100644 --- a/rust/geoarrow/src/algorithm/native/binary.rs +++ b/rust/geoarrow/src/algorithm/native/binary.rs @@ -4,12 +4,13 @@ use arrow_array::{BooleanArray, PrimitiveArray}; use arrow_buffer::ArrowNativeType; use arrow_buffer::{BooleanBufferBuilder, BufferBuilder, MutableBuffer, NullBuffer}; use arrow_data::ArrayData; +use geo_traits::GeometryTrait; use crate::array::*; use crate::error::{GeoArrowError, Result}; use crate::trait_::ArrayAccessor; -pub trait Binary<'a, Rhs: ArrayAccessor<'a> = Self>: ArrayAccessor<'a> { +pub trait Binary<'a, Rhs: ArrayAccessor<'a> = Self>: ArrayAccessor<'a> + NativeArray { fn binary_boolean(&'a self, rhs: &'a Rhs, op: F) -> Result where F: Fn(Self::Item, Rhs::Item) -> bool, @@ -116,6 +117,43 @@ pub trait Binary<'a, Rhs: ArrayAccessor<'a> = Self>: ArrayAccessor<'a> { Ok(PrimitiveArray::new(values, Some(nulls))) } } + + fn try_binary_geometry( + &'a self, + rhs: &'a Rhs, + op: F, + prefer_multi: bool, + ) -> Result + where + G: GeometryTrait, + F: Fn(Self::Item, Rhs::Item) -> Result, + { + if self.len() != rhs.len() { + return Err(GeoArrowError::General( + "Cannot perform binary operation on arrays of different length".to_string(), + )); + } + + let mut builder = GeometryBuilder::with_capacity_and_options( + Default::default(), + self.coord_type(), + self.metadata().clone(), + prefer_multi, + ); + + if self.is_empty() { + return Ok(builder.finish()); + } + + for (left, right) in self.iter().zip(rhs.iter()) { + if let (Some(left), Some(right)) = (left, right) { + builder.push_geometry(Some(&op(left, right)?))?; + } else { + builder.push_null(); + } + } + Ok(builder.finish()) + } } // Implementations on PointArray diff --git a/rust/geoarrow/src/algorithm/native/unary.rs b/rust/geoarrow/src/algorithm/native/unary.rs index 7aaa737e..6e7ac586 100644 --- a/rust/geoarrow/src/algorithm/native/unary.rs +++ b/rust/geoarrow/src/algorithm/native/unary.rs @@ -1,13 +1,14 @@ use arrow_array::types::ArrowPrimitiveType; -use arrow_array::{BooleanArray, OffsetSizeTrait, PrimitiveArray}; +use arrow_array::{BooleanArray, PrimitiveArray}; use arrow_buffer::{BooleanBufferBuilder, BufferBuilder}; use crate::array::*; use crate::datatypes::Dimension; +use crate::error::Result; use crate::trait_::ArrayAccessor; use geo_traits::*; -pub trait Unary<'a>: ArrayAccessor<'a> { +pub trait Unary<'a>: ArrayAccessor<'a> + NativeArray { // Note: This is derived from arrow-rs here: // https://github.com/apache/arrow-rs/blob/3ed7cc61d4157263ef2ab5c2d12bc7890a5315b3/arrow-array/src/array/primitive_array.rs#L753-L767 fn unary_primitive(&'a self, op: F) -> PrimitiveArray @@ -85,6 +86,32 @@ pub trait Unary<'a>: ArrayAccessor<'a> { Ok(BooleanArray::new(buffer.finish(), nulls)) } + + fn try_unary_geometry(&'a self, op: F, prefer_multi: bool) -> Result + where + F: Fn(Self::Item) -> Result, + G: GeometryTrait, + { + let mut builder = GeometryBuilder::with_capacity_and_options( + Default::default(), + self.coord_type(), + self.metadata().clone(), + prefer_multi, + ); + + if self.is_empty() { + return Ok(builder.finish()); + } + + for val in self.iter() { + if let Some(val) = val { + builder.push_geometry(Some(&op(val)?))?; + } else { + builder.push_null(); + } + } + Ok(builder.finish()) + } } impl Unary<'_> for PointArray {} @@ -97,7 +124,7 @@ impl Unary<'_> for MixedGeometryArray {} impl Unary<'_> for GeometryCollectionArray {} impl Unary<'_> for RectArray {} impl Unary<'_> for GeometryArray {} -impl Unary<'_> for WKBArray {} +// impl Unary<'_> for WKBArray {} #[allow(dead_code)] pub trait UnaryPoint<'a>: ArrayAccessor<'a> + NativeArray { diff --git a/rust/geoarrow/src/io/geos/scalar/coord/combined.rs b/rust/geoarrow/src/io/geos/scalar/coord/combined.rs index 9d0ee905..59a55aa3 100644 --- a/rust/geoarrow/src/io/geos/scalar/coord/combined.rs +++ b/rust/geoarrow/src/io/geos/scalar/coord/combined.rs @@ -6,27 +6,8 @@ use geos::{CoordDimensions, CoordSeq}; impl<'a> TryFrom<&'a Coord<'_>> for geos::CoordSeq { type Error = geos::Error; - fn try_from(point: &'a Coord<'_>) -> std::result::Result { - use geo_traits::Dimensions; - - match point.dim() { - Dimensions::Xy | Dimensions::Unknown(2) => { - let mut coord_seq = CoordSeq::new(1, CoordDimensions::TwoD)?; - coord_seq.set_x(0, point.x())?; - coord_seq.set_y(0, point.y())?; - Ok(coord_seq) - } - Dimensions::Xyz | Dimensions::Unknown(3) => { - let mut coord_seq = CoordSeq::new(1, CoordDimensions::ThreeD)?; - coord_seq.set_x(0, point.x())?; - coord_seq.set_y(0, point.y())?; - coord_seq.set_z(0, point.nth(2).unwrap())?; - Ok(coord_seq) - } - _ => Err(geos::Error::GenericError( - "Unexpected dimension".to_string(), - )), - } + fn try_from(coord: &'a Coord<'_>) -> std::result::Result { + coord_to_geos(coord) } } @@ -40,3 +21,48 @@ impl TryFrom for CoordSeq { } } } + +pub(crate) fn coord_to_geos( + coord: &impl CoordTrait, +) -> std::result::Result { + use geo_traits::Dimensions; + + match coord.dim() { + Dimensions::Xy | Dimensions::Unknown(2) => { + let mut coord_seq = CoordSeq::new(1, CoordDimensions::TwoD)?; + coord_seq.set_x(0, coord.x())?; + coord_seq.set_y(0, coord.y())?; + Ok(coord_seq) + } + Dimensions::Xyz | Dimensions::Unknown(3) => { + let mut coord_seq = CoordSeq::new(1, CoordDimensions::ThreeD)?; + coord_seq.set_x(0, coord.x())?; + coord_seq.set_y(0, coord.y())?; + coord_seq.set_z(0, coord.nth(2).unwrap())?; + Ok(coord_seq) + } + _ => Err(geos::Error::GenericError( + "Unexpected dimension".to_string(), + )), + } +} + +pub(crate) fn coords_to_geos, I: ExactSizeIterator>( + coords: I, + dims: CoordDimensions, +) -> std::result::Result { + let mut coord_seq = CoordSeq::new(coords.len().try_into().unwrap(), dims)?; + let is_3d = matches!(dims, CoordDimensions::ThreeD); + + coords.enumerate().try_for_each(|(idx, coord)| { + coord_seq.set_x(idx, coord.nth_or_panic(0))?; + coord_seq.set_y(idx, coord.nth_or_panic(1))?; + + if is_3d { + coord_seq.set_z(idx, coord.nth_or_panic(2))?; + } + Ok(()) + })?; + + Ok(coord_seq) +} diff --git a/rust/geoarrow/src/io/geos/scalar/coord/mod.rs b/rust/geoarrow/src/io/geos/scalar/coord/mod.rs index 2d61d710..410b6337 100644 --- a/rust/geoarrow/src/io/geos/scalar/coord/mod.rs +++ b/rust/geoarrow/src/io/geos/scalar/coord/mod.rs @@ -4,6 +4,8 @@ mod combined; mod interleaved; mod separated; +pub(crate) use combined::{coord_to_geos, coords_to_geos}; + #[derive(Clone)] pub struct GEOSConstCoord { pub(crate) coords: geos::CoordSeq, @@ -35,3 +37,15 @@ impl CoordTrait for GEOSConstCoord { self.coords.get_y(self.geom_index).unwrap() } } + +pub(crate) fn dims_to_geos(dim: geo_traits::Dimensions) -> geos::CoordDimensions { + match dim { + geo_traits::Dimensions::Xy | geo_traits::Dimensions::Unknown(2) => { + geos::CoordDimensions::TwoD + } + geo_traits::Dimensions::Xyz | geo_traits::Dimensions::Unknown(3) => { + geos::CoordDimensions::ThreeD + } + _ => panic!("Invalid coord dimension for GEOS: {:?}", dim), + } +} diff --git a/rust/geoarrow/src/io/geos/scalar/geometry.rs b/rust/geoarrow/src/io/geos/scalar/geometry.rs index a9616acc..092ce484 100644 --- a/rust/geoarrow/src/io/geos/scalar/geometry.rs +++ b/rust/geoarrow/src/io/geos/scalar/geometry.rs @@ -1,3 +1,10 @@ +use crate::io::geos::scalar::geometrycollection::to_geos_geometry_collection; +use crate::io::geos::scalar::linestring::to_geos_line_string; +use crate::io::geos::scalar::multilinestring::to_geos_multi_line_string; +use crate::io::geos::scalar::multipoint::to_geos_multi_point; +use crate::io::geos::scalar::multipolygon::to_geos_multi_polygon; +use crate::io::geos::scalar::point::to_geos_point; +use crate::io::geos::scalar::polygon::to_geos_polygon; use crate::io::geos::scalar::{ GEOSGeometryCollection, GEOSLineString, GEOSMultiLineString, GEOSMultiPoint, GEOSMultiPolygon, GEOSPoint, GEOSPolygon, @@ -27,6 +34,25 @@ impl<'a> TryFrom<&'a Geometry<'_>> for geos::Geometry { } } +pub(crate) fn to_geos_geometry( + geometry: &impl GeometryTrait, +) -> std::result::Result { + use geo_traits::GeometryType::*; + + match geometry.as_type() { + Point(g) => to_geos_point(g), + LineString(g) => to_geos_line_string(g), + Polygon(g) => to_geos_polygon(g), + MultiPoint(g) => to_geos_multi_point(g), + MultiLineString(g) => to_geos_multi_line_string(g), + MultiPolygon(g) => to_geos_multi_polygon(g), + GeometryCollection(g) => to_geos_geometry_collection(g), + Rect(_) => panic!("Unsupported rect in conversion to GEOS"), + Triangle(_) => panic!("Unsupported triangle in conversion to GEOS"), + Line(_) => panic!("Unsupported Line in conversion to GEOS"), + } +} + #[derive(Clone)] pub enum GEOSGeometry { Point(GEOSPoint), diff --git a/rust/geoarrow/src/io/geos/scalar/geometrycollection.rs b/rust/geoarrow/src/io/geos/scalar/geometrycollection.rs index 8de919d8..e82dcf5b 100644 --- a/rust/geoarrow/src/io/geos/scalar/geometrycollection.rs +++ b/rust/geoarrow/src/io/geos/scalar/geometrycollection.rs @@ -1,3 +1,4 @@ +use crate::io::geos::scalar::geometry::to_geos_geometry; use crate::io::geos::scalar::GEOSGeometry; use crate::scalar::GeometryCollection; use geo_traits::GeometryCollectionTrait; @@ -9,15 +10,20 @@ impl<'a> TryFrom<&'a GeometryCollection<'_>> for geos::Geometry { fn try_from( value: &'a GeometryCollection<'_>, ) -> std::result::Result { - geos::Geometry::create_geometry_collection( - value - .geometries() - .map(|geometry| (&geometry).try_into()) - .collect::, geos::Error>>()?, - ) + to_geos_geometry_collection(&value) } } +pub(crate) fn to_geos_geometry_collection( + gc: &impl GeometryCollectionTrait, +) -> std::result::Result { + geos::Geometry::create_geometry_collection( + gc.geometries() + .map(|geometry| to_geos_geometry(&geometry)) + .collect::, geos::Error>>()?, + ) +} + #[derive(Clone)] pub struct GEOSGeometryCollection(geos::Geometry); diff --git a/rust/geoarrow/src/io/geos/scalar/linestring.rs b/rust/geoarrow/src/io/geos/scalar/linestring.rs index be0488ce..5ef8897f 100644 --- a/rust/geoarrow/src/io/geos/scalar/linestring.rs +++ b/rust/geoarrow/src/io/geos/scalar/linestring.rs @@ -1,6 +1,6 @@ use crate::array::util::OffsetBufferUtils; use crate::error::{GeoArrowError, Result}; -use crate::io::geos::scalar::coord::GEOSConstCoord; +use crate::io::geos::scalar::coord::{coords_to_geos, dims_to_geos, GEOSConstCoord}; use crate::scalar::LineString; use geo_traits::LineStringTrait; use geos::{Geom, GeometryTypes}; @@ -27,6 +27,22 @@ impl LineString<'_> { } } +pub(crate) fn to_geos_line_string( + line_string: &impl LineStringTrait, +) -> std::result::Result { + let dims = dims_to_geos(line_string.dim()); + let coord_seq = coords_to_geos(line_string.coords(), dims)?; + geos::Geometry::create_line_string(coord_seq) +} + +pub(crate) fn to_geos_linear_ring( + line_string: &impl LineStringTrait, +) -> std::result::Result { + let dims = dims_to_geos(line_string.dim()); + let coord_seq = coords_to_geos(line_string.coords(), dims)?; + geos::Geometry::create_linear_ring(coord_seq) +} + #[derive(Clone)] pub struct GEOSLineString(geos::Geometry); diff --git a/rust/geoarrow/src/io/geos/scalar/mod.rs b/rust/geoarrow/src/io/geos/scalar/mod.rs index 53d9d4ff..c7077e17 100644 --- a/rust/geoarrow/src/io/geos/scalar/mod.rs +++ b/rust/geoarrow/src/io/geos/scalar/mod.rs @@ -10,6 +10,7 @@ mod multipolygon; mod point; mod polygon; +pub(crate) use geometry::to_geos_geometry; pub use geometry::GEOSGeometry; pub use geometrycollection::GEOSGeometryCollection; pub use linearring::GEOSConstLinearRing; diff --git a/rust/geoarrow/src/io/geos/scalar/multilinestring.rs b/rust/geoarrow/src/io/geos/scalar/multilinestring.rs index d11426dd..fae11c5c 100644 --- a/rust/geoarrow/src/io/geos/scalar/multilinestring.rs +++ b/rust/geoarrow/src/io/geos/scalar/multilinestring.rs @@ -1,4 +1,5 @@ use crate::error::{GeoArrowError, Result}; +use crate::io::geos::scalar::linestring::to_geos_line_string; use crate::io::geos::scalar::GEOSConstLineString; use crate::scalar::MultiLineString; use geo_traits::MultiLineStringTrait; @@ -10,14 +11,21 @@ impl<'a> TryFrom<&'a MultiLineString<'_>> for geos::Geometry { fn try_from( value: &'a MultiLineString<'_>, ) -> std::result::Result { - geos::Geometry::create_multiline_string( - value - .line_strings() - .map(|line| (&line).try_into()) - .collect::, geos::Error>>()?, - ) + to_geos_multi_line_string(&value) } } + +pub(crate) fn to_geos_multi_line_string( + multi_line_string: &impl MultiLineStringTrait, +) -> std::result::Result { + geos::Geometry::create_multiline_string( + multi_line_string + .line_strings() + .map(|line| to_geos_line_string(&line)) + .collect::, geos::Error>>()?, + ) +} + /// A GEOS geometry known to be a MultiLineString #[derive(Clone)] pub struct GEOSMultiLineString(pub(crate) geos::Geometry); diff --git a/rust/geoarrow/src/io/geos/scalar/multipoint.rs b/rust/geoarrow/src/io/geos/scalar/multipoint.rs index ebbf8160..354531d8 100644 --- a/rust/geoarrow/src/io/geos/scalar/multipoint.rs +++ b/rust/geoarrow/src/io/geos/scalar/multipoint.rs @@ -1,4 +1,5 @@ use crate::error::{GeoArrowError, Result}; +use crate::io::geos::scalar::point::to_geos_point; use crate::io::geos::scalar::GEOSConstPoint; use crate::scalar::MultiPoint; use geo_traits::MultiPointTrait; @@ -8,15 +9,21 @@ impl<'a> TryFrom<&'a MultiPoint<'_>> for geos::Geometry { type Error = geos::Error; fn try_from(value: &'a MultiPoint<'_>) -> std::result::Result { - geos::Geometry::create_multipoint( - value - .points() - .map(|point| (&point).try_into()) - .collect::, geos::Error>>()?, - ) + to_geos_multi_point(value) } } +pub(crate) fn to_geos_multi_point( + multi_point: &impl MultiPointTrait, +) -> std::result::Result { + geos::Geometry::create_multipoint( + multi_point + .points() + .map(|point| to_geos_point(&point)) + .collect::, geos::Error>>()?, + ) +} + #[derive(Clone)] pub struct GEOSMultiPoint(pub(crate) geos::Geometry); diff --git a/rust/geoarrow/src/io/geos/scalar/multipolygon.rs b/rust/geoarrow/src/io/geos/scalar/multipolygon.rs index e0383cdf..3cc8df63 100644 --- a/rust/geoarrow/src/io/geos/scalar/multipolygon.rs +++ b/rust/geoarrow/src/io/geos/scalar/multipolygon.rs @@ -1,4 +1,5 @@ use crate::error::{GeoArrowError, Result}; +use crate::io::geos::scalar::polygon::to_geos_polygon; use crate::io::geos::scalar::GEOSConstPolygon; use crate::scalar::MultiPolygon; use geo_traits::MultiPolygonTrait; @@ -8,15 +9,21 @@ impl<'a> TryFrom<&'a MultiPolygon<'_>> for geos::Geometry { type Error = geos::Error; fn try_from(value: &'a MultiPolygon<'_>) -> std::result::Result { - geos::Geometry::create_multipolygon( - value - .polygons() - .map(|polygon| (&polygon).try_into()) - .collect::, geos::Error>>()?, - ) + to_geos_multi_polygon(value) } } +pub(crate) fn to_geos_multi_polygon( + multi_polygon: &impl MultiPolygonTrait, +) -> std::result::Result { + geos::Geometry::create_multipolygon( + multi_polygon + .polygons() + .map(|polygon| to_geos_polygon(&polygon)) + .collect::, geos::Error>>()?, + ) +} + #[derive(Clone)] pub struct GEOSMultiPolygon(pub(crate) geos::Geometry); diff --git a/rust/geoarrow/src/io/geos/scalar/point.rs b/rust/geoarrow/src/io/geos/scalar/point.rs index ea81ba91..32bb69b5 100644 --- a/rust/geoarrow/src/io/geos/scalar/point.rs +++ b/rust/geoarrow/src/io/geos/scalar/point.rs @@ -1,5 +1,5 @@ use crate::error::{GeoArrowError, Result}; -use crate::io::geos::scalar::coord::GEOSConstCoord; +use crate::io::geos::scalar::coord::{coord_to_geos, GEOSConstCoord}; use crate::scalar::Point; use geo_traits::PointTrait; use geos::{Geom, GeometryTypes}; @@ -8,12 +8,18 @@ impl<'a> TryFrom<&'a Point<'_>> for geos::Geometry { type Error = geos::Error; fn try_from(point: &'a Point<'_>) -> std::result::Result { - if let Some(coord) = PointTrait::coord(&point) { - let coord_seq = (&coord).try_into()?; - Ok(geos::Geometry::create_point(coord_seq)?) - } else { - Ok(geos::Geometry::create_empty_point()?) - } + to_geos_point(point) + } +} + +pub(crate) fn to_geos_point( + point: &impl PointTrait, +) -> std::result::Result { + if let Some(coord) = point.coord() { + let coord_seq = coord_to_geos(&coord)?; + Ok(geos::Geometry::create_point(coord_seq)?) + } else { + Ok(geos::Geometry::create_empty_point()?) } } diff --git a/rust/geoarrow/src/io/geos/scalar/polygon.rs b/rust/geoarrow/src/io/geos/scalar/polygon.rs index ce4f3ad4..9f741cf5 100644 --- a/rust/geoarrow/src/io/geos/scalar/polygon.rs +++ b/rust/geoarrow/src/io/geos/scalar/polygon.rs @@ -1,4 +1,5 @@ use crate::error::{GeoArrowError, Result}; +use crate::io::geos::scalar::linestring::to_geos_linear_ring; use crate::io::geos::scalar::GEOSConstLinearRing; use crate::scalar::Polygon; use geo_traits::PolygonTrait; @@ -8,16 +9,22 @@ impl<'a> TryFrom<&'a Polygon<'_>> for geos::Geometry { type Error = geos::Error; fn try_from(value: &'a Polygon<'_>) -> std::result::Result { - if let Some(exterior) = value.exterior() { - let exterior = exterior.to_geos_linear_ring()?; - let interiors = value - .interiors() - .map(|interior| interior.to_geos_linear_ring()) - .collect::, geos::Error>>()?; - geos::Geometry::create_polygon(exterior, interiors) - } else { - geos::Geometry::create_empty_polygon() - } + to_geos_polygon(value) + } +} + +pub(crate) fn to_geos_polygon( + polygon: &impl PolygonTrait, +) -> std::result::Result { + if let Some(exterior) = polygon.exterior() { + let exterior = to_geos_linear_ring(&exterior)?; + let interiors = polygon + .interiors() + .map(|interior| to_geos_linear_ring(&interior)) + .collect::, geos::Error>>()?; + geos::Geometry::create_polygon(exterior, interiors) + } else { + geos::Geometry::create_empty_polygon() } } From ec680184a74be5bc1c6a895fa540e9ee0f190966 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Mon, 9 Dec 2024 22:06:23 -0500 Subject: [PATCH 2/2] compile --- rust/geoarrow/src/algorithm/native/binary.rs | 48 ++++++++++++++++---- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/rust/geoarrow/src/algorithm/native/binary.rs b/rust/geoarrow/src/algorithm/native/binary.rs index 30165a7e..2af12da7 100644 --- a/rust/geoarrow/src/algorithm/native/binary.rs +++ b/rust/geoarrow/src/algorithm/native/binary.rs @@ -158,7 +158,6 @@ pub trait Binary<'a, Rhs: ArrayAccessor<'a> = Self>: ArrayAccessor<'a> + NativeA // Implementations on PointArray impl Binary<'_, PointArray> for PointArray {} -impl Binary<'_, PointArray> for RectArray {} impl Binary<'_, PointArray> for LineStringArray {} impl Binary<'_, PointArray> for PolygonArray {} impl Binary<'_, PointArray> for MultiPointArray {} @@ -166,10 +165,11 @@ impl Binary<'_, PointArray> for MultiLineStringArray {} impl Binary<'_, PointArray> for MultiPolygonArray {} impl Binary<'_, PointArray> for MixedGeometryArray {} impl Binary<'_, PointArray> for GeometryCollectionArray {} +impl Binary<'_, PointArray> for RectArray {} +impl Binary<'_, PointArray> for GeometryArray {} // Implementations on LineStringArray impl Binary<'_, LineStringArray> for PointArray {} -impl Binary<'_, LineStringArray> for RectArray {} impl Binary<'_, LineStringArray> for LineStringArray {} impl Binary<'_, LineStringArray> for PolygonArray {} impl Binary<'_, LineStringArray> for MultiPointArray {} @@ -177,10 +177,11 @@ impl Binary<'_, LineStringArray> for MultiLineStringArray {} impl Binary<'_, LineStringArray> for MultiPolygonArray {} impl Binary<'_, LineStringArray> for MixedGeometryArray {} impl Binary<'_, LineStringArray> for GeometryCollectionArray {} +impl Binary<'_, LineStringArray> for RectArray {} +impl Binary<'_, LineStringArray> for GeometryArray {} // Implementations on PolygonArray impl Binary<'_, PolygonArray> for PointArray {} -impl Binary<'_, PolygonArray> for RectArray {} impl Binary<'_, PolygonArray> for LineStringArray {} impl Binary<'_, PolygonArray> for PolygonArray {} impl Binary<'_, PolygonArray> for MultiPointArray {} @@ -188,10 +189,11 @@ impl Binary<'_, PolygonArray> for MultiLineStringArray {} impl Binary<'_, PolygonArray> for MultiPolygonArray {} impl Binary<'_, PolygonArray> for MixedGeometryArray {} impl Binary<'_, PolygonArray> for GeometryCollectionArray {} +impl Binary<'_, PolygonArray> for RectArray {} +impl Binary<'_, PolygonArray> for GeometryArray {} // Implementations on MultiPointArray impl Binary<'_, MultiPointArray> for PointArray {} -impl Binary<'_, MultiPointArray> for RectArray {} impl Binary<'_, MultiPointArray> for LineStringArray {} impl Binary<'_, MultiPointArray> for PolygonArray {} impl Binary<'_, MultiPointArray> for MultiPointArray {} @@ -199,10 +201,11 @@ impl Binary<'_, MultiPointArray> for MultiLineStringArray {} impl Binary<'_, MultiPointArray> for MultiPolygonArray {} impl Binary<'_, MultiPointArray> for MixedGeometryArray {} impl Binary<'_, MultiPointArray> for GeometryCollectionArray {} +impl Binary<'_, MultiPointArray> for RectArray {} +impl Binary<'_, MultiPointArray> for GeometryArray {} // Implementations on MultiLineStringArray impl Binary<'_, MultiLineStringArray> for PointArray {} -impl Binary<'_, MultiLineStringArray> for RectArray {} impl Binary<'_, MultiLineStringArray> for LineStringArray {} impl Binary<'_, MultiLineStringArray> for PolygonArray {} impl Binary<'_, MultiLineStringArray> for MultiPointArray {} @@ -210,10 +213,11 @@ impl Binary<'_, MultiLineStringArray> for MultiLineStringArray {} impl Binary<'_, MultiLineStringArray> for MultiPolygonArray {} impl Binary<'_, MultiLineStringArray> for MixedGeometryArray {} impl Binary<'_, MultiLineStringArray> for GeometryCollectionArray {} +impl Binary<'_, MultiLineStringArray> for RectArray {} +impl Binary<'_, MultiLineStringArray> for GeometryArray {} // Implementations on MultiPolygonArray impl Binary<'_, MultiPolygonArray> for PointArray {} -impl Binary<'_, MultiPolygonArray> for RectArray {} impl Binary<'_, MultiPolygonArray> for LineStringArray {} impl Binary<'_, MultiPolygonArray> for PolygonArray {} impl Binary<'_, MultiPolygonArray> for MultiPointArray {} @@ -221,10 +225,11 @@ impl Binary<'_, MultiPolygonArray> for MultiLineStringArray {} impl Binary<'_, MultiPolygonArray> for MultiPolygonArray {} impl Binary<'_, MultiPolygonArray> for MixedGeometryArray {} impl Binary<'_, MultiPolygonArray> for GeometryCollectionArray {} +impl Binary<'_, MultiPolygonArray> for RectArray {} +impl Binary<'_, MultiPolygonArray> for GeometryArray {} // Implementations on MixedGeometryArray impl Binary<'_, MixedGeometryArray> for PointArray {} -impl Binary<'_, MixedGeometryArray> for RectArray {} impl Binary<'_, MixedGeometryArray> for LineStringArray {} impl Binary<'_, MixedGeometryArray> for PolygonArray {} impl Binary<'_, MixedGeometryArray> for MultiPointArray {} @@ -232,10 +237,11 @@ impl Binary<'_, MixedGeometryArray> for MultiLineStringArray {} impl Binary<'_, MixedGeometryArray> for MultiPolygonArray {} impl Binary<'_, MixedGeometryArray> for MixedGeometryArray {} impl Binary<'_, MixedGeometryArray> for GeometryCollectionArray {} +impl Binary<'_, MixedGeometryArray> for RectArray {} +impl Binary<'_, MixedGeometryArray> for GeometryArray {} // Implementations on GeometryCollectionArray impl Binary<'_, GeometryCollectionArray> for PointArray {} -impl Binary<'_, GeometryCollectionArray> for RectArray {} impl Binary<'_, GeometryCollectionArray> for LineStringArray {} impl Binary<'_, GeometryCollectionArray> for PolygonArray {} impl Binary<'_, GeometryCollectionArray> for MultiPointArray {} @@ -243,3 +249,29 @@ impl Binary<'_, GeometryCollectionArray> for MultiLineStringArray {} impl Binary<'_, GeometryCollectionArray> for MultiPolygonArray {} impl Binary<'_, GeometryCollectionArray> for MixedGeometryArray {} impl Binary<'_, GeometryCollectionArray> for GeometryCollectionArray {} +impl Binary<'_, GeometryCollectionArray> for RectArray {} +impl Binary<'_, GeometryCollectionArray> for GeometryArray {} + +// Implementations on RectArray +impl Binary<'_, RectArray> for PointArray {} +impl Binary<'_, RectArray> for LineStringArray {} +impl Binary<'_, RectArray> for PolygonArray {} +impl Binary<'_, RectArray> for MultiPointArray {} +impl Binary<'_, RectArray> for MultiLineStringArray {} +impl Binary<'_, RectArray> for MultiPolygonArray {} +impl Binary<'_, RectArray> for MixedGeometryArray {} +impl Binary<'_, RectArray> for GeometryCollectionArray {} +impl Binary<'_, RectArray> for RectArray {} +impl Binary<'_, RectArray> for GeometryArray {} + +// Implementations on GeometryArray +impl Binary<'_, GeometryArray> for PointArray {} +impl Binary<'_, GeometryArray> for LineStringArray {} +impl Binary<'_, GeometryArray> for PolygonArray {} +impl Binary<'_, GeometryArray> for MultiPointArray {} +impl Binary<'_, GeometryArray> for MultiLineStringArray {} +impl Binary<'_, GeometryArray> for MultiPolygonArray {} +impl Binary<'_, GeometryArray> for MixedGeometryArray {} +impl Binary<'_, GeometryArray> for GeometryCollectionArray {} +impl Binary<'_, GeometryArray> for RectArray {} +impl Binary<'_, GeometryArray> for GeometryArray {}