diff --git a/src/from_geo.rs b/src/from_geo.rs index 79644a7..2b94536 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,70 @@ 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(_) => 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(), + )), + } + } +} + +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, Triangle, + }; use std::convert::TryInto; fn coords(tuples: Vec<(f64, f64)>) -> Vec> { @@ -282,6 +344,52 @@ 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 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)