From 09f193786babd00f11aa34c943665055d656e028 Mon Sep 17 00:00:00 2001 From: Jake Low Date: Sun, 18 Aug 2024 22:32:58 -0700 Subject: [PATCH 1/3] Implement TryFrom for GEOS Geometry ...and also TryFrom --- src/from_geo.rs | 96 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 94 insertions(+), 2 deletions(-) diff --git a/src/from_geo.rs b/src/from_geo.rs index 79644a7..620ccec 100644 --- a/src/from_geo.rs +++ b/src/from_geo.rs @@ -1,6 +1,9 @@ use crate::error::Error; use crate::{CoordDimensions, CoordSeq, Geometry as GGeometry}; -use geo_types::{Coord, LineString, MultiLineString, MultiPoint, MultiPolygon, Point, Polygon}; +use geo_types::{ + Coord, Geometry, GeometryCollection, LineString, MultiLineString, MultiPoint, MultiPolygon, + Point, Polygon, +}; use std; use std::borrow::Borrow; @@ -200,11 +203,64 @@ impl TryFrom> for GGeometry { } } +impl<'a, 'b> TryFrom<&'a GeometryCollection> for GGeometry { + type Error = Error; + + fn try_from(other: &'a GeometryCollection) -> Result { + let geoms: Vec<_> = other + .0 + .iter() + .map(|p| p.try_into()) + .collect::, _>>()?; + + GGeometry::create_geometry_collection(geoms) + } +} + +impl TryFrom> for GGeometry { + type Error = Error; + + fn try_from(other: GeometryCollection) -> Result { + GGeometry::try_from(&other) + } +} + +impl<'a, 'b> TryFrom<&'a Geometry> for GGeometry { + type Error = Error; + + fn try_from(other: &'a Geometry) -> Result { + match other { + Geometry::Point(inner) => GGeometry::try_from(inner), + Geometry::MultiPoint(inner) => GGeometry::try_from(inner), + Geometry::LineString(inner) => GGeometry::try_from(inner), + Geometry::MultiLineString(inner) => GGeometry::try_from(inner), + Geometry::Polygon(inner) => GGeometry::try_from(inner), + Geometry::MultiPolygon(inner) => GGeometry::try_from(inner), + Geometry::GeometryCollection(inner) => GGeometry::try_from(inner), + // GEOS has equivalents of the types below, but they aren't subclasses of geos::Geometry + Geometry::Triangle(_) => unimplemented!("Cannot convert Triange to GEOS Geometry"), + Geometry::Rect(_) => unimplemented!("Cannot convert Rect to GEOS Geometry"), + Geometry::Line(_) => unimplemented!("Cannot convert Line to GEOS Geometry"), + } + } +} + +impl TryFrom> for GGeometry { + type Error = Error; + + fn try_from(other: Geometry) -> Result { + GGeometry::try_from(&other) + } +} + #[cfg(test)] mod test { use super::LineRing; use crate::{Geom, Geometry as GGeometry}; - use geo_types::{Coord, LineString, MultiLineString, MultiPoint, MultiPolygon, Point, Polygon}; + use geo_types::{ + Coord, Geometry, GeometryCollection, LineString, MultiLineString, MultiPoint, MultiPolygon, + Point, Polygon, + }; use std::convert::TryInto; fn coords(tuples: Vec<(f64, f64)>) -> Vec> { @@ -282,6 +338,42 @@ mod test { assert!(geom.is_err()); } + #[test] + fn geometry_collection_test() { + let a = Polygon::new( + LineString(coords(vec![ + (0., 0.), + (0., 1.), + (1., 1.), + (1., 0.), + (0., 0.), + ])), + vec![], + ); + let b = Polygon::new( + LineString(coords(vec![ + (2., 1.), + (2., 2.), + (5., 2.), + (5., 1.), + (2., 1.), + ])), + vec![], + ); + + let collection = GeometryCollection::new_from(vec![ + Geometry::Polygon(a.clone()), + Geometry::Polygon(b.clone()), + ]); + + let geos_collection: GGeometry = collection.try_into().unwrap(); + let geos_polygon_a: GGeometry = a.try_into().unwrap(); + let geos_polygon_b: GGeometry = b.try_into().unwrap(); + + assert!(geos_collection.contains(&geos_polygon_a).unwrap()); + assert!(geos_collection.contains(&geos_polygon_b).unwrap()); + } + #[test] fn incorrect_polygon_not_closed() { // even if the polygon is not closed we can convert it to geos (we close it) From 3cd4cbf2fc26c9dc974390dc3fee6beddd53d81d Mon Sep 17 00:00:00 2001 From: Jake Low Date: Mon, 19 Aug 2024 17:25:02 -0700 Subject: [PATCH 2/3] Return Err instead of panicking --- src/from_geo.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/from_geo.rs b/src/from_geo.rs index 620ccec..2b94536 100644 --- a/src/from_geo.rs +++ b/src/from_geo.rs @@ -238,9 +238,15 @@ impl<'a, 'b> TryFrom<&'a Geometry> for GGeometry { Geometry::MultiPolygon(inner) => GGeometry::try_from(inner), Geometry::GeometryCollection(inner) => GGeometry::try_from(inner), // GEOS has equivalents of the types below, but they aren't subclasses of geos::Geometry - Geometry::Triangle(_) => unimplemented!("Cannot convert Triange to GEOS Geometry"), - Geometry::Rect(_) => unimplemented!("Cannot convert Rect to GEOS Geometry"), - Geometry::Line(_) => unimplemented!("Cannot convert Line to GEOS Geometry"), + Geometry::Triangle(_) => Err(Error::ConversionError( + "Cannot convert Triange to GEOS Geometry".to_string(), + )), + Geometry::Rect(_) => Err(Error::ConversionError( + "Cannot convert Rect to GEOS Geometry".to_string(), + )), + Geometry::Line(_) => Err(Error::ConversionError( + "Cannot convert Line to GEOS Geometry".to_string(), + )), } } } @@ -259,7 +265,7 @@ mod test { use crate::{Geom, Geometry as GGeometry}; use geo_types::{ Coord, Geometry, GeometryCollection, LineString, MultiLineString, MultiPoint, MultiPolygon, - Point, Polygon, + Point, Polygon, Triangle, }; use std::convert::TryInto; @@ -374,6 +380,16 @@ mod test { assert!(geos_collection.contains(&geos_polygon_b).unwrap()); } + #[test] + fn unsupported_geometry_type_test() { + let tri = Triangle::new( + Coord::from((0., 0.)), + Coord::from((3., 5.)), + Coord::from((3., 0.)), + ); + assert!(GGeometry::try_from(Geometry::Triangle(tri)).is_err()); + } + #[test] fn incorrect_polygon_not_closed() { // even if the polygon is not closed we can convert it to geos (we close it) From 7b10484b82cf19769bd226d192e9293dcc4d7b3a Mon Sep 17 00:00:00 2001 From: Jake Low Date: Tue, 7 Jan 2025 16:18:19 -0800 Subject: [PATCH 3/3] Fix typo in TryFrom error message --- src/from_geo.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/from_geo.rs b/src/from_geo.rs index 2b94536..8984e72 100644 --- a/src/from_geo.rs +++ b/src/from_geo.rs @@ -239,7 +239,7 @@ impl<'a, 'b> TryFrom<&'a Geometry> for GGeometry { Geometry::GeometryCollection(inner) => GGeometry::try_from(inner), // GEOS has equivalents of the types below, but they aren't subclasses of geos::Geometry Geometry::Triangle(_) => Err(Error::ConversionError( - "Cannot convert Triange to GEOS Geometry".to_string(), + "Cannot convert Triangle to GEOS Geometry".to_string(), )), Geometry::Rect(_) => Err(Error::ConversionError( "Cannot convert Rect to GEOS Geometry".to_string(),