From d3f03e1d39ae844fa2ef016900f7d9932135fc15 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Fri, 20 Dec 2024 11:18:44 -0500 Subject: [PATCH] Work around upstream compiler bug --- rust/geoarrow/src/algorithm/geo/contains.rs | 6 +-- rust/geoarrow/src/algorithm/geo/intersects.rs | 17 +++--- rust/geoarrow/src/io/geo.rs | 53 +++++++++++++++++++ rust/geoarrow/src/io/mod.rs | 1 + rust/geoarrow/src/scalar/binary/scalar.rs | 4 +- rust/geoarrow/src/scalar/geometry/scalar.rs | 4 +- .../src/scalar/geometrycollection/scalar.rs | 4 +- 7 files changed, 72 insertions(+), 17 deletions(-) create mode 100644 rust/geoarrow/src/io/geo.rs diff --git a/rust/geoarrow/src/algorithm/geo/contains.rs b/rust/geoarrow/src/algorithm/geo/contains.rs index 278dd8fe..814acc40 100644 --- a/rust/geoarrow/src/algorithm/geo/contains.rs +++ b/rust/geoarrow/src/algorithm/geo/contains.rs @@ -2,11 +2,11 @@ use crate::algorithm::native::{Binary, Unary}; use crate::array::*; use crate::datatypes::NativeType; use crate::error::GeoArrowError; +use crate::io::geo::geometry_to_geo; use crate::trait_::NativeScalar; use crate::NativeArray; use arrow_array::BooleanArray; use geo::Contains as _Contains; -use geo_traits::to_geo::*; use geo_traits::GeometryTrait; /// Checks if `rhs` is completely contained within `self`. @@ -135,7 +135,7 @@ pub trait ContainsGeometry { impl> ContainsGeometry for PointArray { fn contains(&self, rhs: &G) -> BooleanArray { - let rhs = rhs.to_geometry(); + let rhs = geometry_to_geo(rhs); self.try_unary_boolean::<_, GeoArrowError>(|geom| Ok(geom.to_geo().contains(&rhs))) .unwrap() } @@ -145,7 +145,7 @@ macro_rules! impl_contains_point { ($array:ty) => { impl> ContainsGeometry for $array { fn contains(&self, rhs: &G) -> BooleanArray { - let rhs = rhs.to_geometry(); + let rhs = geometry_to_geo(rhs); self.try_unary_boolean::<_, GeoArrowError>(|geom| { Ok(geom.to_geo_geometry().contains(&rhs)) }) diff --git a/rust/geoarrow/src/algorithm/geo/intersects.rs b/rust/geoarrow/src/algorithm/geo/intersects.rs index fb0d1c39..6f5675d2 100644 --- a/rust/geoarrow/src/algorithm/geo/intersects.rs +++ b/rust/geoarrow/src/algorithm/geo/intersects.rs @@ -1,6 +1,7 @@ use crate::chunked_array::ChunkedArray; use crate::indexed::array::*; use crate::indexed::chunked::*; +use crate::io::geo::{geometry_collection_to_geo, geometry_to_geo}; use crate::trait_::NativeScalar; use arrow_array::BooleanArray; use geo::{BoundingRect, Intersects as _Intersects}; @@ -592,7 +593,7 @@ impl> IntersectsGeometry for IndexedPointArray { type Output = BooleanArray; fn intersects(&self, rhs: &G) -> Self::Output { - let rhs = rhs.to_geometry(); + let rhs = geometry_to_geo(rhs); self.unary_boolean(&rhs.bounding_rect().unwrap(), |geom| { geom.to_geo().intersects(&rhs) }) @@ -605,7 +606,7 @@ macro_rules! impl_intersects { type Output = BooleanArray; fn intersects(&self, rhs: &G) -> Self::Output { - let rhs = rhs.to_geometry(); + let rhs = geometry_to_geo(rhs); self.unary_boolean(&rhs.bounding_rect().unwrap(), |geom| { geom.to_geo().intersects(&rhs) }) @@ -626,7 +627,7 @@ impl> IntersectsGeometry for IndexedChunkedPointArr type Output = ChunkedArray; fn intersects(&self, rhs: &G) -> Self::Output { - let rhs = rhs.to_geometry(); + let rhs = geometry_to_geo(rhs); self.map(|chunk| IntersectsGeometry::intersects(chunk, &rhs)) .try_into() .unwrap() @@ -639,7 +640,7 @@ macro_rules! impl_intersects { type Output = ChunkedArray; fn intersects(&self, rhs: &G) -> Self::Output { - let rhs = rhs.to_geometry(); + let rhs = geometry_to_geo(rhs); self.map(|chunk| IntersectsGeometry::intersects(chunk, &rhs)) .try_into() .unwrap() @@ -666,7 +667,7 @@ impl> IntersectsGeometryCollection for In type Output = BooleanArray; fn intersects(&self, rhs: &G) -> Self::Output { - let rhs = rhs.to_geometry_collection(); + let rhs = geometry_collection_to_geo(rhs); self.unary_boolean(&rhs.bounding_rect().unwrap(), |geom| { geom.to_geo().intersects(&rhs) }) @@ -679,7 +680,7 @@ macro_rules! impl_intersects { type Output = BooleanArray; fn intersects(&self, rhs: &G) -> Self::Output { - let rhs = rhs.to_geometry_collection(); + let rhs = geometry_collection_to_geo(rhs); self.unary_boolean(&rhs.bounding_rect().unwrap(), |geom| { geom.to_geo().intersects(&rhs) }) @@ -702,7 +703,7 @@ impl> IntersectsGeometryCollection type Output = ChunkedArray; fn intersects(&self, rhs: &G) -> Self::Output { - let rhs = rhs.to_geometry_collection(); + let rhs = geometry_collection_to_geo(rhs); self.map(|chunk| IntersectsGeometryCollection::intersects(chunk, &rhs)) .try_into() .unwrap() @@ -715,7 +716,7 @@ macro_rules! impl_intersects { type Output = ChunkedArray; fn intersects(&self, rhs: &G) -> Self::Output { - let rhs = rhs.to_geometry_collection(); + let rhs = geometry_collection_to_geo(rhs); self.map(|chunk| IntersectsGeometryCollection::intersects(chunk, &rhs)) .try_into() .unwrap() diff --git a/rust/geoarrow/src/io/geo.rs b/rust/geoarrow/src/io/geo.rs new file mode 100644 index 00000000..a044c7d9 --- /dev/null +++ b/rust/geoarrow/src/io/geo.rs @@ -0,0 +1,53 @@ +//! Convert structs that implement geo-traits to [geo-types] objects. +//! +//! Note that this is the same underlying implementation as upstream [geo] in +//! . However, the trait-based implementation hits this +//! compiler regression , +//! , which prevents from compiling in release +//! mode on a stable Rust version. For some reason, the **function-based implementation** does not +//! hit this regression, and thus allows building geoarrow without using latest nightly and a +//! custom `RUSTFLAGS`. +//! +//! Note that it's only + +use geo::{CoordNum, Geometry, GeometryCollection}; + +use geo_traits::to_geo::{ + ToGeoLine, ToGeoLineString, ToGeoMultiLineString, ToGeoMultiPoint, ToGeoMultiPolygon, + ToGeoPoint, ToGeoPolygon, ToGeoRect, ToGeoTriangle, +}; +use geo_traits::{GeometryCollectionTrait, GeometryTrait, GeometryType}; + +/// Convert any Geometry to a [`Geometry`]. +/// +/// Only the first two dimensions will be kept. +pub fn geometry_to_geo(geometry: &impl GeometryTrait) -> Geometry { + use GeometryType::*; + + match geometry.as_type() { + Point(geom) => Geometry::Point(geom.to_point()), + LineString(geom) => Geometry::LineString(geom.to_line_string()), + Polygon(geom) => Geometry::Polygon(geom.to_polygon()), + MultiPoint(geom) => Geometry::MultiPoint(geom.to_multi_point()), + MultiLineString(geom) => Geometry::MultiLineString(geom.to_multi_line_string()), + MultiPolygon(geom) => Geometry::MultiPolygon(geom.to_multi_polygon()), + GeometryCollection(geom) => Geometry::GeometryCollection(geometry_collection_to_geo(geom)), + Rect(geom) => Geometry::Rect(geom.to_rect()), + Line(geom) => Geometry::Line(geom.to_line()), + Triangle(geom) => Geometry::Triangle(geom.to_triangle()), + } +} + +/// Convert any GeometryCollection to a [`GeometryCollection`]. +/// +/// Only the first two dimensions will be kept. +pub fn geometry_collection_to_geo( + geometry_collection: &impl GeometryCollectionTrait, +) -> GeometryCollection { + GeometryCollection::new_from( + geometry_collection + .geometries() + .map(|geometry| geometry_to_geo(&geometry)) + .collect(), + ) +} diff --git a/rust/geoarrow/src/io/mod.rs b/rust/geoarrow/src/io/mod.rs index 38eeadd3..a3ee3557 100644 --- a/rust/geoarrow/src/io/mod.rs +++ b/rust/geoarrow/src/io/mod.rs @@ -11,6 +11,7 @@ pub(crate) mod display; pub mod flatgeobuf; #[cfg(feature = "gdal")] pub mod gdal; +pub(crate) mod geo; pub mod geojson; pub mod geojson_lines; #[cfg(feature = "geos")] diff --git a/rust/geoarrow/src/scalar/binary/scalar.rs b/rust/geoarrow/src/scalar/binary/scalar.rs index 26e3062c..d5035717 100644 --- a/rust/geoarrow/src/scalar/binary/scalar.rs +++ b/rust/geoarrow/src/scalar/binary/scalar.rs @@ -1,8 +1,8 @@ use crate::error::Result; +use crate::io::geo::geometry_to_geo; use crate::trait_::NativeScalar; use arrow_array::{GenericBinaryArray, OffsetSizeTrait}; use geo::BoundingRect; -use geo_traits::to_geo::ToGeoGeometry; use geo_traits::GeometryTrait; use rstar::{RTreeObject, AABB}; @@ -77,7 +77,7 @@ impl AsRef<[u8]> for WKB<'_, O> { impl From<&WKB<'_, O>> for geo::Geometry { fn from(value: &WKB<'_, O>) -> Self { - value.parse().unwrap().to_geometry() + geometry_to_geo(&value.parse().unwrap()) } } diff --git a/rust/geoarrow/src/scalar/geometry/scalar.rs b/rust/geoarrow/src/scalar/geometry/scalar.rs index 179e6647..f0bd1806 100644 --- a/rust/geoarrow/src/scalar/geometry/scalar.rs +++ b/rust/geoarrow/src/scalar/geometry/scalar.rs @@ -1,7 +1,7 @@ use crate::algorithm::native::eq::geometry_eq; +use crate::io::geo::geometry_to_geo; use crate::scalar::*; use crate::trait_::NativeScalar; -use geo_traits::to_geo::ToGeoGeometry; use geo_traits::{ GeometryCollectionTrait, GeometryTrait, GeometryType, LineStringTrait, MultiLineStringTrait, MultiPointTrait, MultiPolygonTrait, PointTrait, PolygonTrait, RectTrait, UnimplementedLine, @@ -241,7 +241,7 @@ impl From> for geo::Geometry { impl From<&Geometry<'_>> for geo::Geometry { fn from(value: &Geometry<'_>) -> Self { - ToGeoGeometry::to_geometry(value) + geometry_to_geo(value) } } diff --git a/rust/geoarrow/src/scalar/geometrycollection/scalar.rs b/rust/geoarrow/src/scalar/geometrycollection/scalar.rs index b1cf9a4b..635b2800 100644 --- a/rust/geoarrow/src/scalar/geometrycollection/scalar.rs +++ b/rust/geoarrow/src/scalar/geometrycollection/scalar.rs @@ -2,12 +2,12 @@ use crate::algorithm::native::eq::geometry_collection_eq; use crate::array::util::OffsetBufferUtils; use crate::array::MixedGeometryArray; use crate::datatypes::Dimension; +use crate::io::geo::geometry_collection_to_geo; use crate::scalar::Geometry; use crate::trait_::ArrayAccessor; use crate::trait_::NativeScalar; use crate::NativeArray; use arrow_buffer::OffsetBuffer; -use geo_traits::to_geo::ToGeoGeometryCollection; use geo_traits::GeometryCollectionTrait; use rstar::{RTreeObject, AABB}; @@ -111,7 +111,7 @@ impl<'a> GeometryCollectionTrait for &'a GeometryCollection<'a> { impl From<&GeometryCollection<'_>> for geo::GeometryCollection { fn from(value: &GeometryCollection<'_>) -> Self { - value.to_geometry_collection() + geometry_collection_to_geo(value) } }