From fca637e987a50d87b17e5676e0771dfe07cb0616 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 25 Oct 2024 00:24:31 -0400 Subject: [PATCH 01/11] Implement `geo_traits` for `geojson` types. --- Cargo.toml | 2 + src/geo_traits_impl/coord.rs | 52 ++++++ src/geo_traits_impl/geometry.rs | 174 +++++++++++++++++++++ src/geo_traits_impl/geometry_collection.rs | 62 ++++++++ src/geo_traits_impl/line_string.rs | 59 +++++++ src/geo_traits_impl/mod.rs | 51 ++++++ src/geo_traits_impl/multi_line_string.rs | 63 ++++++++ src/geo_traits_impl/multi_point.rs | 59 +++++++ src/geo_traits_impl/multi_polygon.rs | 63 ++++++++ src/geo_traits_impl/point.rs | 34 ++++ src/geo_traits_impl/polygon.rs | 67 ++++++++ src/lib.rs | 2 + 12 files changed, 688 insertions(+) create mode 100644 src/geo_traits_impl/coord.rs create mode 100644 src/geo_traits_impl/geometry.rs create mode 100644 src/geo_traits_impl/geometry_collection.rs create mode 100644 src/geo_traits_impl/line_string.rs create mode 100644 src/geo_traits_impl/mod.rs create mode 100644 src/geo_traits_impl/multi_line_string.rs create mode 100644 src/geo_traits_impl/multi_point.rs create mode 100644 src/geo_traits_impl/multi_polygon.rs create mode 100644 src/geo_traits_impl/point.rs create mode 100644 src/geo_traits_impl/polygon.rs diff --git a/Cargo.toml b/Cargo.toml index 4634dd1..daada0b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,8 @@ serde_json = "~1.0" geo-types = { version = "0.7.13", features = ["serde"], optional = true } thiserror = "1.0.20" log = "0.4.17" +geo-traits = { git = "https://github.com/kylebarron/geo/", branch = "kyle/geo-traits-crate" } +bytemuck = { version = "1", features = ["derive"] } [dev-dependencies] num-traits = "0.2" diff --git a/src/geo_traits_impl/coord.rs b/src/geo_traits_impl/coord.rs new file mode 100644 index 0000000..943d62a --- /dev/null +++ b/src/geo_traits_impl/coord.rs @@ -0,0 +1,52 @@ +use super::PointType; +use geo_traits::{CoordTrait, Dimensions}; + +impl geo_traits::CoordTrait for PointType { + type T = f64; + + fn dim(&self) -> Dimensions { + match self.0.len() { + 0 | 1 => panic!("Position must have at least 2 dimensions"), + 2 => Dimensions::Xy, + 3 => Dimensions::Xyz, + _ => Dimensions::Unknown(self.0.len()), + } + } + + fn x(&self) -> Self::T { + self.0[0] + } + + fn y(&self) -> Self::T { + self.0[1] + } + + fn nth_unchecked(&self, n: usize) -> Self::T { + self.0[n] + } +} + +impl geo_traits::CoordTrait for &PointType { + type T = f64; + + fn dim(&self) -> Dimensions { + match self.0.len() { + 0 | 1 => panic!("Position must have at least 2 dimensions"), + 2 => Dimensions::Xy, + 3 => Dimensions::Xyz, + _ => Dimensions::Unknown(self.0.len()), + } + } + + fn x(&self) -> Self::T { + self.0[0] + } + + fn y(&self) -> Self::T { + self.0[1] + } + + fn nth_unchecked(&self, n: usize) -> Self::T { + self.0[n] + } +} diff --git a/src/geo_traits_impl/geometry.rs b/src/geo_traits_impl/geometry.rs new file mode 100644 index 0000000..b63f57d --- /dev/null +++ b/src/geo_traits_impl/geometry.rs @@ -0,0 +1,174 @@ +use super::{ + GeometryCollectionType, LineStringType, MultiLineStringType, MultiPointType, MultiPolygonType, + PointType, PolygonType, +}; +use bytemuck::TransparentWrapper; +use geo_traits::{ + Dimensions, GeometryCollectionTrait, LineStringTrait, MultiLineStringTrait, MultiPointTrait, + MultiPolygonTrait, PointTrait, PolygonTrait, UnimplementedLine, UnimplementedRect, + UnimplementedTriangle, +}; + +impl geo_traits::GeometryTrait for crate::Value { + type T = f64; + type PointType<'a> = PointType; + type LineStringType<'a> = LineStringType; + type PolygonType<'a> = PolygonType; + type MultiPointType<'a> = MultiPointType; + type MultiLineStringType<'a> = MultiLineStringType; + type MultiPolygonType<'a> = MultiPolygonType; + type GeometryCollectionType<'a> = GeometryCollectionType; + type RectType<'a> = UnimplementedRect; + type TriangleType<'a> = UnimplementedTriangle; + type LineType<'a> = UnimplementedLine; + + fn as_type( + &self, + ) -> geo_traits::GeometryType< + '_, + Self::PointType<'_>, + Self::LineStringType<'_>, + Self::PolygonType<'_>, + Self::MultiPointType<'_>, + Self::MultiLineStringType<'_>, + Self::MultiPolygonType<'_>, + Self::GeometryCollectionType<'_>, + Self::RectType<'_>, + Self::TriangleType<'_>, + Self::LineType<'_>, + > { + match self { + crate::Value::Point(p) => geo_traits::GeometryType::Point(PointType::wrap_ref(p)), + crate::Value::LineString(ls) => { + geo_traits::GeometryType::LineString(LineStringType::wrap_ref(ls)) + } + crate::Value::Polygon(p) => geo_traits::GeometryType::Polygon(PolygonType::wrap_ref(p)), + crate::Value::MultiPoint(mp) => { + geo_traits::GeometryType::MultiPoint(MultiPointType::wrap_ref(mp)) + } + crate::Value::MultiLineString(mls) => { + geo_traits::GeometryType::MultiLineString(MultiLineStringType::wrap_ref(mls)) + } + crate::Value::MultiPolygon(mp) => { + geo_traits::GeometryType::MultiPolygon(MultiPolygonType::wrap_ref(mp)) + } + crate::Value::GeometryCollection(gc) => { + geo_traits::GeometryType::GeometryCollection(GeometryCollectionType::wrap_ref(gc)) + } + } + } + + fn dim(&self) -> Dimensions { + match self { + crate::Value::Point(ref p) => PointType::wrap_ref(p).dim(), + crate::Value::LineString(ref ls) => LineStringType::wrap_ref(ls).dim(), + crate::Value::Polygon(ref p) => PolygonType::wrap_ref(p).dim(), + crate::Value::MultiPoint(ref mp) => MultiPointType::wrap_ref(mp).dim(), + crate::Value::MultiLineString(ref mls) => MultiLineStringType::wrap_ref(mls).dim(), + crate::Value::MultiPolygon(ref mp) => MultiPolygonType::wrap_ref(mp).dim(), + crate::Value::GeometryCollection(ref gc) => GeometryCollectionType::wrap_ref(gc).dim(), + } + } +} + +impl geo_traits::GeometryTrait for crate::Geometry { + type T = f64; + type PointType<'b> = PointType; + type LineStringType<'b> = LineStringType; + type PolygonType<'b> = PolygonType; + type MultiPointType<'b> = MultiPointType; + type MultiLineStringType<'b> = MultiLineStringType; + type MultiPolygonType<'b> = MultiPolygonType; + type GeometryCollectionType<'b> = GeometryCollectionType; + type RectType<'b> = UnimplementedRect; + type TriangleType<'b> = UnimplementedTriangle; + type LineType<'b> = UnimplementedLine; + + fn dim(&self) -> Dimensions { + self.value.dim() + } + + fn as_type( + &self, + ) -> geo_traits::GeometryType< + '_, + Self::PointType<'_>, + Self::LineStringType<'_>, + Self::PolygonType<'_>, + Self::MultiPointType<'_>, + Self::MultiLineStringType<'_>, + Self::MultiPolygonType<'_>, + Self::GeometryCollectionType<'_>, + Self::RectType<'_>, + Self::TriangleType<'_>, + Self::LineType<'_>, + > { + self.value.as_type() + } +} + +impl geo_traits::GeometryTrait for &crate::Geometry { + type T = f64; + type PointType<'b> + = PointType + where + Self: 'b; + type LineStringType<'b> + = LineStringType + where + Self: 'b; + type PolygonType<'b> + = PolygonType + where + Self: 'b; + type MultiPointType<'b> + = MultiPointType + where + Self: 'b; + type MultiLineStringType<'b> + = MultiLineStringType + where + Self: 'b; + type MultiPolygonType<'b> + = MultiPolygonType + where + Self: 'b; + type GeometryCollectionType<'b> + = GeometryCollectionType + where + Self: 'b; + type RectType<'b> + = UnimplementedRect + where + Self: 'b; + type TriangleType<'b> + = UnimplementedTriangle + where + Self: 'b; + type LineType<'b> + = UnimplementedLine + where + Self: 'b; + + fn as_type( + &self, + ) -> geo_traits::GeometryType< + '_, + Self::PointType<'_>, + Self::LineStringType<'_>, + Self::PolygonType<'_>, + Self::MultiPointType<'_>, + Self::MultiLineStringType<'_>, + Self::MultiPolygonType<'_>, + Self::GeometryCollectionType<'_>, + Self::RectType<'_>, + Self::TriangleType<'_>, + Self::LineType<'_>, + > { + self.value.as_type() + } + + fn dim(&self) -> Dimensions { + self.value.dim() + } +} diff --git a/src/geo_traits_impl/geometry_collection.rs b/src/geo_traits_impl/geometry_collection.rs new file mode 100644 index 0000000..ea49249 --- /dev/null +++ b/src/geo_traits_impl/geometry_collection.rs @@ -0,0 +1,62 @@ +use super::GeometryCollectionType; +use geo_traits::{Dimensions, GeometryTrait}; + +impl geo_traits::GeometryCollectionTrait for GeometryCollectionType { + type T = f64; + type GeometryType<'b> + = &'b crate::Geometry + where + Self: 'b; + + fn dim(&self) -> Dimensions { + self.geometry(0).unwrap().dim() + } + + fn geometries( + &self, + ) -> impl DoubleEndedIterator + ExactSizeIterator> { + self.0.iter() + } + + fn geometry(&self, i: usize) -> Option> { + self.0.get(i) + } + + unsafe fn geometry_unchecked(&self, i: usize) -> Self::GeometryType<'_> { + self.0.get_unchecked(i) + } + + fn num_geometries(&self) -> usize { + self.0.len() + } +} + +impl<'a> geo_traits::GeometryCollectionTrait for &'a GeometryCollectionType { + type T = f64; + type GeometryType<'b> + = &'b crate::Geometry + where + Self: 'b; + + fn dim(&self) -> Dimensions { + unimplemented!() + } + + fn geometries( + &self, + ) -> impl DoubleEndedIterator + ExactSizeIterator> { + self.0.iter() + } + + fn geometry(&self, i: usize) -> Option> { + self.0.get(i) + } + + unsafe fn geometry_unchecked(&self, i: usize) -> Self::GeometryType<'_> { + self.0.get_unchecked(i) + } + + fn num_geometries(&self) -> usize { + self.0.len() + } +} diff --git a/src/geo_traits_impl/line_string.rs b/src/geo_traits_impl/line_string.rs new file mode 100644 index 0000000..bd8dd06 --- /dev/null +++ b/src/geo_traits_impl/line_string.rs @@ -0,0 +1,59 @@ +use super::{LineStringType, PointType}; +use bytemuck::TransparentWrapper; +use geo_traits::{Dimensions, LineStringTrait, PointTrait}; + +impl LineStringTrait for LineStringType { + type T = f64; + type CoordType<'b> + = &'b PointType + where + Self: 'b; + + fn num_coords(&self) -> usize { + self.0.len() + } + + fn coord(&self, i: usize) -> Option> { + Some(PointType::wrap_ref(&self.0[i])) + } + + unsafe fn coord_unchecked(&self, i: usize) -> Self::CoordType<'_> { + self.coord(i).unwrap() + } + + fn coords(&self) -> impl DoubleEndedIterator + ExactSizeIterator> { + self.0.iter().map(PointType::wrap_ref) + } + + fn dim(&self) -> Dimensions { + self.coord(0).unwrap().dim() // TODO: is this okay? + } +} + +impl<'a> geo_traits::LineStringTrait for &'a LineStringType { + type T = f64; + type CoordType<'b> + = &'b PointType + where + Self: 'b; + + fn num_coords(&self) -> usize { + self.0.len() + } + + fn coord(&self, i: usize) -> Option> { + Some(PointType::wrap_ref(&self.0[i])) + } + + unsafe fn coord_unchecked(&self, i: usize) -> Self::CoordType<'_> { + self.coord(i).unwrap() + } + + fn coords(&self) -> impl DoubleEndedIterator + ExactSizeIterator> { + self.0.iter().map(PointType::wrap_ref) + } + + fn dim(&self) -> Dimensions { + self.coord(0).unwrap().dim() + } +} diff --git a/src/geo_traits_impl/mod.rs b/src/geo_traits_impl/mod.rs new file mode 100644 index 0000000..5f667da --- /dev/null +++ b/src/geo_traits_impl/mod.rs @@ -0,0 +1,51 @@ +use bytemuck::TransparentWrapper; +use geo_traits::{ + CoordTrait, Dimensions, GeometryCollectionTrait, GeometryTrait, LineStringTrait, + MultiLineStringTrait, MultiPointTrait, MultiPolygonTrait, PolygonTrait, +}; +use geo_traits::{UnimplementedLine, UnimplementedRect, UnimplementedTriangle}; + +mod coord; +mod geometry; +mod geometry_collection; +mod line_string; +mod multi_line_string; +mod multi_point; +mod multi_polygon; +mod point; +mod polygon; + +#[derive(bytemuck::TransparentWrapper)] +#[repr(transparent)] +#[doc(hidden)] +pub struct PointType(crate::Position); + +#[derive(bytemuck::TransparentWrapper)] +#[repr(transparent)] +#[doc(hidden)] +pub struct LineStringType(crate::LineStringType); + +#[derive(bytemuck::TransparentWrapper)] +#[repr(transparent)] +#[doc(hidden)] +pub struct PolygonType(crate::PolygonType); + +#[derive(bytemuck::TransparentWrapper)] +#[repr(transparent)] +#[doc(hidden)] +pub struct MultiPointType(Vec); + +#[derive(bytemuck::TransparentWrapper)] +#[repr(transparent)] +#[doc(hidden)] +pub struct MultiLineStringType(Vec); + +#[derive(bytemuck::TransparentWrapper)] +#[repr(transparent)] +#[doc(hidden)] +pub struct MultiPolygonType(Vec); + +#[derive(bytemuck::TransparentWrapper)] +#[repr(transparent)] +#[doc(hidden)] +pub struct GeometryCollectionType(Vec); diff --git a/src/geo_traits_impl/multi_line_string.rs b/src/geo_traits_impl/multi_line_string.rs new file mode 100644 index 0000000..c3a2cfb --- /dev/null +++ b/src/geo_traits_impl/multi_line_string.rs @@ -0,0 +1,63 @@ +use super::{LineStringType, MultiLineStringType}; +use bytemuck::TransparentWrapper; +use geo_traits::{Dimensions, LineStringTrait, MultiLineStringTrait}; + +impl geo_traits::MultiLineStringTrait for MultiLineStringType { + type T = f64; + type LineStringType<'b> + = &'b LineStringType + where + Self: 'b; + + fn num_line_strings(&self) -> usize { + self.0.len() + } + + fn dim(&self) -> Dimensions { + self.line_string(0).unwrap().dim() + } + + fn line_string(&self, i: usize) -> Option> { + self.0.get(i).map(LineStringType::wrap_ref) + } + + unsafe fn line_string_unchecked(&self, i: usize) -> Self::LineStringType<'_> { + LineStringType::wrap_ref(self.0.get_unchecked(i)) + } + + fn line_strings( + &self, + ) -> impl DoubleEndedIterator + ExactSizeIterator> { + self.0.iter().map(LineStringType::wrap_ref) + } +} + +impl<'a> geo_traits::MultiLineStringTrait for &'a MultiLineStringType { + type T = f64; + type LineStringType<'b> + = &'b LineStringType + where + Self: 'b; + + fn num_line_strings(&self) -> usize { + self.0.len() + } + + fn dim(&self) -> Dimensions { + self.line_string(0).unwrap().dim() + } + + fn line_string(&self, i: usize) -> Option> { + self.0.get(i).map(LineStringType::wrap_ref) + } + + unsafe fn line_string_unchecked(&self, i: usize) -> Self::LineStringType<'_> { + LineStringType::wrap_ref(self.0.get_unchecked(i)) + } + + fn line_strings( + &self, + ) -> impl DoubleEndedIterator + ExactSizeIterator> { + self.0.iter().map(LineStringType::wrap_ref) + } +} diff --git a/src/geo_traits_impl/multi_point.rs b/src/geo_traits_impl/multi_point.rs new file mode 100644 index 0000000..e6e6cb7 --- /dev/null +++ b/src/geo_traits_impl/multi_point.rs @@ -0,0 +1,59 @@ +use super::{MultiPointType, PointType}; +use bytemuck::TransparentWrapper; +use geo_traits::{Dimensions, PointTrait}; + +impl geo_traits::MultiPointTrait for MultiPointType { + type T = f64; + type PointType<'b> + = &'b PointType + where + Self: 'b; + + fn num_points(&self) -> usize { + self.0.len() + } + + fn dim(&self) -> Dimensions { + self.point(0).unwrap().dim() + } + + fn point(&self, i: usize) -> Option> { + self.0.get(i).map(PointType::wrap_ref) + } + + unsafe fn point_unchecked(&self, i: usize) -> Self::PointType<'_> { + PointType::wrap_ref(self.0.get_unchecked(i)) + } + + fn points(&self) -> impl DoubleEndedIterator + ExactSizeIterator> { + self.0.iter().map(PointType::wrap_ref) + } +} + +impl<'a> geo_traits::MultiPointTrait for &'a MultiPointType { + type T = f64; + type PointType<'b> + = &'b PointType + where + Self: 'b; + + fn num_points(&self) -> usize { + self.0.len() + } + + fn dim(&self) -> Dimensions { + self.point(0).unwrap().dim() // TODO: is this okay? + } + + fn point(&self, i: usize) -> Option> { + self.0.get(i).map(PointType::wrap_ref) + } + + unsafe fn point_unchecked(&self, i: usize) -> Self::PointType<'_> { + PointType::wrap_ref(self.0.get_unchecked(i)) + } + + fn points(&self) -> impl DoubleEndedIterator + ExactSizeIterator> { + self.0.iter().map(PointType::wrap_ref) + } +} diff --git a/src/geo_traits_impl/multi_polygon.rs b/src/geo_traits_impl/multi_polygon.rs new file mode 100644 index 0000000..31a3592 --- /dev/null +++ b/src/geo_traits_impl/multi_polygon.rs @@ -0,0 +1,63 @@ +use super::{MultiPolygonType, PolygonType}; +use bytemuck::TransparentWrapper; +use geo_traits::{Dimensions, PolygonTrait}; + +impl geo_traits::MultiPolygonTrait for MultiPolygonType { + type T = f64; + type PolygonType<'b> + = &'b PolygonType + where + Self: 'b; + + fn num_polygons(&self) -> usize { + self.0.len() + } + + fn dim(&self) -> Dimensions { + self.polygon(0).unwrap().dim() + } + + fn polygon(&self, i: usize) -> Option> { + self.0.get(i).map(PolygonType::wrap_ref) + } + + unsafe fn polygon_unchecked(&self, i: usize) -> Self::PolygonType<'_> { + PolygonType::wrap_ref(self.0.get_unchecked(i)) + } + + fn polygons( + &self, + ) -> impl DoubleEndedIterator + ExactSizeIterator> { + self.0.iter().map(PolygonType::wrap_ref) + } +} + +impl<'a> geo_traits::MultiPolygonTrait for &'a MultiPolygonType { + type T = f64; + type PolygonType<'b> + = &'b PolygonType + where + Self: 'b; + + fn num_polygons(&self) -> usize { + self.0.len() + } + + fn dim(&self) -> Dimensions { + self.polygon(0).unwrap().dim() + } + + fn polygon(&self, i: usize) -> Option> { + self.0.get(i).map(PolygonType::wrap_ref) + } + + unsafe fn polygon_unchecked(&self, i: usize) -> Self::PolygonType<'_> { + PolygonType::wrap_ref(self.0.get_unchecked(i)) + } + + fn polygons( + &self, + ) -> impl DoubleEndedIterator + ExactSizeIterator> { + self.0.iter().map(PolygonType::wrap_ref) + } +} diff --git a/src/geo_traits_impl/point.rs b/src/geo_traits_impl/point.rs new file mode 100644 index 0000000..6a6f68d --- /dev/null +++ b/src/geo_traits_impl/point.rs @@ -0,0 +1,34 @@ +use super::PointType; +use geo_traits::{Dimensions, PointTrait}; + +impl PointTrait for PointType { + type T = f64; + type CoordType<'b> + = &'b PointType + where + Self: 'b; + + fn coord(&self) -> Option> { + Some(self) + } + + fn dim(&self) -> Dimensions { + ::dim(self) + } +} + +impl geo_traits::PointTrait for &PointType { + type T = f64; + type CoordType<'b> + = &'b PointType + where + Self: 'b; + + fn coord(&self) -> Option> { + Some(self) + } + + fn dim(&self) -> Dimensions { + ::dim(self) + } +} diff --git a/src/geo_traits_impl/polygon.rs b/src/geo_traits_impl/polygon.rs new file mode 100644 index 0000000..553a622 --- /dev/null +++ b/src/geo_traits_impl/polygon.rs @@ -0,0 +1,67 @@ +use super::{LineStringType, PolygonType}; +use bytemuck::TransparentWrapper; +use geo_traits::{Dimensions, LineStringTrait, PolygonTrait}; + +impl geo_traits::PolygonTrait for PolygonType { + type T = f64; + type RingType<'b> + = &'b LineStringType + where + Self: 'b; + + fn exterior(&self) -> Option> { + self.0.first().map(LineStringType::wrap_ref) + } + + fn num_interiors(&self) -> usize { + self.0.len() - 1 + } + + fn interior(&self, i: usize) -> Option> { + self.0.get(i + 1).map(LineStringType::wrap_ref) + } + + fn dim(&self) -> Dimensions { + self.exterior().unwrap().dim() + } + + unsafe fn interior_unchecked(&self, i: usize) -> Self::RingType<'_> { + LineStringType::wrap_ref(self.0.get_unchecked(i + 1)) + } + + fn interiors(&self) -> impl DoubleEndedIterator + ExactSizeIterator> { + self.0.iter().skip(1).map(LineStringType::wrap_ref) + } +} + +impl<'a> geo_traits::PolygonTrait for &'a PolygonType { + type T = f64; + type RingType<'b> + = &'b LineStringType + where + Self: 'b; + + fn exterior(&self) -> Option> { + self.0.first().map(LineStringType::wrap_ref) + } + + fn num_interiors(&self) -> usize { + self.0.len() - 1 + } + + fn interior(&self, i: usize) -> Option> { + self.0.get(i + 1).map(LineStringType::wrap_ref) + } + + fn dim(&self) -> Dimensions { + self.exterior().unwrap().dim() + } + + unsafe fn interior_unchecked(&self, i: usize) -> Self::RingType<'_> { + LineStringType::wrap_ref(self.0.get_unchecked(i + 1)) + } + + fn interiors(&self) -> impl DoubleEndedIterator + ExactSizeIterator> { + self.0.iter().skip(1).map(LineStringType::wrap_ref) + } +} diff --git a/src/lib.rs b/src/lib.rs index f7da524..7370e8d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -408,6 +408,8 @@ pub use crate::errors::{Error, Result}; #[cfg(feature = "geo-types")] mod conversion; +mod geo_traits_impl; + /// Build your struct from GeoJSON using [`serde`] pub mod de; From e6461ef22ff66d76ffb8c27bc24fda433044a1b6 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 25 Oct 2024 00:26:17 -0400 Subject: [PATCH 02/11] unused imports --- src/geo_traits_impl/mod.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/geo_traits_impl/mod.rs b/src/geo_traits_impl/mod.rs index 5f667da..df8b47f 100644 --- a/src/geo_traits_impl/mod.rs +++ b/src/geo_traits_impl/mod.rs @@ -1,10 +1,3 @@ -use bytemuck::TransparentWrapper; -use geo_traits::{ - CoordTrait, Dimensions, GeometryCollectionTrait, GeometryTrait, LineStringTrait, - MultiLineStringTrait, MultiPointTrait, MultiPolygonTrait, PolygonTrait, -}; -use geo_traits::{UnimplementedLine, UnimplementedRect, UnimplementedTriangle}; - mod coord; mod geometry; mod geometry_collection; From 6f5b520a86154ac6a63235288d61b4f8ef77714b Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 25 Oct 2024 00:27:14 -0400 Subject: [PATCH 03/11] unneeded doc(hidden) --- src/geo_traits_impl/mod.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/geo_traits_impl/mod.rs b/src/geo_traits_impl/mod.rs index df8b47f..9a2cee5 100644 --- a/src/geo_traits_impl/mod.rs +++ b/src/geo_traits_impl/mod.rs @@ -10,35 +10,28 @@ mod polygon; #[derive(bytemuck::TransparentWrapper)] #[repr(transparent)] -#[doc(hidden)] pub struct PointType(crate::Position); #[derive(bytemuck::TransparentWrapper)] #[repr(transparent)] -#[doc(hidden)] pub struct LineStringType(crate::LineStringType); #[derive(bytemuck::TransparentWrapper)] #[repr(transparent)] -#[doc(hidden)] pub struct PolygonType(crate::PolygonType); #[derive(bytemuck::TransparentWrapper)] #[repr(transparent)] -#[doc(hidden)] pub struct MultiPointType(Vec); #[derive(bytemuck::TransparentWrapper)] #[repr(transparent)] -#[doc(hidden)] pub struct MultiLineStringType(Vec); #[derive(bytemuck::TransparentWrapper)] #[repr(transparent)] -#[doc(hidden)] pub struct MultiPolygonType(Vec); #[derive(bytemuck::TransparentWrapper)] #[repr(transparent)] -#[doc(hidden)] pub struct GeometryCollectionType(Vec); From 403a089ffad56bb2ee7421084458e5042f4426dd Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 25 Oct 2024 00:31:49 -0400 Subject: [PATCH 04/11] dry --- src/geo_traits_impl/coord.rs | 13 ++-- src/geo_traits_impl/geometry.rs | 70 +++++++++++++++++++++- src/geo_traits_impl/geometry_collection.rs | 10 ++-- src/geo_traits_impl/line_string.rs | 10 ++-- src/geo_traits_impl/multi_line_string.rs | 10 ++-- src/geo_traits_impl/multi_point.rs | 10 ++-- src/geo_traits_impl/multi_polygon.rs | 10 ++-- src/geo_traits_impl/point.rs | 4 +- src/geo_traits_impl/polygon.rs | 12 ++-- 9 files changed, 105 insertions(+), 44 deletions(-) diff --git a/src/geo_traits_impl/coord.rs b/src/geo_traits_impl/coord.rs index 943d62a..10df32e 100644 --- a/src/geo_traits_impl/coord.rs +++ b/src/geo_traits_impl/coord.rs @@ -30,23 +30,18 @@ impl geo_traits::CoordTrait for &PointType { type T = f64; fn dim(&self) -> Dimensions { - match self.0.len() { - 0 | 1 => panic!("Position must have at least 2 dimensions"), - 2 => Dimensions::Xy, - 3 => Dimensions::Xyz, - _ => Dimensions::Unknown(self.0.len()), - } + PointType::dim(self) } fn x(&self) -> Self::T { - self.0[0] + PointType::x(self) } fn y(&self) -> Self::T { - self.0[1] + PointType::y(self) } fn nth_unchecked(&self, n: usize) -> Self::T { - self.0[n] + PointType::nth_unchecked(self, n) } } diff --git a/src/geo_traits_impl/geometry.rs b/src/geo_traits_impl/geometry.rs index b63f57d..f2b2a47 100644 --- a/src/geo_traits_impl/geometry.rs +++ b/src/geo_traits_impl/geometry.rs @@ -71,6 +71,72 @@ impl geo_traits::GeometryTrait for crate::Value { } } +impl geo_traits::GeometryTrait for &crate::Value { + type T = f64; + type PointType<'b> + = PointType + where + Self: 'b; + type LineStringType<'b> + = LineStringType + where + Self: 'b; + type PolygonType<'b> + = PolygonType + where + Self: 'b; + type MultiPointType<'b> + = MultiPointType + where + Self: 'b; + type MultiLineStringType<'b> + = MultiLineStringType + where + Self: 'b; + type MultiPolygonType<'b> + = MultiPolygonType + where + Self: 'b; + type GeometryCollectionType<'b> + = GeometryCollectionType + where + Self: 'b; + type RectType<'b> + = UnimplementedRect + where + Self: 'b; + type TriangleType<'b> + = UnimplementedTriangle + where + Self: 'b; + type LineType<'b> + = UnimplementedLine + where + Self: 'b; + + fn dim(&self) -> Dimensions { + crate::Value::dim(self) + } + + fn as_type( + &self, + ) -> geo_traits::GeometryType< + '_, + Self::PointType<'_>, + Self::LineStringType<'_>, + Self::PolygonType<'_>, + Self::MultiPointType<'_>, + Self::MultiLineStringType<'_>, + Self::MultiPolygonType<'_>, + Self::GeometryCollectionType<'_>, + Self::RectType<'_>, + Self::TriangleType<'_>, + Self::LineType<'_>, + > { + crate::Value::as_type(self) + } +} + impl geo_traits::GeometryTrait for crate::Geometry { type T = f64; type PointType<'b> = PointType; @@ -165,10 +231,10 @@ impl geo_traits::GeometryTrait for &crate::Geometry { Self::TriangleType<'_>, Self::LineType<'_>, > { - self.value.as_type() + crate::Geometry::as_type(self) } fn dim(&self) -> Dimensions { - self.value.dim() + crate::Geometry::dim(self) } } diff --git a/src/geo_traits_impl/geometry_collection.rs b/src/geo_traits_impl/geometry_collection.rs index ea49249..53ab9fd 100644 --- a/src/geo_traits_impl/geometry_collection.rs +++ b/src/geo_traits_impl/geometry_collection.rs @@ -39,24 +39,24 @@ impl<'a> geo_traits::GeometryCollectionTrait for &'a GeometryCollectionType { Self: 'b; fn dim(&self) -> Dimensions { - unimplemented!() + GeometryCollectionType::dim(self) } fn geometries( &self, ) -> impl DoubleEndedIterator + ExactSizeIterator> { - self.0.iter() + GeometryCollectionType::geometries(self) } fn geometry(&self, i: usize) -> Option> { - self.0.get(i) + GeometryCollectionType::geometry(self, i) } unsafe fn geometry_unchecked(&self, i: usize) -> Self::GeometryType<'_> { - self.0.get_unchecked(i) + GeometryCollectionType::geometry_unchecked(self, i) } fn num_geometries(&self) -> usize { - self.0.len() + GeometryCollectionType::num_geometries(self) } } diff --git a/src/geo_traits_impl/line_string.rs b/src/geo_traits_impl/line_string.rs index bd8dd06..5f3ec0c 100644 --- a/src/geo_traits_impl/line_string.rs +++ b/src/geo_traits_impl/line_string.rs @@ -38,22 +38,22 @@ impl<'a> geo_traits::LineStringTrait for &'a LineStringType { Self: 'b; fn num_coords(&self) -> usize { - self.0.len() + LineStringType::num_coords(self) } fn coord(&self, i: usize) -> Option> { - Some(PointType::wrap_ref(&self.0[i])) + LineStringType::coord(self, i) } unsafe fn coord_unchecked(&self, i: usize) -> Self::CoordType<'_> { - self.coord(i).unwrap() + LineStringType::coord_unchecked(self, i) } fn coords(&self) -> impl DoubleEndedIterator + ExactSizeIterator> { - self.0.iter().map(PointType::wrap_ref) + LineStringType::coords(self) } fn dim(&self) -> Dimensions { - self.coord(0).unwrap().dim() + LineStringType::dim(self) } } diff --git a/src/geo_traits_impl/multi_line_string.rs b/src/geo_traits_impl/multi_line_string.rs index c3a2cfb..29b59f7 100644 --- a/src/geo_traits_impl/multi_line_string.rs +++ b/src/geo_traits_impl/multi_line_string.rs @@ -40,24 +40,24 @@ impl<'a> geo_traits::MultiLineStringTrait for &'a MultiLineStringType { Self: 'b; fn num_line_strings(&self) -> usize { - self.0.len() + MultiLineStringType::num_line_strings(self) } fn dim(&self) -> Dimensions { - self.line_string(0).unwrap().dim() + MultiLineStringType::dim(self) } fn line_string(&self, i: usize) -> Option> { - self.0.get(i).map(LineStringType::wrap_ref) + MultiLineStringType::line_string(self, i) } unsafe fn line_string_unchecked(&self, i: usize) -> Self::LineStringType<'_> { - LineStringType::wrap_ref(self.0.get_unchecked(i)) + MultiLineStringType::line_string_unchecked(self, i) } fn line_strings( &self, ) -> impl DoubleEndedIterator + ExactSizeIterator> { - self.0.iter().map(LineStringType::wrap_ref) + MultiLineStringType::line_strings(self) } } diff --git a/src/geo_traits_impl/multi_point.rs b/src/geo_traits_impl/multi_point.rs index e6e6cb7..5780986 100644 --- a/src/geo_traits_impl/multi_point.rs +++ b/src/geo_traits_impl/multi_point.rs @@ -38,22 +38,22 @@ impl<'a> geo_traits::MultiPointTrait for &'a MultiPointType { Self: 'b; fn num_points(&self) -> usize { - self.0.len() + MultiPointType::num_points(self) } fn dim(&self) -> Dimensions { - self.point(0).unwrap().dim() // TODO: is this okay? + MultiPointType::dim(self) } fn point(&self, i: usize) -> Option> { - self.0.get(i).map(PointType::wrap_ref) + MultiPointType::point(self, i) } unsafe fn point_unchecked(&self, i: usize) -> Self::PointType<'_> { - PointType::wrap_ref(self.0.get_unchecked(i)) + MultiPointType::point_unchecked(self, i) } fn points(&self) -> impl DoubleEndedIterator + ExactSizeIterator> { - self.0.iter().map(PointType::wrap_ref) + MultiPointType::points(self) } } diff --git a/src/geo_traits_impl/multi_polygon.rs b/src/geo_traits_impl/multi_polygon.rs index 31a3592..5b85437 100644 --- a/src/geo_traits_impl/multi_polygon.rs +++ b/src/geo_traits_impl/multi_polygon.rs @@ -40,24 +40,24 @@ impl<'a> geo_traits::MultiPolygonTrait for &'a MultiPolygonType { Self: 'b; fn num_polygons(&self) -> usize { - self.0.len() + MultiPolygonType::num_polygons(self) } fn dim(&self) -> Dimensions { - self.polygon(0).unwrap().dim() + MultiPolygonType::dim(self) } fn polygon(&self, i: usize) -> Option> { - self.0.get(i).map(PolygonType::wrap_ref) + MultiPolygonType::polygon(self, i) } unsafe fn polygon_unchecked(&self, i: usize) -> Self::PolygonType<'_> { - PolygonType::wrap_ref(self.0.get_unchecked(i)) + MultiPolygonType::polygon_unchecked(self, i) } fn polygons( &self, ) -> impl DoubleEndedIterator + ExactSizeIterator> { - self.0.iter().map(PolygonType::wrap_ref) + MultiPolygonType::polygons(self) } } diff --git a/src/geo_traits_impl/point.rs b/src/geo_traits_impl/point.rs index 6a6f68d..e6bc236 100644 --- a/src/geo_traits_impl/point.rs +++ b/src/geo_traits_impl/point.rs @@ -25,10 +25,10 @@ impl geo_traits::PointTrait for &PointType { Self: 'b; fn coord(&self) -> Option> { - Some(self) + PointType::coord(self) } fn dim(&self) -> Dimensions { - ::dim(self) + PointType::dim(self) } } diff --git a/src/geo_traits_impl/polygon.rs b/src/geo_traits_impl/polygon.rs index 553a622..cd0699a 100644 --- a/src/geo_traits_impl/polygon.rs +++ b/src/geo_traits_impl/polygon.rs @@ -42,26 +42,26 @@ impl<'a> geo_traits::PolygonTrait for &'a PolygonType { Self: 'b; fn exterior(&self) -> Option> { - self.0.first().map(LineStringType::wrap_ref) + PolygonType::exterior(self) } fn num_interiors(&self) -> usize { - self.0.len() - 1 + PolygonType::num_interiors(self) } fn interior(&self, i: usize) -> Option> { - self.0.get(i + 1).map(LineStringType::wrap_ref) + PolygonType::interior(self, i) } fn dim(&self) -> Dimensions { - self.exterior().unwrap().dim() + PolygonType::dim(self) } unsafe fn interior_unchecked(&self, i: usize) -> Self::RingType<'_> { - LineStringType::wrap_ref(self.0.get_unchecked(i + 1)) + PolygonType::interior_unchecked(self, i) } fn interiors(&self) -> impl DoubleEndedIterator + ExactSizeIterator> { - self.0.iter().skip(1).map(LineStringType::wrap_ref) + PolygonType::interiors(self) } } From 0c503b67c36e73eb2380a462a089a89b1f44833b Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 25 Oct 2024 00:40:20 -0400 Subject: [PATCH 05/11] comment --- src/geo_traits_impl/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/geo_traits_impl/mod.rs b/src/geo_traits_impl/mod.rs index 9a2cee5..225a1f5 100644 --- a/src/geo_traits_impl/mod.rs +++ b/src/geo_traits_impl/mod.rs @@ -8,6 +8,10 @@ mod multi_polygon; mod point; mod polygon; +// These structures are needed because we can't implement traits on types like +// `geojson::PointType` because they are just type aliases of raw types like +// `Vec`. + #[derive(bytemuck::TransparentWrapper)] #[repr(transparent)] pub struct PointType(crate::Position); From b74e52b6489066ea0f75ec9f86f8c1bf143fce03 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 27 Oct 2024 15:24:47 -0400 Subject: [PATCH 06/11] make optional; use stable version --- Cargo.toml | 5 +++-- src/lib.rs | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index daada0b..6f3bc3c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,15 +12,16 @@ edition = "2018" [features] default = ["geo-types"] +geo-traits = ["dep:geo-traits", "dep:bytemuck"] [dependencies] serde = { version="~1.0", features = ["derive"] } serde_json = "~1.0" geo-types = { version = "0.7.13", features = ["serde"], optional = true } +geo-traits = { version = "0.1.0", optional = true } +bytemuck = { version = "1", features = ["derive"], optional = true } thiserror = "1.0.20" log = "0.4.17" -geo-traits = { git = "https://github.com/kylebarron/geo/", branch = "kyle/geo-traits-crate" } -bytemuck = { version = "1", features = ["derive"] } [dev-dependencies] num-traits = "0.2" diff --git a/src/lib.rs b/src/lib.rs index 7370e8d..a216085 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -408,6 +408,7 @@ pub use crate::errors::{Error, Result}; #[cfg(feature = "geo-types")] mod conversion; +#[cfg(feature = "geo-traits")] mod geo_traits_impl; /// Build your struct from GeoJSON using [`serde`] From d57de452e36629386cdffc47c3535e5b3329bb6a Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 27 Oct 2024 16:04:40 -0400 Subject: [PATCH 07/11] implement for featurecollection, feature, and geojson --- src/geo_traits_impl/coord.rs | 2 +- src/geo_traits_impl/geometry.rs | 124 +++++++++++++++++++++ src/geo_traits_impl/geometry_collection.rs | 54 +++++++++ src/geo_traits_impl/multi_line_string.rs | 2 +- src/geo_traits_impl/polygon.rs | 2 +- 5 files changed, 181 insertions(+), 3 deletions(-) diff --git a/src/geo_traits_impl/coord.rs b/src/geo_traits_impl/coord.rs index 10df32e..be5f57a 100644 --- a/src/geo_traits_impl/coord.rs +++ b/src/geo_traits_impl/coord.rs @@ -1,5 +1,5 @@ use super::PointType; -use geo_traits::{CoordTrait, Dimensions}; +use geo_traits::Dimensions; impl geo_traits::CoordTrait for PointType { type T = f64; diff --git a/src/geo_traits_impl/geometry.rs b/src/geo_traits_impl/geometry.rs index f2b2a47..31a4458 100644 --- a/src/geo_traits_impl/geometry.rs +++ b/src/geo_traits_impl/geometry.rs @@ -238,3 +238,127 @@ impl geo_traits::GeometryTrait for &crate::Geometry { crate::Geometry::dim(self) } } + +impl geo_traits::GeometryTrait for crate::Feature { + type T = f64; + type PointType<'b> = PointType; + type LineStringType<'b> = LineStringType; + type PolygonType<'b> = PolygonType; + type MultiPointType<'b> = MultiPointType; + type MultiLineStringType<'b> = MultiLineStringType; + type MultiPolygonType<'b> = MultiPolygonType; + type GeometryCollectionType<'b> = GeometryCollectionType; + type RectType<'b> = UnimplementedRect; + type TriangleType<'b> = UnimplementedTriangle; + type LineType<'b> = UnimplementedLine; + + fn as_type( + &self, + ) -> geo_traits::GeometryType< + '_, + Self::PointType<'_>, + Self::LineStringType<'_>, + Self::PolygonType<'_>, + Self::MultiPointType<'_>, + Self::MultiLineStringType<'_>, + Self::MultiPolygonType<'_>, + Self::GeometryCollectionType<'_>, + Self::RectType<'_>, + Self::TriangleType<'_>, + Self::LineType<'_>, + > { + match self.geometry { + Some(ref g) => g.as_type(), + None => panic!("GeoJSON feature has no geometry"), + } + } + + fn dim(&self) -> Dimensions { + match self.geometry { + Some(ref g) => g.dim(), + None => panic!("GeoJSON feature has no geometry"), + } + } +} + +impl geo_traits::GeometryTrait for &crate::Feature { + type T = f64; + type PointType<'b> = PointType where Self: 'b; + type LineStringType<'b> = LineStringType where Self: 'b; + type PolygonType<'b> = PolygonType where Self: 'b; + type MultiPointType<'b> = MultiPointType where Self: 'b; + type MultiLineStringType<'b> = MultiLineStringType where Self: 'b; + type MultiPolygonType<'b> = MultiPolygonType where Self: 'b; + type GeometryCollectionType<'b> = GeometryCollectionType where Self: 'b; + type RectType<'b> = UnimplementedRect where Self: 'b; + type TriangleType<'b> = UnimplementedTriangle where Self: 'b; + type LineType<'b> = UnimplementedLine where Self: 'b; + + fn as_type( + &self, + ) -> geo_traits::GeometryType< + '_, + Self::PointType<'_>, + Self::LineStringType<'_>, + Self::PolygonType<'_>, + Self::MultiPointType<'_>, + Self::MultiLineStringType<'_>, + Self::MultiPolygonType<'_>, + Self::GeometryCollectionType<'_>, + Self::RectType<'_>, + Self::TriangleType<'_>, + Self::LineType<'_>, + > { + crate::Feature::as_type(self) + } + + fn dim(&self) -> Dimensions { + crate::Feature::dim(self) + } +} + +impl geo_traits::GeometryTrait for crate::GeoJson { + type T = f64; + type PointType<'b> = PointType where Self: 'b; + type LineStringType<'b> = LineStringType where Self: 'b; + type PolygonType<'b> = PolygonType where Self: 'b; + type MultiPointType<'b> = MultiPointType where Self: 'b; + type MultiLineStringType<'b> = MultiLineStringType where Self: 'b; + type MultiPolygonType<'b> = MultiPolygonType where Self: 'b; + type GeometryCollectionType<'b> = GeometryCollectionType where Self: 'b; + type RectType<'b> = UnimplementedRect where Self: 'b; + type TriangleType<'b> = UnimplementedTriangle where Self: 'b; + type LineType<'b> = UnimplementedLine where Self: 'b; + + fn dim(&self) -> Dimensions { + match self { + crate::GeoJson::Feature(f) => f.dim(), + crate::GeoJson::FeatureCollection(fc) => fc.dim(), + crate::GeoJson::Geometry(g) => g.dim(), + } + } + + fn as_type( + &self, + ) -> geo_traits::GeometryType< + '_, + Self::PointType<'_>, + Self::LineStringType<'_>, + Self::PolygonType<'_>, + Self::MultiPointType<'_>, + Self::MultiLineStringType<'_>, + Self::MultiPolygonType<'_>, + Self::GeometryCollectionType<'_>, + Self::RectType<'_>, + Self::TriangleType<'_>, + Self::LineType<'_>, + > { + match self { + crate::GeoJson::Feature(f) => f.as_type(), + crate::GeoJson::FeatureCollection(_fc) => { + unimplemented!("TODO") + } + crate::GeoJson::Geometry(g) => g.as_type(), + } + } +} diff --git a/src/geo_traits_impl/geometry_collection.rs b/src/geo_traits_impl/geometry_collection.rs index 53ab9fd..f529998 100644 --- a/src/geo_traits_impl/geometry_collection.rs +++ b/src/geo_traits_impl/geometry_collection.rs @@ -60,3 +60,57 @@ impl<'a> geo_traits::GeometryCollectionTrait for &'a GeometryCollectionType { GeometryCollectionType::num_geometries(self) } } + +impl geo_traits::GeometryCollectionTrait for crate::FeatureCollection { + type T = f64; + type GeometryType<'b> = &'b crate::Feature; + + fn dim(&self) -> Dimensions { + self.features.first().unwrap().dim() + } + + fn geometries( + &self, + ) -> impl DoubleEndedIterator + ExactSizeIterator> { + self.features.iter() + } + + fn geometry(&self, i: usize) -> Option> { + self.features.get(i) + } + + unsafe fn geometry_unchecked(&self, i: usize) -> Self::GeometryType<'_> { + self.features.get_unchecked(i) + } + + fn num_geometries(&self) -> usize { + self.features.len() + } +} + +impl<'a> geo_traits::GeometryCollectionTrait for &'a crate::FeatureCollection { + type T = f64; + type GeometryType<'b> = &'b crate::Feature where Self: 'b; + + fn dim(&self) -> Dimensions { + crate::FeatureCollection::dim(self) + } + + fn geometries( + &self, + ) -> impl DoubleEndedIterator + ExactSizeIterator> { + crate::FeatureCollection::geometries(self) + } + + fn geometry(&self, i: usize) -> Option> { + crate::FeatureCollection::geometry(self, i) + } + + unsafe fn geometry_unchecked(&self, i: usize) -> Self::GeometryType<'_> { + crate::FeatureCollection::geometry_unchecked(self, i) + } + + fn num_geometries(&self) -> usize { + crate::FeatureCollection::num_geometries(self) + } +} diff --git a/src/geo_traits_impl/multi_line_string.rs b/src/geo_traits_impl/multi_line_string.rs index 29b59f7..ee3a9ba 100644 --- a/src/geo_traits_impl/multi_line_string.rs +++ b/src/geo_traits_impl/multi_line_string.rs @@ -1,6 +1,6 @@ use super::{LineStringType, MultiLineStringType}; use bytemuck::TransparentWrapper; -use geo_traits::{Dimensions, LineStringTrait, MultiLineStringTrait}; +use geo_traits::{Dimensions, LineStringTrait}; impl geo_traits::MultiLineStringTrait for MultiLineStringType { type T = f64; diff --git a/src/geo_traits_impl/polygon.rs b/src/geo_traits_impl/polygon.rs index cd0699a..938d9bb 100644 --- a/src/geo_traits_impl/polygon.rs +++ b/src/geo_traits_impl/polygon.rs @@ -1,6 +1,6 @@ use super::{LineStringType, PolygonType}; use bytemuck::TransparentWrapper; -use geo_traits::{Dimensions, LineStringTrait, PolygonTrait}; +use geo_traits::{Dimensions, LineStringTrait}; impl geo_traits::PolygonTrait for PolygonType { type T = f64; From 466a5cbdcf266b933a2ac21459c18a031bad855d Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 27 Oct 2024 16:29:36 -0400 Subject: [PATCH 08/11] basic implementation test --- src/geo_traits_impl/mod.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/geo_traits_impl/mod.rs b/src/geo_traits_impl/mod.rs index 225a1f5..a4e36d2 100644 --- a/src/geo_traits_impl/mod.rs +++ b/src/geo_traits_impl/mod.rs @@ -39,3 +39,19 @@ pub struct MultiPolygonType(Vec); #[derive(bytemuck::TransparentWrapper)] #[repr(transparent)] pub struct GeometryCollectionType(Vec); + +#[cfg(test)] +mod test { + #[test] + fn test_implementation() { + let geojson_str = include_str!("../../tests/fixtures/countries.geojson"); + let geojson = geojson_str.parse::().unwrap(); + let area = area(geojson); + assert_eq!(area, 0.0); + } + + // Example to demonstrate usage of geo-traits + fn area(g: impl geo_traits::GeometryTrait) -> f64 { + 0. + } +} From 7bd2f7556c93e3b8583df75e2470547c4eee6e4b Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 1 Nov 2024 00:20:10 -0400 Subject: [PATCH 09/11] format --- src/geo_traits_impl/geometry.rs | 100 +++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 20 deletions(-) diff --git a/src/geo_traits_impl/geometry.rs b/src/geo_traits_impl/geometry.rs index 31a4458..1688fc1 100644 --- a/src/geo_traits_impl/geometry.rs +++ b/src/geo_traits_impl/geometry.rs @@ -283,16 +283,46 @@ impl geo_traits::GeometryTrait for crate::Feature { impl geo_traits::GeometryTrait for &crate::Feature { type T = f64; - type PointType<'b> = PointType where Self: 'b; - type LineStringType<'b> = LineStringType where Self: 'b; - type PolygonType<'b> = PolygonType where Self: 'b; - type MultiPointType<'b> = MultiPointType where Self: 'b; - type MultiLineStringType<'b> = MultiLineStringType where Self: 'b; - type MultiPolygonType<'b> = MultiPolygonType where Self: 'b; - type GeometryCollectionType<'b> = GeometryCollectionType where Self: 'b; - type RectType<'b> = UnimplementedRect where Self: 'b; - type TriangleType<'b> = UnimplementedTriangle where Self: 'b; - type LineType<'b> = UnimplementedLine where Self: 'b; + type PointType<'b> + = PointType + where + Self: 'b; + type LineStringType<'b> + = LineStringType + where + Self: 'b; + type PolygonType<'b> + = PolygonType + where + Self: 'b; + type MultiPointType<'b> + = MultiPointType + where + Self: 'b; + type MultiLineStringType<'b> + = MultiLineStringType + where + Self: 'b; + type MultiPolygonType<'b> + = MultiPolygonType + where + Self: 'b; + type GeometryCollectionType<'b> + = GeometryCollectionType + where + Self: 'b; + type RectType<'b> + = UnimplementedRect + where + Self: 'b; + type TriangleType<'b> + = UnimplementedTriangle + where + Self: 'b; + type LineType<'b> + = UnimplementedLine + where + Self: 'b; fn as_type( &self, @@ -319,16 +349,46 @@ impl geo_traits::GeometryTrait for &crate::Feature { impl geo_traits::GeometryTrait for crate::GeoJson { type T = f64; - type PointType<'b> = PointType where Self: 'b; - type LineStringType<'b> = LineStringType where Self: 'b; - type PolygonType<'b> = PolygonType where Self: 'b; - type MultiPointType<'b> = MultiPointType where Self: 'b; - type MultiLineStringType<'b> = MultiLineStringType where Self: 'b; - type MultiPolygonType<'b> = MultiPolygonType where Self: 'b; - type GeometryCollectionType<'b> = GeometryCollectionType where Self: 'b; - type RectType<'b> = UnimplementedRect where Self: 'b; - type TriangleType<'b> = UnimplementedTriangle where Self: 'b; - type LineType<'b> = UnimplementedLine where Self: 'b; + type PointType<'b> + = PointType + where + Self: 'b; + type LineStringType<'b> + = LineStringType + where + Self: 'b; + type PolygonType<'b> + = PolygonType + where + Self: 'b; + type MultiPointType<'b> + = MultiPointType + where + Self: 'b; + type MultiLineStringType<'b> + = MultiLineStringType + where + Self: 'b; + type MultiPolygonType<'b> + = MultiPolygonType + where + Self: 'b; + type GeometryCollectionType<'b> + = GeometryCollectionType + where + Self: 'b; + type RectType<'b> + = UnimplementedRect + where + Self: 'b; + type TriangleType<'b> + = UnimplementedTriangle + where + Self: 'b; + type LineType<'b> + = UnimplementedLine + where + Self: 'b; fn dim(&self) -> Dimensions { match self { From 765e37ae3f729925049e3ab138167975eaf134f2 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 1 Nov 2024 00:20:18 -0400 Subject: [PATCH 10/11] implement for &GeoJson --- src/geo_traits_impl/geometry.rs | 66 +++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/geo_traits_impl/geometry.rs b/src/geo_traits_impl/geometry.rs index 1688fc1..f986124 100644 --- a/src/geo_traits_impl/geometry.rs +++ b/src/geo_traits_impl/geometry.rs @@ -422,3 +422,69 @@ impl geo_traits::GeometryTrait for crate::GeoJson { } } } + +impl geo_traits::GeometryTrait for &crate::GeoJson { + type T = f64; + type PointType<'b> + = PointType + where + Self: 'b; + type LineStringType<'b> + = LineStringType + where + Self: 'b; + type PolygonType<'b> + = PolygonType + where + Self: 'b; + type MultiPointType<'b> + = MultiPointType + where + Self: 'b; + type MultiLineStringType<'b> + = MultiLineStringType + where + Self: 'b; + type MultiPolygonType<'b> + = MultiPolygonType + where + Self: 'b; + type GeometryCollectionType<'b> + = GeometryCollectionType + where + Self: 'b; + type RectType<'b> + = UnimplementedRect + where + Self: 'b; + type TriangleType<'b> + = UnimplementedTriangle + where + Self: 'b; + type LineType<'b> + = UnimplementedLine + where + Self: 'b; + + fn dim(&self) -> Dimensions { + crate::GeoJson::dim(self) + } + + fn as_type( + &self, + ) -> geo_traits::GeometryType< + '_, + Self::PointType<'_>, + Self::LineStringType<'_>, + Self::PolygonType<'_>, + Self::MultiPointType<'_>, + Self::MultiLineStringType<'_>, + Self::MultiPolygonType<'_>, + Self::GeometryCollectionType<'_>, + Self::RectType<'_>, + Self::TriangleType<'_>, + Self::LineType<'_>, + > { + crate::GeoJson::as_type(self) + } +} From 40bec4b3efe859e7978113465b52921cae6a40fe Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 1 Nov 2024 00:24:01 -0400 Subject: [PATCH 11/11] remove methods with default impls --- src/geo_traits_impl/line_string.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/geo_traits_impl/line_string.rs b/src/geo_traits_impl/line_string.rs index 5f3ec0c..6e06073 100644 --- a/src/geo_traits_impl/line_string.rs +++ b/src/geo_traits_impl/line_string.rs @@ -21,10 +21,6 @@ impl LineStringTrait for LineStringType { self.coord(i).unwrap() } - fn coords(&self) -> impl DoubleEndedIterator + ExactSizeIterator> { - self.0.iter().map(PointType::wrap_ref) - } - fn dim(&self) -> Dimensions { self.coord(0).unwrap().dim() // TODO: is this okay? } @@ -49,10 +45,6 @@ impl<'a> geo_traits::LineStringTrait for &'a LineStringType { LineStringType::coord_unchecked(self, i) } - fn coords(&self) -> impl DoubleEndedIterator + ExactSizeIterator> { - LineStringType::coords(self) - } - fn dim(&self) -> Dimensions { LineStringType::dim(self) }