From e337d8ad2720b500bf5034b14fc91809512c8f5e Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Sun, 25 Feb 2024 23:39:17 -0500 Subject: [PATCH 01/33] Add geo-traits crate --- .github/workflows/test.yml | 27 ++++- Cargo.toml | 5 +- geo-traits/Cargo.toml | 17 +++ geo-traits/src/coord.rs | 77 +++++++++++++ geo-traits/src/geometry.rs | 153 ++++++++++++++++++++++++++ geo-traits/src/geometry_collection.rs | 64 +++++++++++ geo-traits/src/iterator.rs | 113 +++++++++++++++++++ geo-traits/src/lib.rs | 36 ++++++ geo-traits/src/line_string.rs | 62 +++++++++++ geo-traits/src/multi_line_string.rs | 61 ++++++++++ geo-traits/src/multi_point.rs | 78 +++++++++++++ geo-traits/src/multi_polygon.rs | 61 ++++++++++ geo-traits/src/point.rs | 65 +++++++++++ geo-traits/src/polygon.rs | 75 +++++++++++++ geo-traits/src/rect.rs | 41 +++++++ 15 files changed, 932 insertions(+), 3 deletions(-) create mode 100644 geo-traits/Cargo.toml create mode 100644 geo-traits/src/coord.rs create mode 100644 geo-traits/src/geometry.rs create mode 100644 geo-traits/src/geometry_collection.rs create mode 100644 geo-traits/src/iterator.rs create mode 100644 geo-traits/src/lib.rs create mode 100644 geo-traits/src/line_string.rs create mode 100644 geo-traits/src/multi_line_string.rs create mode 100644 geo-traits/src/multi_point.rs create mode 100644 geo-traits/src/multi_polygon.rs create mode 100644 geo-traits/src/point.rs create mode 100644 geo-traits/src/polygon.rs create mode 100644 geo-traits/src/rect.rs diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1b3ad6fcca..70d221fc02 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -118,6 +118,32 @@ jobs: # we don't want to test `proj-network` because it only enables the `proj` feature - run: cargo test --features "use-proj use-serde" + geo_traits: + name: geo-traits + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, '[skip ci]')" + defaults: + run: + working-directory: geo-traits + strategy: + matrix: + container_image: + # We aim to support rust-stable plus (at least) the prior 3 releases, + # giving us about 6 months of coverage. + # + # Minimum supported rust version (MSRV) + - "georust/geo-ci:proj-9.3.1-rust-1.70" + # Two most recent releases - we omit older ones for expedient CI + - "georust/geo-ci:proj-9.3.1-rust-1.74" + - "georust/geo-ci:proj-9.3.1-rust-1.75" + container: + image: ${{ matrix.container_image }} + steps: + - name: Checkout repository + uses: actions/checkout@v2 + - run: cargo check --all-targets + - run: cargo test + geo_postgis: name: geo-postgis runs-on: ubuntu-latest @@ -184,4 +210,3 @@ jobs: - name: Checkout repository uses: actions/checkout@v3 - run: RUSTDOCFLAGS="-D warnings" cargo doc --all-features --no-deps - diff --git a/Cargo.toml b/Cargo.toml index 232f863983..f6c018b1a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,11 +2,12 @@ resolver = "2" members = [ "geo", - "geo-types", + "geo-bool-ops-benches", "geo-postgis", "geo-test-fixtures", + "geo-traits", + "geo-types", "jts-test-runner", - "geo-bool-ops-benches", ] [patch.crates-io] diff --git a/geo-traits/Cargo.toml b/geo-traits/Cargo.toml new file mode 100644 index 0000000000..4603624521 --- /dev/null +++ b/geo-traits/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "geo-traits" +version = "0.1.0" +license = "MIT OR Apache-2.0" +repository = "https://github.com/georust/geo" +documentation = "https://docs.rs/geo-traits/" +readme = "../README.md" +keywords = ["gis", "geo", "geography", "geospatial"] +description = "Geospatial traits" +rust-version = "1.65" +edition = "2021" + +[dependencies] +geo-types = "0.7" + +[dev-dependencies] +approx = ">= 0.4.0, < 0.6.0" diff --git a/geo-traits/src/coord.rs b/geo-traits/src/coord.rs new file mode 100644 index 0000000000..31b39411af --- /dev/null +++ b/geo-traits/src/coord.rs @@ -0,0 +1,77 @@ +use geo_types::{Coord, CoordNum, Point}; + +/// A trait for accessing data from a generic Coord. +pub trait CoordTrait { + type T: CoordNum; + + /// x component of this coord + fn x(&self) -> Self::T; + + /// y component of this coord + fn y(&self) -> Self::T; + + /// Returns a tuple that contains the x/horizontal & y/vertical component of the coord. + fn x_y(&self) -> (Self::T, Self::T) { + (self.x(), self.y()) + } +} + +impl CoordTrait for Point { + type T = T; + + fn x(&self) -> Self::T { + self.0.x + } + + fn y(&self) -> Self::T { + self.0.y + } +} + +impl CoordTrait for &Point { + type T = T; + + fn x(&self) -> Self::T { + self.0.x + } + + fn y(&self) -> Self::T { + self.0.y + } +} + +impl CoordTrait for Coord { + type T = T; + + fn x(&self) -> Self::T { + self.x + } + + fn y(&self) -> Self::T { + self.y + } +} + +impl CoordTrait for &Coord { + type T = T; + + fn x(&self) -> Self::T { + self.x + } + + fn y(&self) -> Self::T { + self.y + } +} + +impl CoordTrait for (T, T) { + type T = T; + + fn x(&self) -> Self::T { + self.0 + } + + fn y(&self) -> Self::T { + self.1 + } +} diff --git a/geo-traits/src/geometry.rs b/geo-traits/src/geometry.rs new file mode 100644 index 0000000000..24d73fd3c2 --- /dev/null +++ b/geo-traits/src/geometry.rs @@ -0,0 +1,153 @@ +use geo_types::{ + CoordNum, Geometry, GeometryCollection, LineString, MultiLineString, MultiPoint, MultiPolygon, + Point, Polygon, Rect, +}; + +use super::{ + GeometryCollectionTrait, LineStringTrait, MultiLineStringTrait, MultiPointTrait, + MultiPolygonTrait, PointTrait, PolygonTrait, RectTrait, +}; + +/// A trait for accessing data from a generic Geometry. +#[allow(clippy::type_complexity)] +pub trait GeometryTrait { + type T: CoordNum; + type Point<'a>: 'a + PointTrait + where + Self: 'a; + type LineString<'a>: 'a + LineStringTrait + where + Self: 'a; + type Polygon<'a>: 'a + PolygonTrait + where + Self: 'a; + type MultiPoint<'a>: 'a + MultiPointTrait + where + Self: 'a; + type MultiLineString<'a>: 'a + MultiLineStringTrait + where + Self: 'a; + type MultiPolygon<'a>: 'a + MultiPolygonTrait + where + Self: 'a; + type GeometryCollection<'a>: 'a + GeometryCollectionTrait + where + Self: 'a; + type Rect<'a>: 'a + RectTrait + where + Self: 'a; + + fn as_type( + &self, + ) -> GeometryType< + '_, + Self::Point<'_>, + Self::LineString<'_>, + Self::Polygon<'_>, + Self::MultiPoint<'_>, + Self::MultiLineString<'_>, + Self::MultiPolygon<'_>, + Self::GeometryCollection<'_>, + Self::Rect<'_>, + >; +} + +/// An enumeration of all geometry types that can be contained inside a [GeometryTrait]. This is +/// used for extracting concrete geometry types out of a [GeometryTrait]. +#[derive(Debug)] +pub enum GeometryType<'a, P, L, Y, MP, ML, MY, GC, R> +where + P: PointTrait, + L: LineStringTrait, + Y: PolygonTrait, + MP: MultiPointTrait, + ML: MultiLineStringTrait, + MY: MultiPolygonTrait, + GC: GeometryCollectionTrait, + R: RectTrait, +{ + Point(&'a P), + LineString(&'a L), + Polygon(&'a Y), + MultiPoint(&'a MP), + MultiLineString(&'a ML), + MultiPolygon(&'a MY), + GeometryCollection(&'a GC), + Rect(&'a R), +} + +impl<'a, T: CoordNum + 'a> GeometryTrait for Geometry { + type T = T; + type Point<'b> = Point where Self: 'b; + type LineString<'b> = LineString where Self: 'b; + type Polygon<'b> = Polygon where Self: 'b; + type MultiPoint<'b> = MultiPoint where Self: 'b; + type MultiLineString<'b> = MultiLineString where Self: 'b; + type MultiPolygon<'b> = MultiPolygon where Self: 'b; + type GeometryCollection<'b> = GeometryCollection where Self: 'b; + type Rect<'b> = Rect where Self: 'b; + + fn as_type( + &self, + ) -> GeometryType< + '_, + Point, + LineString, + Polygon, + MultiPoint, + MultiLineString, + MultiPolygon, + GeometryCollection, + Rect, + > { + match self { + Geometry::Point(p) => GeometryType::Point(p), + Geometry::LineString(p) => GeometryType::LineString(p), + Geometry::Polygon(p) => GeometryType::Polygon(p), + Geometry::MultiPoint(p) => GeometryType::MultiPoint(p), + Geometry::MultiLineString(p) => GeometryType::MultiLineString(p), + Geometry::MultiPolygon(p) => GeometryType::MultiPolygon(p), + Geometry::GeometryCollection(p) => GeometryType::GeometryCollection(p), + Geometry::Rect(p) => GeometryType::Rect(p), + _ => todo!(), + } + } +} + +impl<'a, T: CoordNum + 'a> GeometryTrait for &'a Geometry { + type T = T; + type Point<'b> = Point where Self: 'b; + type LineString<'b> = LineString where Self: 'b; + type Polygon<'b> = Polygon where Self: 'b; + type MultiPoint<'b> = MultiPoint where Self: 'b; + type MultiLineString<'b> = MultiLineString where Self: 'b; + type MultiPolygon<'b> = MultiPolygon where Self: 'b; + type GeometryCollection<'b> = GeometryCollection where Self: 'b; + type Rect<'b> = Rect where Self: 'b; + + fn as_type( + &self, + ) -> GeometryType< + '_, + Point, + LineString, + Polygon, + MultiPoint, + MultiLineString, + MultiPolygon, + GeometryCollection, + Rect, + > { + match self { + Geometry::Point(p) => GeometryType::Point(p), + Geometry::LineString(p) => GeometryType::LineString(p), + Geometry::Polygon(p) => GeometryType::Polygon(p), + Geometry::MultiPoint(p) => GeometryType::MultiPoint(p), + Geometry::MultiLineString(p) => GeometryType::MultiLineString(p), + Geometry::MultiPolygon(p) => GeometryType::MultiPolygon(p), + Geometry::GeometryCollection(p) => GeometryType::GeometryCollection(p), + Geometry::Rect(p) => GeometryType::Rect(p), + _ => todo!(), + } + } +} diff --git a/geo-traits/src/geometry_collection.rs b/geo-traits/src/geometry_collection.rs new file mode 100644 index 0000000000..5e19846ef5 --- /dev/null +++ b/geo-traits/src/geometry_collection.rs @@ -0,0 +1,64 @@ +use super::{GeometryCollectionIterator, GeometryTrait}; +use geo_types::{CoordNum, Geometry, GeometryCollection}; + +/// A trait for accessing data from a generic GeometryCollection. +pub trait GeometryCollectionTrait: Sized { + type T: CoordNum; + type ItemType<'a>: 'a + GeometryTrait + where + Self: 'a; + + /// An iterator over the geometries in this GeometryCollection + fn geometries(&self) -> GeometryCollectionIterator<'_, Self::T, Self::ItemType<'_>, Self> { + GeometryCollectionIterator::new(self, 0, self.num_geometries()) + } + + /// The number of geometries in this GeometryCollection + fn num_geometries(&self) -> usize; + + /// Access to a specified geometry in this GeometryCollection + /// Will return None if the provided index is out of bounds + fn geometry(&self, i: usize) -> Option> { + if i >= self.num_geometries() { + None + } else { + unsafe { Some(self.geometry_unchecked(i)) } + } + } + + /// Access to a specified geometry in this GeometryCollection + /// + /// # Safety + /// + /// Accessing an index out of bounds is UB. + unsafe fn geometry_unchecked(&self, i: usize) -> Self::ItemType<'_>; +} + +impl GeometryCollectionTrait for GeometryCollection { + type T = T; + type ItemType<'a> = &'a Geometry + where + Self: 'a; + + fn num_geometries(&self) -> usize { + self.0.len() + } + + unsafe fn geometry_unchecked(&self, i: usize) -> Self::ItemType<'_> { + self.0.get_unchecked(i) + } +} + +impl<'a, T: CoordNum> GeometryCollectionTrait for &'a GeometryCollection { + type T = T; + type ItemType<'b> = &'a Geometry where + Self: 'b; + + fn num_geometries(&self) -> usize { + self.0.len() + } + + unsafe fn geometry_unchecked(&self, i: usize) -> Self::ItemType<'_> { + self.0.get_unchecked(i) + } +} diff --git a/geo-traits/src/iterator.rs b/geo-traits/src/iterator.rs new file mode 100644 index 0000000000..9de6e589c5 --- /dev/null +++ b/geo-traits/src/iterator.rs @@ -0,0 +1,113 @@ +use super::{ + CoordTrait, GeometryCollectionTrait, GeometryTrait, LineStringTrait, MultiLineStringTrait, + MultiPointTrait, MultiPolygonTrait, PointTrait, PolygonTrait, +}; +use geo_types::CoordNum; + +macro_rules! impl_iterator { + ($struct_name:ident, $self_trait:ident, $item_trait:ident, $access_method:ident) => { + /// An iterator over the parts of this geometry. + pub struct $struct_name< + 'a, + T: CoordNum, + ItemType: 'a + $item_trait, + G: $self_trait = ItemType>, + > { + geom: &'a G, + index: usize, + end: usize, + } + + impl< + 'a, + T: CoordNum, + ItemType: 'a + $item_trait, + G: $self_trait = ItemType>, + > $struct_name<'a, T, ItemType, G> + { + pub fn new(geom: &'a G, index: usize, end: usize) -> Self { + Self { geom, index, end } + } + } + + impl< + 'a, + T: CoordNum, + ItemType: 'a + $item_trait, + G: $self_trait = ItemType>, + > Iterator for $struct_name<'a, T, ItemType, G> + { + type Item = ItemType; + + #[inline] + fn next(&mut self) -> Option { + if self.index == self.end { + return None; + } + let old = self.index; + self.index += 1; + unsafe { Some(self.geom.$access_method(old)) } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.end - self.index, Some(self.end - self.index)) + } + } + + impl< + 'a, + T: CoordNum, + ItemType: 'a + $item_trait, + G: $self_trait = ItemType>, + > DoubleEndedIterator for $struct_name<'a, T, ItemType, G> + { + #[inline] + fn next_back(&mut self) -> Option { + if self.index == self.end { + None + } else { + self.end -= 1; + unsafe { Some(self.geom.$access_method(self.end)) } + } + } + } + }; +} + +impl_iterator!( + LineStringIterator, + LineStringTrait, + CoordTrait, + coord_unchecked +); +impl_iterator!( + PolygonInteriorIterator, + PolygonTrait, + LineStringTrait, + interior_unchecked +); +impl_iterator!( + MultiPointIterator, + MultiPointTrait, + PointTrait, + point_unchecked +); +impl_iterator!( + MultiLineStringIterator, + MultiLineStringTrait, + LineStringTrait, + line_unchecked +); +impl_iterator!( + MultiPolygonIterator, + MultiPolygonTrait, + PolygonTrait, + polygon_unchecked +); +impl_iterator!( + GeometryCollectionIterator, + GeometryCollectionTrait, + GeometryTrait, + geometry_unchecked +); diff --git a/geo-traits/src/lib.rs b/geo-traits/src/lib.rs new file mode 100644 index 0000000000..d2105fab4a --- /dev/null +++ b/geo-traits/src/lib.rs @@ -0,0 +1,36 @@ +//! An initial, in-progress implementation of [geometry access +//! traits](https://github.com/georust/geo/discussions/838). +//! +//! The idea is that functions should be able to operate on and consume geospatial vector data from +//! _any_ source without overhead, not limited to just the layout defined in the [`geo`] crate. +//! +//! The main work for this is happening in the [`geo`] repository (see +//! [here](https://github.com/georust/geo/pull/1019)) but that is vendored into this repository for +//! use internally, such as in the WKB parser. + +pub use coord::CoordTrait; +pub use geometry::{GeometryTrait, GeometryType}; +pub use geometry_collection::GeometryCollectionTrait; +pub use iterator::{ + GeometryCollectionIterator, LineStringIterator, MultiLineStringIterator, MultiPointIterator, + MultiPolygonIterator, PolygonInteriorIterator, +}; +pub use line_string::LineStringTrait; +pub use multi_line_string::MultiLineStringTrait; +pub use multi_point::MultiPointTrait; +pub use multi_polygon::MultiPolygonTrait; +pub use point::PointTrait; +pub use polygon::PolygonTrait; +pub use rect::RectTrait; + +mod coord; +mod geometry; +mod geometry_collection; +mod iterator; +mod line_string; +mod multi_line_string; +mod multi_point; +mod multi_polygon; +mod point; +mod polygon; +mod rect; diff --git a/geo-traits/src/line_string.rs b/geo-traits/src/line_string.rs new file mode 100644 index 0000000000..8a591ee574 --- /dev/null +++ b/geo-traits/src/line_string.rs @@ -0,0 +1,62 @@ +use super::{CoordTrait, LineStringIterator}; +use geo_types::{Coord, CoordNum, LineString}; + +/// A trait for accessing data from a generic LineString. +pub trait LineStringTrait: Sized { + type T: CoordNum; + type ItemType<'a>: 'a + CoordTrait + where + Self: 'a; + + /// An iterator over the coords in this LineString + fn coords(&self) -> LineStringIterator<'_, Self::T, Self::ItemType<'_>, Self> { + LineStringIterator::new(self, 0, self.num_coords()) + } + + /// The number of coords in this LineString + fn num_coords(&self) -> usize; + + /// Access to a specified point in this LineString + /// Will return None if the provided index is out of bounds + #[inline] + fn coord(&self, i: usize) -> Option> { + if i >= self.num_coords() { + None + } else { + unsafe { Some(self.coord_unchecked(i)) } + } + } + + /// Access to a specified point in this LineString + /// + /// # Safety + /// + /// Accessing an index out of bounds is UB. + unsafe fn coord_unchecked(&self, i: usize) -> Self::ItemType<'_>; +} + +impl LineStringTrait for LineString { + type T = T; + type ItemType<'a> = &'a Coord where Self: 'a; + + fn num_coords(&self) -> usize { + self.0.len() + } + + unsafe fn coord_unchecked(&self, i: usize) -> Self::ItemType<'_> { + self.0.get_unchecked(i) + } +} + +impl<'a, T: CoordNum> LineStringTrait for &'a LineString { + type T = T; + type ItemType<'b> = &'a Coord where Self: 'b; + + fn num_coords(&self) -> usize { + self.0.len() + } + + unsafe fn coord_unchecked(&self, i: usize) -> Self::ItemType<'_> { + self.0.get_unchecked(i) + } +} diff --git a/geo-traits/src/multi_line_string.rs b/geo-traits/src/multi_line_string.rs new file mode 100644 index 0000000000..88549c1843 --- /dev/null +++ b/geo-traits/src/multi_line_string.rs @@ -0,0 +1,61 @@ +use super::{LineStringTrait, MultiLineStringIterator}; +use geo_types::{CoordNum, LineString, MultiLineString}; + +/// A trait for accessing data from a generic MultiLineString. +pub trait MultiLineStringTrait: Sized { + type T: CoordNum; + type ItemType<'a>: 'a + LineStringTrait + where + Self: 'a; + + /// An iterator over the LineStrings in this MultiLineString + fn lines(&self) -> MultiLineStringIterator<'_, Self::T, Self::ItemType<'_>, Self> { + MultiLineStringIterator::new(self, 0, self.num_lines()) + } + + /// The number of lines in this MultiLineString + fn num_lines(&self) -> usize; + + /// Access to a specified line in this MultiLineString + /// Will return None if the provided index is out of bounds + fn line(&self, i: usize) -> Option> { + if i >= self.num_lines() { + None + } else { + unsafe { Some(self.line_unchecked(i)) } + } + } + + /// Access to a specified line in this MultiLineString + /// + /// # Safety + /// + /// Accessing an index out of bounds is UB. + unsafe fn line_unchecked(&self, i: usize) -> Self::ItemType<'_>; +} + +impl MultiLineStringTrait for MultiLineString { + type T = T; + type ItemType<'a> = &'a LineString where Self: 'a; + + fn num_lines(&self) -> usize { + self.0.len() + } + + unsafe fn line_unchecked(&self, i: usize) -> Self::ItemType<'_> { + self.0.get_unchecked(i) + } +} + +impl<'a, T: CoordNum> MultiLineStringTrait for &'a MultiLineString { + type T = T; + type ItemType<'b> = &'a LineString where Self: 'b; + + fn num_lines(&self) -> usize { + self.0.len() + } + + unsafe fn line_unchecked(&self, i: usize) -> Self::ItemType<'_> { + self.0.get_unchecked(i) + } +} diff --git a/geo-traits/src/multi_point.rs b/geo-traits/src/multi_point.rs new file mode 100644 index 0000000000..d7f20d9cae --- /dev/null +++ b/geo-traits/src/multi_point.rs @@ -0,0 +1,78 @@ +use super::{MultiPointIterator, PointTrait}; +use geo_types::{CoordNum, MultiPoint, Point}; + +/// A trait for accessing data from a generic MultiPoint. +pub trait MultiPointTrait: Sized { + type T: CoordNum; + type ItemType<'a>: 'a + PointTrait + where + Self: 'a; + + /// An iterator over the points in this MultiPoint + fn points(&self) -> MultiPointIterator<'_, Self::T, Self::ItemType<'_>, Self> { + MultiPointIterator::new(self, 0, self.num_points()) + } + + /// The number of points in this MultiPoint + fn num_points(&self) -> usize; + + /// Access to a specified point in this MultiPoint + /// Will return None if the provided index is out of bounds + fn point(&self, i: usize) -> Option> { + if i >= self.num_points() { + None + } else { + unsafe { Some(self.point_unchecked(i)) } + } + } + + /// Access to a specified point in this MultiPoint + /// + /// # Safety + /// + /// Accessing an index out of bounds is UB. + unsafe fn point_unchecked(&self, i: usize) -> Self::ItemType<'_>; +} + +impl MultiPointTrait for MultiPoint { + type T = T; + type ItemType<'a> = &'a Point where Self: 'a; + + fn num_points(&self) -> usize { + self.0.len() + } + + unsafe fn point_unchecked(&self, i: usize) -> Self::ItemType<'_> { + self.0.get_unchecked(i) + } +} + +impl<'a, T: CoordNum> MultiPointTrait for &'a MultiPoint { + type T = T; + type ItemType<'b> = &'a Point where Self: 'b; + + fn num_points(&self) -> usize { + self.0.len() + } + + unsafe fn point_unchecked(&self, i: usize) -> Self::ItemType<'_> { + self.0.get_unchecked(i) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn tmp() { + let mp = MultiPoint::new(vec![ + Point::new(0.0, 1.0), + Point::new(2.0, 3.0), + Point::new(4.0, 5.0), + ]); + MultiPointTrait::points(&mp).for_each(|p| { + dbg!(p); + }); + } +} diff --git a/geo-traits/src/multi_polygon.rs b/geo-traits/src/multi_polygon.rs new file mode 100644 index 0000000000..e4e6c2e20c --- /dev/null +++ b/geo-traits/src/multi_polygon.rs @@ -0,0 +1,61 @@ +use super::{MultiPolygonIterator, PolygonTrait}; +use geo_types::{CoordNum, MultiPolygon, Polygon}; + +/// A trait for accessing data from a generic MultiPolygon. +pub trait MultiPolygonTrait: Sized { + type T: CoordNum; + type ItemType<'a>: 'a + PolygonTrait + where + Self: 'a; + + /// An iterator over the Polygons in this MultiPolygon + fn polygons(&self) -> MultiPolygonIterator<'_, Self::T, Self::ItemType<'_>, Self> { + MultiPolygonIterator::new(self, 0, self.num_polygons()) + } + + /// The number of polygons in this MultiPolygon + fn num_polygons(&self) -> usize; + + /// Access to a specified polygon in this MultiPolygon + /// Will return None if the provided index is out of bounds + fn polygon(&self, i: usize) -> Option> { + if i >= self.num_polygons() { + None + } else { + unsafe { Some(self.polygon_unchecked(i)) } + } + } + + /// Access to a specified polygon in this MultiPolygon + /// + /// # Safety + /// + /// Accessing an index out of bounds is UB. + unsafe fn polygon_unchecked(&self, i: usize) -> Self::ItemType<'_>; +} + +impl MultiPolygonTrait for MultiPolygon { + type T = T; + type ItemType<'a> = &'a Polygon where Self: 'a; + + fn num_polygons(&self) -> usize { + self.0.len() + } + + unsafe fn polygon_unchecked(&self, i: usize) -> Self::ItemType<'_> { + self.0.get_unchecked(i) + } +} + +impl<'a, T: CoordNum> MultiPolygonTrait for &'a MultiPolygon { + type T = T; + type ItemType<'b> = &'a Polygon where Self: 'b; + + fn num_polygons(&self) -> usize { + self.0.len() + } + + unsafe fn polygon_unchecked(&self, i: usize) -> Self::ItemType<'_> { + self.0.get_unchecked(i) + } +} diff --git a/geo-traits/src/point.rs b/geo-traits/src/point.rs new file mode 100644 index 0000000000..8c17ad063e --- /dev/null +++ b/geo-traits/src/point.rs @@ -0,0 +1,65 @@ +use geo_types::{Coord, CoordNum, Point}; + +/// A trait for accessing data from a generic Point. +pub trait PointTrait { + type T: CoordNum; + + /// x component of this point. + fn x(&self) -> Self::T; + + /// y component of this point. + fn y(&self) -> Self::T; + + /// Returns a tuple that contains the x/horizontal & y/vertical component of the point. + fn x_y(&self) -> (Self::T, Self::T) { + (self.x(), self.y()) + } +} + +impl PointTrait for Point { + type T = T; + + fn x(&self) -> Self::T { + self.0.x + } + + fn y(&self) -> Self::T { + self.0.y + } +} + +impl PointTrait for &Point { + type T = T; + + fn x(&self) -> Self::T { + self.0.x + } + + fn y(&self) -> Self::T { + self.0.y + } +} + +impl PointTrait for Coord { + type T = T; + + fn x(&self) -> Self::T { + self.x + } + + fn y(&self) -> Self::T { + self.y + } +} + +impl PointTrait for &Coord { + type T = T; + + fn x(&self) -> Self::T { + self.x + } + + fn y(&self) -> Self::T { + self.y + } +} diff --git a/geo-traits/src/polygon.rs b/geo-traits/src/polygon.rs new file mode 100644 index 0000000000..0f5187e5a6 --- /dev/null +++ b/geo-traits/src/polygon.rs @@ -0,0 +1,75 @@ +use super::{LineStringTrait, PolygonInteriorIterator}; +use geo_types::{CoordNum, LineString, Polygon}; + +/// A trait for accessing data from a generic Polygon. +pub trait PolygonTrait: Sized { + type T: CoordNum; + type ItemType<'a>: 'a + LineStringTrait + where + Self: 'a; + + /// The exterior ring of the polygon + fn exterior(&self) -> Option>; + + /// An iterator of the interior rings of this Polygon + fn interiors(&self) -> PolygonInteriorIterator<'_, Self::T, Self::ItemType<'_>, Self> { + PolygonInteriorIterator::new(self, 0, self.num_interiors()) + } + + /// The number of interior rings in this Polygon + fn num_interiors(&self) -> usize; + + /// Access to a specified interior ring in this Polygon + /// Will return None if the provided index is out of bounds + fn interior(&self, i: usize) -> Option> { + if i >= self.num_interiors() { + None + } else { + unsafe { Some(self.interior_unchecked(i)) } + } + } + + /// Access to a specified interior ring in this Polygon + /// + /// # Safety + /// + /// Accessing an index out of bounds is UB. + unsafe fn interior_unchecked(&self, i: usize) -> Self::ItemType<'_>; +} + +impl PolygonTrait for Polygon { + type T = T; + type ItemType<'a> = &'a LineString where Self: 'a; + + fn exterior(&self) -> Option> { + // geo-types doesn't really have a way to describe an empty polygon + Some(Polygon::exterior(self)) + } + + fn num_interiors(&self) -> usize { + Polygon::interiors(self).len() + } + + unsafe fn interior_unchecked(&self, i: usize) -> Self::ItemType<'_> { + unsafe { Polygon::interiors(self).get_unchecked(i) } + } +} + +impl<'a, T: CoordNum> PolygonTrait for &'a Polygon { + type T = T; + type ItemType<'b> = &'a LineString where + Self: 'b; + + fn exterior(&self) -> Option> { + // geo-types doesn't really have a way to describe an empty polygon + Some(Polygon::exterior(self)) + } + + fn num_interiors(&self) -> usize { + Polygon::interiors(self).len() + } + + unsafe fn interior_unchecked(&self, i: usize) -> Self::ItemType<'_> { + unsafe { Polygon::interiors(self).get_unchecked(i) } + } +} diff --git a/geo-traits/src/rect.rs b/geo-traits/src/rect.rs new file mode 100644 index 0000000000..b31be57c3e --- /dev/null +++ b/geo-traits/src/rect.rs @@ -0,0 +1,41 @@ +use geo_types::{Coord, CoordNum, Rect}; + +use super::CoordTrait; + +/// A trait for accessing data from a generic Rect. +pub trait RectTrait { + type T: CoordNum; + type ItemType<'a>: 'a + CoordTrait + where + Self: 'a; + + fn lower(&self) -> Self::ItemType<'_>; + + fn upper(&self) -> Self::ItemType<'_>; +} + +impl<'a, T: CoordNum + 'a> RectTrait for Rect { + type T = T; + type ItemType<'b> = Coord where Self: 'b; + + fn lower(&self) -> Self::ItemType<'_> { + self.min() + } + + fn upper(&self) -> Self::ItemType<'_> { + self.max() + } +} + +impl<'a, T: CoordNum + 'a> RectTrait for &'a Rect { + type T = T; + type ItemType<'b> = Coord where Self: 'b; + + fn lower(&self) -> Self::ItemType<'_> { + self.min() + } + + fn upper(&self) -> Self::ItemType<'_> { + self.max() + } +} From 7f68df25b40e03a3f624bcd946bdcaf44d399d4f Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Sun, 25 Feb 2024 23:42:59 -0500 Subject: [PATCH 02/33] Update doc --- geo-traits/src/lib.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/geo-traits/src/lib.rs b/geo-traits/src/lib.rs index d2105fab4a..f0d160eed7 100644 --- a/geo-traits/src/lib.rs +++ b/geo-traits/src/lib.rs @@ -2,11 +2,8 @@ //! traits](https://github.com/georust/geo/discussions/838). //! //! The idea is that functions should be able to operate on and consume geospatial vector data from -//! _any_ source without overhead, not limited to just the layout defined in the [`geo`] crate. -//! -//! The main work for this is happening in the [`geo`] repository (see -//! [here](https://github.com/georust/geo/pull/1019)) but that is vendored into this repository for -//! use internally, such as in the WKB parser. +//! _any_ source without overhead, not limited to just the layout defined in the [`geo-types`] +//! crate. pub use coord::CoordTrait; pub use geometry::{GeometryTrait, GeometryType}; From 34ed5bea2c8bc9778c2cb6fe8e8994842a0828bf Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Tue, 27 Feb 2024 11:12:45 -0500 Subject: [PATCH 03/33] Update geo-traits/Cargo.toml --- geo-traits/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/geo-traits/Cargo.toml b/geo-traits/Cargo.toml index 4603624521..a9c3c48b34 100644 --- a/geo-traits/Cargo.toml +++ b/geo-traits/Cargo.toml @@ -14,4 +14,3 @@ edition = "2021" geo-types = "0.7" [dev-dependencies] -approx = ">= 0.4.0, < 0.6.0" From ee0420133d43b3b29ce7ae5547f85cb1b72d8db2 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Wed, 9 Oct 2024 23:32:00 -0400 Subject: [PATCH 04/33] Update docker images --- .github/workflows/test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 24108dd764..ddf68ef018 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -132,10 +132,10 @@ jobs: # giving us about 6 months of coverage. # # Minimum supported rust version (MSRV) - - "georust/geo-ci:proj-9.3.1-rust-1.70" + - "ghcr.io/georust/geo-ci:proj-9.4.0-rust-1.75" # Two most recent releases - we omit older ones for expedient CI - - "georust/geo-ci:proj-9.3.1-rust-1.74" - - "georust/geo-ci:proj-9.3.1-rust-1.75" + - "ghcr.io/georust/geo-ci:proj-9.4.0-rust-1.78" + - "ghcr.io/georust/geo-ci:proj-9.4.0-rust-1.79" container: image: ${{ matrix.container_image }} steps: From ad48ee16e461312423e032f1dbd6b1c7c7d29a44 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Wed, 9 Oct 2024 23:36:17 -0400 Subject: [PATCH 05/33] Remove CoordTrait and add multiple dimensions --- geo-traits/src/coord.rs | 77 ------------------ geo-traits/src/geometry.rs | 38 +++++++++ geo-traits/src/geometry_collection.rs | 14 ++++ geo-traits/src/iterator.rs | 7 +- geo-traits/src/lib.rs | 2 - geo-traits/src/line_string.rs | 18 ++++- geo-traits/src/multi_line_string.rs | 14 ++++ geo-traits/src/multi_point.rs | 14 ++++ geo-traits/src/multi_polygon.rs | 14 ++++ geo-traits/src/point.rs | 112 ++++++++++++++++++++++++++ geo-traits/src/polygon.rs | 14 ++++ geo-traits/src/rect.rs | 20 ++++- 12 files changed, 258 insertions(+), 86 deletions(-) delete mode 100644 geo-traits/src/coord.rs diff --git a/geo-traits/src/coord.rs b/geo-traits/src/coord.rs deleted file mode 100644 index 31b39411af..0000000000 --- a/geo-traits/src/coord.rs +++ /dev/null @@ -1,77 +0,0 @@ -use geo_types::{Coord, CoordNum, Point}; - -/// A trait for accessing data from a generic Coord. -pub trait CoordTrait { - type T: CoordNum; - - /// x component of this coord - fn x(&self) -> Self::T; - - /// y component of this coord - fn y(&self) -> Self::T; - - /// Returns a tuple that contains the x/horizontal & y/vertical component of the coord. - fn x_y(&self) -> (Self::T, Self::T) { - (self.x(), self.y()) - } -} - -impl CoordTrait for Point { - type T = T; - - fn x(&self) -> Self::T { - self.0.x - } - - fn y(&self) -> Self::T { - self.0.y - } -} - -impl CoordTrait for &Point { - type T = T; - - fn x(&self) -> Self::T { - self.0.x - } - - fn y(&self) -> Self::T { - self.0.y - } -} - -impl CoordTrait for Coord { - type T = T; - - fn x(&self) -> Self::T { - self.x - } - - fn y(&self) -> Self::T { - self.y - } -} - -impl CoordTrait for &Coord { - type T = T; - - fn x(&self) -> Self::T { - self.x - } - - fn y(&self) -> Self::T { - self.y - } -} - -impl CoordTrait for (T, T) { - type T = T; - - fn x(&self) -> Self::T { - self.0 - } - - fn y(&self) -> Self::T { - self.1 - } -} diff --git a/geo-traits/src/geometry.rs b/geo-traits/src/geometry.rs index 24d73fd3c2..f877a4b1d2 100644 --- a/geo-traits/src/geometry.rs +++ b/geo-traits/src/geometry.rs @@ -11,32 +11,54 @@ use super::{ /// A trait for accessing data from a generic Geometry. #[allow(clippy::type_complexity)] pub trait GeometryTrait { + /// The coordinate type of this geometry type T: CoordNum; + + /// The type of each underlying Point, which implements [PointTrait] type Point<'a>: 'a + PointTrait where Self: 'a; + + /// The type of each underlying LineString, which implements [LineStringTrait] type LineString<'a>: 'a + LineStringTrait where Self: 'a; + + /// The type of each underlying Polygon, which implements [PolygonTrait] type Polygon<'a>: 'a + PolygonTrait where Self: 'a; + + /// The type of each underlying MultiPoint, which implements [MultiPointTrait] type MultiPoint<'a>: 'a + MultiPointTrait where Self: 'a; + + /// The type of each underlying MultiLineString, which implements [MultiLineStringTrait] type MultiLineString<'a>: 'a + MultiLineStringTrait where Self: 'a; + + /// The type of each underlying MultiPolygon, which implements [MultiPolygonTrait] type MultiPolygon<'a>: 'a + MultiPolygonTrait where Self: 'a; + + /// The type of each underlying GeometryCollection, which implements [GeometryCollectionTrait] type GeometryCollection<'a>: 'a + GeometryCollectionTrait where Self: 'a; + + /// The type of each underlying Rect, which implements [RectTrait] type Rect<'a>: 'a + RectTrait where Self: 'a; + /// The number of dimensions in this geometry + fn dim(&self) -> usize; + + /// Cast this geometry to a [`GeometryType`] enum, which allows for downcasting to a specific + /// type fn as_type( &self, ) -> GeometryType< @@ -66,13 +88,21 @@ where GC: GeometryCollectionTrait, R: RectTrait, { + /// A Point, which implements [PointTrait] Point(&'a P), + /// A LineString, which implements [LineStringTrait] LineString(&'a L), + /// A Polygon, which implements [PolygonTrait] Polygon(&'a Y), + /// A MultiPoint, which implements [MultiPointTrait] MultiPoint(&'a MP), + /// A MultiLineString, which implements [MultiLineStringTrait] MultiLineString(&'a ML), + /// A MultiPolygon, which implements [MultiPolygonTrait] MultiPolygon(&'a MY), + /// A GeometryCollection, which implements [GeometryCollectionTrait] GeometryCollection(&'a GC), + /// A Rect, which implements [RectTrait] Rect(&'a R), } @@ -87,6 +117,10 @@ impl<'a, T: CoordNum + 'a> GeometryTrait for Geometry { type GeometryCollection<'b> = GeometryCollection where Self: 'b; type Rect<'b> = Rect where Self: 'b; + fn dim(&self) -> usize { + 2 + } + fn as_type( &self, ) -> GeometryType< @@ -125,6 +159,10 @@ impl<'a, T: CoordNum + 'a> GeometryTrait for &'a Geometry { type GeometryCollection<'b> = GeometryCollection where Self: 'b; type Rect<'b> = Rect where Self: 'b; + fn dim(&self) -> usize { + 2 + } + fn as_type( &self, ) -> GeometryType< diff --git a/geo-traits/src/geometry_collection.rs b/geo-traits/src/geometry_collection.rs index 5e19846ef5..f107252073 100644 --- a/geo-traits/src/geometry_collection.rs +++ b/geo-traits/src/geometry_collection.rs @@ -3,11 +3,17 @@ use geo_types::{CoordNum, Geometry, GeometryCollection}; /// A trait for accessing data from a generic GeometryCollection. pub trait GeometryCollectionTrait: Sized { + /// The coordinate type of this geometry type T: CoordNum; + + /// The type of each underlying geometry, which implements [GeometryTrait] type ItemType<'a>: 'a + GeometryTrait where Self: 'a; + /// The number of dimensions in this geometry + fn dim(&self) -> usize; + /// An iterator over the geometries in this GeometryCollection fn geometries(&self) -> GeometryCollectionIterator<'_, Self::T, Self::ItemType<'_>, Self> { GeometryCollectionIterator::new(self, 0, self.num_geometries()) @@ -40,6 +46,10 @@ impl GeometryCollectionTrait for GeometryCollection { where Self: 'a; + fn dim(&self) -> usize { + 2 + } + fn num_geometries(&self) -> usize { self.0.len() } @@ -54,6 +64,10 @@ impl<'a, T: CoordNum> GeometryCollectionTrait for &'a GeometryCollection { type ItemType<'b> = &'a Geometry where Self: 'b; + fn dim(&self) -> usize { + 2 + } + fn num_geometries(&self) -> usize { self.0.len() } diff --git a/geo-traits/src/iterator.rs b/geo-traits/src/iterator.rs index 9de6e589c5..f4b920cb7d 100644 --- a/geo-traits/src/iterator.rs +++ b/geo-traits/src/iterator.rs @@ -1,6 +1,6 @@ use super::{ - CoordTrait, GeometryCollectionTrait, GeometryTrait, LineStringTrait, MultiLineStringTrait, - MultiPointTrait, MultiPolygonTrait, PointTrait, PolygonTrait, + GeometryCollectionTrait, GeometryTrait, LineStringTrait, MultiLineStringTrait, MultiPointTrait, + MultiPolygonTrait, PointTrait, PolygonTrait, }; use geo_types::CoordNum; @@ -25,6 +25,7 @@ macro_rules! impl_iterator { G: $self_trait = ItemType>, > $struct_name<'a, T, ItemType, G> { + /// Create a new iterator pub fn new(geom: &'a G, index: usize, end: usize) -> Self { Self { geom, index, end } } @@ -78,7 +79,7 @@ macro_rules! impl_iterator { impl_iterator!( LineStringIterator, LineStringTrait, - CoordTrait, + PointTrait, coord_unchecked ); impl_iterator!( diff --git a/geo-traits/src/lib.rs b/geo-traits/src/lib.rs index f0d160eed7..0a43b815cb 100644 --- a/geo-traits/src/lib.rs +++ b/geo-traits/src/lib.rs @@ -5,7 +5,6 @@ //! _any_ source without overhead, not limited to just the layout defined in the [`geo-types`] //! crate. -pub use coord::CoordTrait; pub use geometry::{GeometryTrait, GeometryType}; pub use geometry_collection::GeometryCollectionTrait; pub use iterator::{ @@ -20,7 +19,6 @@ pub use point::PointTrait; pub use polygon::PolygonTrait; pub use rect::RectTrait; -mod coord; mod geometry; mod geometry_collection; mod iterator; diff --git a/geo-traits/src/line_string.rs b/geo-traits/src/line_string.rs index 8a591ee574..3ba3d49b1e 100644 --- a/geo-traits/src/line_string.rs +++ b/geo-traits/src/line_string.rs @@ -1,13 +1,19 @@ -use super::{CoordTrait, LineStringIterator}; +use super::{LineStringIterator, PointTrait}; use geo_types::{Coord, CoordNum, LineString}; /// A trait for accessing data from a generic LineString. pub trait LineStringTrait: Sized { + /// The coordinate type of this geometry type T: CoordNum; - type ItemType<'a>: 'a + CoordTrait + + /// The type of each underlying coordinate, which implements [PointTrait] + type ItemType<'a>: 'a + PointTrait where Self: 'a; + /// The number of dimensions in this geometry + fn dim(&self) -> usize; + /// An iterator over the coords in this LineString fn coords(&self) -> LineStringIterator<'_, Self::T, Self::ItemType<'_>, Self> { LineStringIterator::new(self, 0, self.num_coords()) @@ -39,6 +45,10 @@ impl LineStringTrait for LineString { type T = T; type ItemType<'a> = &'a Coord where Self: 'a; + fn dim(&self) -> usize { + 2 + } + fn num_coords(&self) -> usize { self.0.len() } @@ -52,6 +62,10 @@ impl<'a, T: CoordNum> LineStringTrait for &'a LineString { type T = T; type ItemType<'b> = &'a Coord where Self: 'b; + fn dim(&self) -> usize { + 2 + } + fn num_coords(&self) -> usize { self.0.len() } diff --git a/geo-traits/src/multi_line_string.rs b/geo-traits/src/multi_line_string.rs index 88549c1843..8f4f8124aa 100644 --- a/geo-traits/src/multi_line_string.rs +++ b/geo-traits/src/multi_line_string.rs @@ -3,11 +3,17 @@ use geo_types::{CoordNum, LineString, MultiLineString}; /// A trait for accessing data from a generic MultiLineString. pub trait MultiLineStringTrait: Sized { + /// The coordinate type of this geometry type T: CoordNum; + + /// The type of each underlying LineString, which implements [LineStringTrait] type ItemType<'a>: 'a + LineStringTrait where Self: 'a; + /// The number of dimensions in this geometry + fn dim(&self) -> usize; + /// An iterator over the LineStrings in this MultiLineString fn lines(&self) -> MultiLineStringIterator<'_, Self::T, Self::ItemType<'_>, Self> { MultiLineStringIterator::new(self, 0, self.num_lines()) @@ -38,6 +44,10 @@ impl MultiLineStringTrait for MultiLineString { type T = T; type ItemType<'a> = &'a LineString where Self: 'a; + fn dim(&self) -> usize { + 2 + } + fn num_lines(&self) -> usize { self.0.len() } @@ -51,6 +61,10 @@ impl<'a, T: CoordNum> MultiLineStringTrait for &'a MultiLineString { type T = T; type ItemType<'b> = &'a LineString where Self: 'b; + fn dim(&self) -> usize { + 2 + } + fn num_lines(&self) -> usize { self.0.len() } diff --git a/geo-traits/src/multi_point.rs b/geo-traits/src/multi_point.rs index d7f20d9cae..b717390ff9 100644 --- a/geo-traits/src/multi_point.rs +++ b/geo-traits/src/multi_point.rs @@ -3,11 +3,17 @@ use geo_types::{CoordNum, MultiPoint, Point}; /// A trait for accessing data from a generic MultiPoint. pub trait MultiPointTrait: Sized { + /// The coordinate type of this geometry type T: CoordNum; + + /// The type of each underlying Point, which implements [PointTrait] type ItemType<'a>: 'a + PointTrait where Self: 'a; + /// The number of dimensions in this geometry + fn dim(&self) -> usize; + /// An iterator over the points in this MultiPoint fn points(&self) -> MultiPointIterator<'_, Self::T, Self::ItemType<'_>, Self> { MultiPointIterator::new(self, 0, self.num_points()) @@ -38,6 +44,10 @@ impl MultiPointTrait for MultiPoint { type T = T; type ItemType<'a> = &'a Point where Self: 'a; + fn dim(&self) -> usize { + 2 + } + fn num_points(&self) -> usize { self.0.len() } @@ -51,6 +61,10 @@ impl<'a, T: CoordNum> MultiPointTrait for &'a MultiPoint { type T = T; type ItemType<'b> = &'a Point where Self: 'b; + fn dim(&self) -> usize { + 2 + } + fn num_points(&self) -> usize { self.0.len() } diff --git a/geo-traits/src/multi_polygon.rs b/geo-traits/src/multi_polygon.rs index e4e6c2e20c..be52879964 100644 --- a/geo-traits/src/multi_polygon.rs +++ b/geo-traits/src/multi_polygon.rs @@ -3,11 +3,17 @@ use geo_types::{CoordNum, MultiPolygon, Polygon}; /// A trait for accessing data from a generic MultiPolygon. pub trait MultiPolygonTrait: Sized { + /// The coordinate type of this geometry type T: CoordNum; + + /// The type of each underlying Polygon, which implements [PolygonTrait] type ItemType<'a>: 'a + PolygonTrait where Self: 'a; + /// The number of dimensions in this geometry + fn dim(&self) -> usize; + /// An iterator over the Polygons in this MultiPolygon fn polygons(&self) -> MultiPolygonIterator<'_, Self::T, Self::ItemType<'_>, Self> { MultiPolygonIterator::new(self, 0, self.num_polygons()) @@ -38,6 +44,10 @@ impl MultiPolygonTrait for MultiPolygon { type T = T; type ItemType<'a> = &'a Polygon where Self: 'a; + fn dim(&self) -> usize { + 2 + } + fn num_polygons(&self) -> usize { self.0.len() } @@ -51,6 +61,10 @@ impl<'a, T: CoordNum> MultiPolygonTrait for &'a MultiPolygon { type T = T; type ItemType<'b> = &'a Polygon where Self: 'b; + fn dim(&self) -> usize { + 2 + } + fn num_polygons(&self) -> usize { self.0.len() } diff --git a/geo-traits/src/point.rs b/geo-traits/src/point.rs index 8c17ad063e..261d3bde3e 100644 --- a/geo-traits/src/point.rs +++ b/geo-traits/src/point.rs @@ -2,8 +2,28 @@ use geo_types::{Coord, CoordNum, Point}; /// A trait for accessing data from a generic Point. pub trait PointTrait { + /// The coordinate type of this geometry type T: CoordNum; + /// Access the n'th (0-based) element of the CoordinateTuple. + /// May panic if n >= DIMENSION. + /// See also [`nth()`](Self::nth). + fn nth_unchecked(&self, n: usize) -> Self::T; + + /// Native dimension of the coordinate tuple + fn dim(&self) -> usize; + + /// Access the n'th (0-based) element of the CoordinateTuple. + /// Returns NaN if `n >= DIMENSION`. + /// See also [`nth()`](Self::nth_unchecked). + fn nth(&self, n: usize) -> Option { + if n < self.dim() { + Some(self.nth_unchecked(n)) + } else { + None + } + } + /// x component of this point. fn x(&self) -> Self::T; @@ -19,6 +39,18 @@ pub trait PointTrait { impl PointTrait for Point { type T = T; + fn nth_unchecked(&self, n: usize) -> Self::T { + match n { + 0 => self.x(), + 1 => self.y(), + _ => panic!(), + } + } + + fn dim(&self) -> usize { + 2 + } + fn x(&self) -> Self::T { self.0.x } @@ -31,6 +63,18 @@ impl PointTrait for Point { impl PointTrait for &Point { type T = T; + fn nth_unchecked(&self, n: usize) -> Self::T { + match n { + 0 => self.x(), + 1 => self.y(), + _ => panic!(), + } + } + + fn dim(&self) -> usize { + 2 + } + fn x(&self) -> Self::T { self.0.x } @@ -43,6 +87,18 @@ impl PointTrait for &Point { impl PointTrait for Coord { type T = T; + fn nth_unchecked(&self, n: usize) -> Self::T { + match n { + 0 => self.x(), + 1 => self.y(), + _ => panic!(), + } + } + + fn dim(&self) -> usize { + 2 + } + fn x(&self) -> Self::T { self.x } @@ -55,6 +111,18 @@ impl PointTrait for Coord { impl PointTrait for &Coord { type T = T; + fn nth_unchecked(&self, n: usize) -> Self::T { + match n { + 0 => self.x(), + 1 => self.y(), + _ => panic!(), + } + } + + fn dim(&self) -> usize { + 2 + } + fn x(&self) -> Self::T { self.x } @@ -63,3 +131,47 @@ impl PointTrait for &Coord { self.y } } + +impl PointTrait for (T, T) { + type T = T; + + fn nth_unchecked(&self, n: usize) -> Self::T { + match n { + 0 => self.x(), + 1 => self.y(), + _ => panic!(), + } + } + + fn dim(&self) -> usize { + 2 + } + + fn x(&self) -> Self::T { + self.0 + } + + fn y(&self) -> Self::T { + self.1 + } +} + +impl PointTrait for [T; D] { + type T = T; + + fn nth_unchecked(&self, n: usize) -> Self::T { + self[n] + } + + fn dim(&self) -> usize { + D + } + + fn x(&self) -> Self::T { + self[0] + } + + fn y(&self) -> Self::T { + self[1] + } +} diff --git a/geo-traits/src/polygon.rs b/geo-traits/src/polygon.rs index 0f5187e5a6..bcbd1d34ce 100644 --- a/geo-traits/src/polygon.rs +++ b/geo-traits/src/polygon.rs @@ -3,11 +3,17 @@ use geo_types::{CoordNum, LineString, Polygon}; /// A trait for accessing data from a generic Polygon. pub trait PolygonTrait: Sized { + /// The coordinate type of this geometry type T: CoordNum; + + /// The type of each underlying ring, which implements [LineStringTrait] type ItemType<'a>: 'a + LineStringTrait where Self: 'a; + /// The number of dimensions in this geometry + fn dim(&self) -> usize; + /// The exterior ring of the polygon fn exterior(&self) -> Option>; @@ -41,6 +47,10 @@ impl PolygonTrait for Polygon { type T = T; type ItemType<'a> = &'a LineString where Self: 'a; + fn dim(&self) -> usize { + 2 + } + fn exterior(&self) -> Option> { // geo-types doesn't really have a way to describe an empty polygon Some(Polygon::exterior(self)) @@ -60,6 +70,10 @@ impl<'a, T: CoordNum> PolygonTrait for &'a Polygon { type ItemType<'b> = &'a LineString where Self: 'b; + fn dim(&self) -> usize { + 2 + } + fn exterior(&self) -> Option> { // geo-types doesn't really have a way to describe an empty polygon Some(Polygon::exterior(self)) diff --git a/geo-traits/src/rect.rs b/geo-traits/src/rect.rs index b31be57c3e..270a2cffc6 100644 --- a/geo-traits/src/rect.rs +++ b/geo-traits/src/rect.rs @@ -1,16 +1,24 @@ use geo_types::{Coord, CoordNum, Rect}; -use super::CoordTrait; +use super::PointTrait; /// A trait for accessing data from a generic Rect. pub trait RectTrait { + /// The coordinate type of this geometry type T: CoordNum; - type ItemType<'a>: 'a + CoordTrait + + /// The type of each underlying coordinate, which implements [PointTrait] + type ItemType<'a>: 'a + PointTrait where Self: 'a; + /// The number of dimensions in this geometry + fn dim(&self) -> usize; + + /// The lower coordinate of this Rect fn lower(&self) -> Self::ItemType<'_>; + /// The upper coordinate of this Rect fn upper(&self) -> Self::ItemType<'_>; } @@ -18,6 +26,10 @@ impl<'a, T: CoordNum + 'a> RectTrait for Rect { type T = T; type ItemType<'b> = Coord where Self: 'b; + fn dim(&self) -> usize { + 2 + } + fn lower(&self) -> Self::ItemType<'_> { self.min() } @@ -31,6 +43,10 @@ impl<'a, T: CoordNum + 'a> RectTrait for &'a Rect { type T = T; type ItemType<'b> = Coord where Self: 'b; + fn dim(&self) -> usize { + 2 + } + fn lower(&self) -> Self::ItemType<'_> { self.min() } From 4261836f548204494b75b1738bf42ab6840f7040 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Thu, 10 Oct 2024 00:20:21 -0400 Subject: [PATCH 06/33] Module docs --- geo-traits/src/lib.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/geo-traits/src/lib.rs b/geo-traits/src/lib.rs index 0a43b815cb..75d1663cf1 100644 --- a/geo-traits/src/lib.rs +++ b/geo-traits/src/lib.rs @@ -1,9 +1,19 @@ -//! An initial, in-progress implementation of [geometry access -//! traits](https://github.com/georust/geo/discussions/838). +//! A trait-based interface for geospatial vector data interchange in Rust. //! -//! The idea is that functions should be able to operate on and consume geospatial vector data from -//! _any_ source without overhead, not limited to just the layout defined in the [`geo-types`] -//! crate. +//! This crate contains a set of traits based on the Simple Features standard for geospatial vector +//! data. These traits are designed to make it easy to operate on and consume geometries throughout +//! the Rust ecosystem without knowing library-specific APIs or memory layouts. +//! +//! It is expected that accessing any individual coordinate or value from a geometry is +//! **constant-time**. This means that when implementing these traits on a format like WKB that +//! requires linear-time search to locate coordinates, the WKB wrapper should have already +//! undergone an initial pass to find the relevant byte offsets where coordinate sequences start +//! and end. +//! +//! This interface will usually but not always be zero-copy. Coordinate access is expected to be +//! constant-time but not necessarily _free_. For example, WKB is not aligned and may use a +//! different endianness than the current machine, so individual values may need to be cloned on +//! read. pub use geometry::{GeometryTrait, GeometryType}; pub use geometry_collection::GeometryCollectionTrait; From 449b39fed135b8048ddd4129d1026902396661c4 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Thu, 10 Oct 2024 00:30:47 -0400 Subject: [PATCH 07/33] rename --- geo-traits/src/iterator.rs | 4 ++-- geo-traits/src/line_string.rs | 26 +++++++++++++------------- geo-traits/src/multi_line_string.rs | 28 ++++++++++++++-------------- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/geo-traits/src/iterator.rs b/geo-traits/src/iterator.rs index f4b920cb7d..c363132de4 100644 --- a/geo-traits/src/iterator.rs +++ b/geo-traits/src/iterator.rs @@ -80,7 +80,7 @@ impl_iterator!( LineStringIterator, LineStringTrait, PointTrait, - coord_unchecked + point_unchecked ); impl_iterator!( PolygonInteriorIterator, @@ -98,7 +98,7 @@ impl_iterator!( MultiLineStringIterator, MultiLineStringTrait, LineStringTrait, - line_unchecked + line_string_unchecked ); impl_iterator!( MultiPolygonIterator, diff --git a/geo-traits/src/line_string.rs b/geo-traits/src/line_string.rs index 3ba3d49b1e..25ecf0d674 100644 --- a/geo-traits/src/line_string.rs +++ b/geo-traits/src/line_string.rs @@ -14,22 +14,22 @@ pub trait LineStringTrait: Sized { /// The number of dimensions in this geometry fn dim(&self) -> usize; - /// An iterator over the coords in this LineString - fn coords(&self) -> LineStringIterator<'_, Self::T, Self::ItemType<'_>, Self> { - LineStringIterator::new(self, 0, self.num_coords()) + /// An iterator over the points in this LineString + fn points(&self) -> LineStringIterator<'_, Self::T, Self::ItemType<'_>, Self> { + LineStringIterator::new(self, 0, self.num_points()) } - /// The number of coords in this LineString - fn num_coords(&self) -> usize; + /// The number of points in this LineString + fn num_points(&self) -> usize; /// Access to a specified point in this LineString /// Will return None if the provided index is out of bounds #[inline] - fn coord(&self, i: usize) -> Option> { - if i >= self.num_coords() { + fn point(&self, i: usize) -> Option> { + if i >= self.num_points() { None } else { - unsafe { Some(self.coord_unchecked(i)) } + unsafe { Some(self.point_unchecked(i)) } } } @@ -38,7 +38,7 @@ pub trait LineStringTrait: Sized { /// # Safety /// /// Accessing an index out of bounds is UB. - unsafe fn coord_unchecked(&self, i: usize) -> Self::ItemType<'_>; + unsafe fn point_unchecked(&self, i: usize) -> Self::ItemType<'_>; } impl LineStringTrait for LineString { @@ -49,11 +49,11 @@ impl LineStringTrait for LineString { 2 } - fn num_coords(&self) -> usize { + fn num_points(&self) -> usize { self.0.len() } - unsafe fn coord_unchecked(&self, i: usize) -> Self::ItemType<'_> { + unsafe fn point_unchecked(&self, i: usize) -> Self::ItemType<'_> { self.0.get_unchecked(i) } } @@ -66,11 +66,11 @@ impl<'a, T: CoordNum> LineStringTrait for &'a LineString { 2 } - fn num_coords(&self) -> usize { + fn num_points(&self) -> usize { self.0.len() } - unsafe fn coord_unchecked(&self, i: usize) -> Self::ItemType<'_> { + unsafe fn point_unchecked(&self, i: usize) -> Self::ItemType<'_> { self.0.get_unchecked(i) } } diff --git a/geo-traits/src/multi_line_string.rs b/geo-traits/src/multi_line_string.rs index 8f4f8124aa..868d0dcba6 100644 --- a/geo-traits/src/multi_line_string.rs +++ b/geo-traits/src/multi_line_string.rs @@ -15,29 +15,29 @@ pub trait MultiLineStringTrait: Sized { fn dim(&self) -> usize; /// An iterator over the LineStrings in this MultiLineString - fn lines(&self) -> MultiLineStringIterator<'_, Self::T, Self::ItemType<'_>, Self> { - MultiLineStringIterator::new(self, 0, self.num_lines()) + fn line_strings(&self) -> MultiLineStringIterator<'_, Self::T, Self::ItemType<'_>, Self> { + MultiLineStringIterator::new(self, 0, self.num_line_strings()) } - /// The number of lines in this MultiLineString - fn num_lines(&self) -> usize; + /// The number of line_strings in this MultiLineString + fn num_line_strings(&self) -> usize; - /// Access to a specified line in this MultiLineString + /// Access to a specified line_string in this MultiLineString /// Will return None if the provided index is out of bounds - fn line(&self, i: usize) -> Option> { - if i >= self.num_lines() { + fn line_string(&self, i: usize) -> Option> { + if i >= self.num_line_strings() { None } else { - unsafe { Some(self.line_unchecked(i)) } + unsafe { Some(self.line_string_unchecked(i)) } } } - /// Access to a specified line in this MultiLineString + /// Access to a specified line_string in this MultiLineString /// /// # Safety /// /// Accessing an index out of bounds is UB. - unsafe fn line_unchecked(&self, i: usize) -> Self::ItemType<'_>; + unsafe fn line_string_unchecked(&self, i: usize) -> Self::ItemType<'_>; } impl MultiLineStringTrait for MultiLineString { @@ -48,11 +48,11 @@ impl MultiLineStringTrait for MultiLineString { 2 } - fn num_lines(&self) -> usize { + fn num_line_strings(&self) -> usize { self.0.len() } - unsafe fn line_unchecked(&self, i: usize) -> Self::ItemType<'_> { + unsafe fn line_string_unchecked(&self, i: usize) -> Self::ItemType<'_> { self.0.get_unchecked(i) } } @@ -65,11 +65,11 @@ impl<'a, T: CoordNum> MultiLineStringTrait for &'a MultiLineString { 2 } - fn num_lines(&self) -> usize { + fn num_line_strings(&self) -> usize { self.0.len() } - unsafe fn line_unchecked(&self, i: usize) -> Self::ItemType<'_> { + unsafe fn line_string_unchecked(&self, i: usize) -> Self::ItemType<'_> { self.0.get_unchecked(i) } } From f54fffc0fc2b7170593e048b12945af75321ab11 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Thu, 10 Oct 2024 21:22:25 -0400 Subject: [PATCH 08/33] Add logical Dimension --- geo-traits/src/dimension.rs | 34 +++++++++++++++++++ geo-traits/src/geometry.rs | 16 ++++----- geo-traits/src/geometry_collection.rs | 14 ++++---- geo-traits/src/lib.rs | 2 ++ geo-traits/src/line_string.rs | 14 ++++---- geo-traits/src/multi_line_string.rs | 14 ++++---- geo-traits/src/multi_point.rs | 14 ++++---- geo-traits/src/multi_polygon.rs | 14 ++++---- geo-traits/src/point.rs | 48 +++++++++------------------ geo-traits/src/polygon.rs | 14 ++++---- geo-traits/src/rect.rs | 14 ++++---- 11 files changed, 108 insertions(+), 90 deletions(-) create mode 100644 geo-traits/src/dimension.rs diff --git a/geo-traits/src/dimension.rs b/geo-traits/src/dimension.rs new file mode 100644 index 0000000000..5b2340d534 --- /dev/null +++ b/geo-traits/src/dimension.rs @@ -0,0 +1,34 @@ +/// The logical dimension of the geometry. +/// +/// +#[allow(clippy::upper_case_acronyms)] +#[derive(Debug, Clone, Copy)] +pub enum Dimension { + /// A two-dimensional geometry with X and Y values + XY, + + /// A three-dimensional geometry with X, Y, and Z values + XYZ, + + /// A three-dimensional geometry with X, Y, and M values + XYM, + + /// A four-dimensional geometry with X, Y, Z, and M values + XYZM, + + /// A geometry with unknown logical type. The contained `usize` value represents the number of + /// physical dimensions. + Unknown(usize), +} + +impl Dimension { + /// The physical number of dimensions in this geometry. + pub fn size(&self) -> usize { + match self { + Self::XY => 2, + Self::XYZ | Self::XYM => 3, + Self::XYZM => 4, + Self::Unknown(val) => *val, + } + } +} diff --git a/geo-traits/src/geometry.rs b/geo-traits/src/geometry.rs index f877a4b1d2..8233e5eae9 100644 --- a/geo-traits/src/geometry.rs +++ b/geo-traits/src/geometry.rs @@ -3,8 +3,8 @@ use geo_types::{ Point, Polygon, Rect, }; -use super::{ - GeometryCollectionTrait, LineStringTrait, MultiLineStringTrait, MultiPointTrait, +use crate::{ + Dimension, GeometryCollectionTrait, LineStringTrait, MultiLineStringTrait, MultiPointTrait, MultiPolygonTrait, PointTrait, PolygonTrait, RectTrait, }; @@ -54,8 +54,8 @@ pub trait GeometryTrait { where Self: 'a; - /// The number of dimensions in this geometry - fn dim(&self) -> usize; + /// The dimension of this geometry + fn dim(&self) -> Dimension; /// Cast this geometry to a [`GeometryType`] enum, which allows for downcasting to a specific /// type @@ -117,8 +117,8 @@ impl<'a, T: CoordNum + 'a> GeometryTrait for Geometry { type GeometryCollection<'b> = GeometryCollection where Self: 'b; type Rect<'b> = Rect where Self: 'b; - fn dim(&self) -> usize { - 2 + fn dim(&self) -> Dimension { + Dimension::XY } fn as_type( @@ -159,8 +159,8 @@ impl<'a, T: CoordNum + 'a> GeometryTrait for &'a Geometry { type GeometryCollection<'b> = GeometryCollection where Self: 'b; type Rect<'b> = Rect where Self: 'b; - fn dim(&self) -> usize { - 2 + fn dim(&self) -> Dimension { + Dimension::XY } fn as_type( diff --git a/geo-traits/src/geometry_collection.rs b/geo-traits/src/geometry_collection.rs index f107252073..056e5b014d 100644 --- a/geo-traits/src/geometry_collection.rs +++ b/geo-traits/src/geometry_collection.rs @@ -1,4 +1,4 @@ -use super::{GeometryCollectionIterator, GeometryTrait}; +use crate::{Dimension, GeometryCollectionIterator, GeometryTrait}; use geo_types::{CoordNum, Geometry, GeometryCollection}; /// A trait for accessing data from a generic GeometryCollection. @@ -11,8 +11,8 @@ pub trait GeometryCollectionTrait: Sized { where Self: 'a; - /// The number of dimensions in this geometry - fn dim(&self) -> usize; + /// The dimension of this geometry + fn dim(&self) -> Dimension; /// An iterator over the geometries in this GeometryCollection fn geometries(&self) -> GeometryCollectionIterator<'_, Self::T, Self::ItemType<'_>, Self> { @@ -46,8 +46,8 @@ impl GeometryCollectionTrait for GeometryCollection { where Self: 'a; - fn dim(&self) -> usize { - 2 + fn dim(&self) -> Dimension { + Dimension::XY } fn num_geometries(&self) -> usize { @@ -64,8 +64,8 @@ impl<'a, T: CoordNum> GeometryCollectionTrait for &'a GeometryCollection { type ItemType<'b> = &'a Geometry where Self: 'b; - fn dim(&self) -> usize { - 2 + fn dim(&self) -> Dimension { + Dimension::XY } fn num_geometries(&self) -> usize { diff --git a/geo-traits/src/lib.rs b/geo-traits/src/lib.rs index 75d1663cf1..b5ea8c6cd2 100644 --- a/geo-traits/src/lib.rs +++ b/geo-traits/src/lib.rs @@ -15,6 +15,7 @@ //! different endianness than the current machine, so individual values may need to be cloned on //! read. +pub use dimension::Dimension; pub use geometry::{GeometryTrait, GeometryType}; pub use geometry_collection::GeometryCollectionTrait; pub use iterator::{ @@ -29,6 +30,7 @@ pub use point::PointTrait; pub use polygon::PolygonTrait; pub use rect::RectTrait; +mod dimension; mod geometry; mod geometry_collection; mod iterator; diff --git a/geo-traits/src/line_string.rs b/geo-traits/src/line_string.rs index 25ecf0d674..7f35c4e0d7 100644 --- a/geo-traits/src/line_string.rs +++ b/geo-traits/src/line_string.rs @@ -1,4 +1,4 @@ -use super::{LineStringIterator, PointTrait}; +use crate::{Dimension, LineStringIterator, PointTrait}; use geo_types::{Coord, CoordNum, LineString}; /// A trait for accessing data from a generic LineString. @@ -11,8 +11,8 @@ pub trait LineStringTrait: Sized { where Self: 'a; - /// The number of dimensions in this geometry - fn dim(&self) -> usize; + /// The dimension of this geometry + fn dim(&self) -> Dimension; /// An iterator over the points in this LineString fn points(&self) -> LineStringIterator<'_, Self::T, Self::ItemType<'_>, Self> { @@ -45,8 +45,8 @@ impl LineStringTrait for LineString { type T = T; type ItemType<'a> = &'a Coord where Self: 'a; - fn dim(&self) -> usize { - 2 + fn dim(&self) -> Dimension { + Dimension::XY } fn num_points(&self) -> usize { @@ -62,8 +62,8 @@ impl<'a, T: CoordNum> LineStringTrait for &'a LineString { type T = T; type ItemType<'b> = &'a Coord where Self: 'b; - fn dim(&self) -> usize { - 2 + fn dim(&self) -> Dimension { + Dimension::XY } fn num_points(&self) -> usize { diff --git a/geo-traits/src/multi_line_string.rs b/geo-traits/src/multi_line_string.rs index 868d0dcba6..4585b7c053 100644 --- a/geo-traits/src/multi_line_string.rs +++ b/geo-traits/src/multi_line_string.rs @@ -1,4 +1,4 @@ -use super::{LineStringTrait, MultiLineStringIterator}; +use crate::{Dimension, LineStringTrait, MultiLineStringIterator}; use geo_types::{CoordNum, LineString, MultiLineString}; /// A trait for accessing data from a generic MultiLineString. @@ -11,8 +11,8 @@ pub trait MultiLineStringTrait: Sized { where Self: 'a; - /// The number of dimensions in this geometry - fn dim(&self) -> usize; + /// The dimension of this geometry + fn dim(&self) -> Dimension; /// An iterator over the LineStrings in this MultiLineString fn line_strings(&self) -> MultiLineStringIterator<'_, Self::T, Self::ItemType<'_>, Self> { @@ -44,8 +44,8 @@ impl MultiLineStringTrait for MultiLineString { type T = T; type ItemType<'a> = &'a LineString where Self: 'a; - fn dim(&self) -> usize { - 2 + fn dim(&self) -> Dimension { + Dimension::XY } fn num_line_strings(&self) -> usize { @@ -61,8 +61,8 @@ impl<'a, T: CoordNum> MultiLineStringTrait for &'a MultiLineString { type T = T; type ItemType<'b> = &'a LineString where Self: 'b; - fn dim(&self) -> usize { - 2 + fn dim(&self) -> Dimension { + Dimension::XY } fn num_line_strings(&self) -> usize { diff --git a/geo-traits/src/multi_point.rs b/geo-traits/src/multi_point.rs index b717390ff9..1d209edff0 100644 --- a/geo-traits/src/multi_point.rs +++ b/geo-traits/src/multi_point.rs @@ -1,4 +1,4 @@ -use super::{MultiPointIterator, PointTrait}; +use crate::{Dimension, MultiPointIterator, PointTrait}; use geo_types::{CoordNum, MultiPoint, Point}; /// A trait for accessing data from a generic MultiPoint. @@ -11,8 +11,8 @@ pub trait MultiPointTrait: Sized { where Self: 'a; - /// The number of dimensions in this geometry - fn dim(&self) -> usize; + /// The dimension of this geometry + fn dim(&self) -> Dimension; /// An iterator over the points in this MultiPoint fn points(&self) -> MultiPointIterator<'_, Self::T, Self::ItemType<'_>, Self> { @@ -44,8 +44,8 @@ impl MultiPointTrait for MultiPoint { type T = T; type ItemType<'a> = &'a Point where Self: 'a; - fn dim(&self) -> usize { - 2 + fn dim(&self) -> Dimension { + Dimension::XY } fn num_points(&self) -> usize { @@ -61,8 +61,8 @@ impl<'a, T: CoordNum> MultiPointTrait for &'a MultiPoint { type T = T; type ItemType<'b> = &'a Point where Self: 'b; - fn dim(&self) -> usize { - 2 + fn dim(&self) -> Dimension { + Dimension::XY } fn num_points(&self) -> usize { diff --git a/geo-traits/src/multi_polygon.rs b/geo-traits/src/multi_polygon.rs index be52879964..fc0256e6c4 100644 --- a/geo-traits/src/multi_polygon.rs +++ b/geo-traits/src/multi_polygon.rs @@ -1,4 +1,4 @@ -use super::{MultiPolygonIterator, PolygonTrait}; +use crate::{Dimension, MultiPolygonIterator, PolygonTrait}; use geo_types::{CoordNum, MultiPolygon, Polygon}; /// A trait for accessing data from a generic MultiPolygon. @@ -11,8 +11,8 @@ pub trait MultiPolygonTrait: Sized { where Self: 'a; - /// The number of dimensions in this geometry - fn dim(&self) -> usize; + /// The dimension of this geometry + fn dim(&self) -> Dimension; /// An iterator over the Polygons in this MultiPolygon fn polygons(&self) -> MultiPolygonIterator<'_, Self::T, Self::ItemType<'_>, Self> { @@ -44,8 +44,8 @@ impl MultiPolygonTrait for MultiPolygon { type T = T; type ItemType<'a> = &'a Polygon where Self: 'a; - fn dim(&self) -> usize { - 2 + fn dim(&self) -> Dimension { + Dimension::XY } fn num_polygons(&self) -> usize { @@ -61,8 +61,8 @@ impl<'a, T: CoordNum> MultiPolygonTrait for &'a MultiPolygon { type T = T; type ItemType<'b> = &'a Polygon where Self: 'b; - fn dim(&self) -> usize { - 2 + fn dim(&self) -> Dimension { + Dimension::XY } fn num_polygons(&self) -> usize { diff --git a/geo-traits/src/point.rs b/geo-traits/src/point.rs index 261d3bde3e..599b3d2ba3 100644 --- a/geo-traits/src/point.rs +++ b/geo-traits/src/point.rs @@ -1,5 +1,7 @@ use geo_types::{Coord, CoordNum, Point}; +use crate::Dimension; + /// A trait for accessing data from a generic Point. pub trait PointTrait { /// The coordinate type of this geometry @@ -10,14 +12,14 @@ pub trait PointTrait { /// See also [`nth()`](Self::nth). fn nth_unchecked(&self, n: usize) -> Self::T; - /// Native dimension of the coordinate tuple - fn dim(&self) -> usize; + /// Dimension of the coordinate tuple + fn dim(&self) -> Dimension; /// Access the n'th (0-based) element of the CoordinateTuple. /// Returns NaN if `n >= DIMENSION`. /// See also [`nth()`](Self::nth_unchecked). fn nth(&self, n: usize) -> Option { - if n < self.dim() { + if n < self.dim().size() { Some(self.nth_unchecked(n)) } else { None @@ -47,8 +49,8 @@ impl PointTrait for Point { } } - fn dim(&self) -> usize { - 2 + fn dim(&self) -> Dimension { + Dimension::XY } fn x(&self) -> Self::T { @@ -71,8 +73,8 @@ impl PointTrait for &Point { } } - fn dim(&self) -> usize { - 2 + fn dim(&self) -> Dimension { + Dimension::XY } fn x(&self) -> Self::T { @@ -95,8 +97,8 @@ impl PointTrait for Coord { } } - fn dim(&self) -> usize { - 2 + fn dim(&self) -> Dimension { + Dimension::XY } fn x(&self) -> Self::T { @@ -119,8 +121,8 @@ impl PointTrait for &Coord { } } - fn dim(&self) -> usize { - 2 + fn dim(&self) -> Dimension { + Dimension::XY } fn x(&self) -> Self::T { @@ -143,8 +145,8 @@ impl PointTrait for (T, T) { } } - fn dim(&self) -> usize { - 2 + fn dim(&self) -> Dimension { + Dimension::XY } fn x(&self) -> Self::T { @@ -155,23 +157,3 @@ impl PointTrait for (T, T) { self.1 } } - -impl PointTrait for [T; D] { - type T = T; - - fn nth_unchecked(&self, n: usize) -> Self::T { - self[n] - } - - fn dim(&self) -> usize { - D - } - - fn x(&self) -> Self::T { - self[0] - } - - fn y(&self) -> Self::T { - self[1] - } -} diff --git a/geo-traits/src/polygon.rs b/geo-traits/src/polygon.rs index bcbd1d34ce..a1a3ff71b2 100644 --- a/geo-traits/src/polygon.rs +++ b/geo-traits/src/polygon.rs @@ -1,4 +1,4 @@ -use super::{LineStringTrait, PolygonInteriorIterator}; +use crate::{Dimension, LineStringTrait, PolygonInteriorIterator}; use geo_types::{CoordNum, LineString, Polygon}; /// A trait for accessing data from a generic Polygon. @@ -11,8 +11,8 @@ pub trait PolygonTrait: Sized { where Self: 'a; - /// The number of dimensions in this geometry - fn dim(&self) -> usize; + /// The dimension of this geometry + fn dim(&self) -> Dimension; /// The exterior ring of the polygon fn exterior(&self) -> Option>; @@ -47,8 +47,8 @@ impl PolygonTrait for Polygon { type T = T; type ItemType<'a> = &'a LineString where Self: 'a; - fn dim(&self) -> usize { - 2 + fn dim(&self) -> Dimension { + Dimension::XY } fn exterior(&self) -> Option> { @@ -70,8 +70,8 @@ impl<'a, T: CoordNum> PolygonTrait for &'a Polygon { type ItemType<'b> = &'a LineString where Self: 'b; - fn dim(&self) -> usize { - 2 + fn dim(&self) -> Dimension { + Dimension::XY } fn exterior(&self) -> Option> { diff --git a/geo-traits/src/rect.rs b/geo-traits/src/rect.rs index 270a2cffc6..d9f348885a 100644 --- a/geo-traits/src/rect.rs +++ b/geo-traits/src/rect.rs @@ -1,6 +1,6 @@ use geo_types::{Coord, CoordNum, Rect}; -use super::PointTrait; +use crate::{Dimension, PointTrait}; /// A trait for accessing data from a generic Rect. pub trait RectTrait { @@ -12,8 +12,8 @@ pub trait RectTrait { where Self: 'a; - /// The number of dimensions in this geometry - fn dim(&self) -> usize; + /// The dimension of this geometry + fn dim(&self) -> Dimension; /// The lower coordinate of this Rect fn lower(&self) -> Self::ItemType<'_>; @@ -26,8 +26,8 @@ impl<'a, T: CoordNum + 'a> RectTrait for Rect { type T = T; type ItemType<'b> = Coord where Self: 'b; - fn dim(&self) -> usize { - 2 + fn dim(&self) -> Dimension { + Dimension::XY } fn lower(&self) -> Self::ItemType<'_> { @@ -43,8 +43,8 @@ impl<'a, T: CoordNum + 'a> RectTrait for &'a Rect { type T = T; type ItemType<'b> = Coord where Self: 'b; - fn dim(&self) -> usize { - 2 + fn dim(&self) -> Dimension { + Dimension::XY } fn lower(&self) -> Self::ItemType<'_> { From db08c55650352fbd3c23a40acb9abdd00190aaac Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Thu, 10 Oct 2024 22:27:26 -0400 Subject: [PATCH 09/33] partialeq and hash --- geo-traits/src/dimension.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geo-traits/src/dimension.rs b/geo-traits/src/dimension.rs index 5b2340d534..856d7e16db 100644 --- a/geo-traits/src/dimension.rs +++ b/geo-traits/src/dimension.rs @@ -2,7 +2,7 @@ /// /// #[allow(clippy::upper_case_acronyms)] -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Dimension { /// A two-dimensional geometry with X and Y values XY, From 7ecdb7ed586678f46f7635c88f2064e68ac9d61e Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Sat, 12 Oct 2024 13:40:29 -0400 Subject: [PATCH 10/33] return impl Iterator --- geo-traits/src/geometry_collection.rs | 2 +- geo-traits/src/line_string.rs | 2 +- geo-traits/src/multi_line_string.rs | 2 +- geo-traits/src/multi_point.rs | 2 +- geo-traits/src/multi_polygon.rs | 2 +- geo-traits/src/polygon.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/geo-traits/src/geometry_collection.rs b/geo-traits/src/geometry_collection.rs index 056e5b014d..f074297257 100644 --- a/geo-traits/src/geometry_collection.rs +++ b/geo-traits/src/geometry_collection.rs @@ -15,7 +15,7 @@ pub trait GeometryCollectionTrait: Sized { fn dim(&self) -> Dimension; /// An iterator over the geometries in this GeometryCollection - fn geometries(&self) -> GeometryCollectionIterator<'_, Self::T, Self::ItemType<'_>, Self> { + fn geometries(&self) -> impl Iterator> { GeometryCollectionIterator::new(self, 0, self.num_geometries()) } diff --git a/geo-traits/src/line_string.rs b/geo-traits/src/line_string.rs index 7f35c4e0d7..0383da30e3 100644 --- a/geo-traits/src/line_string.rs +++ b/geo-traits/src/line_string.rs @@ -15,7 +15,7 @@ pub trait LineStringTrait: Sized { fn dim(&self) -> Dimension; /// An iterator over the points in this LineString - fn points(&self) -> LineStringIterator<'_, Self::T, Self::ItemType<'_>, Self> { + fn points(&self) -> impl Iterator> { LineStringIterator::new(self, 0, self.num_points()) } diff --git a/geo-traits/src/multi_line_string.rs b/geo-traits/src/multi_line_string.rs index 4585b7c053..d3ebaac55c 100644 --- a/geo-traits/src/multi_line_string.rs +++ b/geo-traits/src/multi_line_string.rs @@ -15,7 +15,7 @@ pub trait MultiLineStringTrait: Sized { fn dim(&self) -> Dimension; /// An iterator over the LineStrings in this MultiLineString - fn line_strings(&self) -> MultiLineStringIterator<'_, Self::T, Self::ItemType<'_>, Self> { + fn line_strings(&self) -> impl Iterator> { MultiLineStringIterator::new(self, 0, self.num_line_strings()) } diff --git a/geo-traits/src/multi_point.rs b/geo-traits/src/multi_point.rs index 1d209edff0..2fff588c3b 100644 --- a/geo-traits/src/multi_point.rs +++ b/geo-traits/src/multi_point.rs @@ -15,7 +15,7 @@ pub trait MultiPointTrait: Sized { fn dim(&self) -> Dimension; /// An iterator over the points in this MultiPoint - fn points(&self) -> MultiPointIterator<'_, Self::T, Self::ItemType<'_>, Self> { + fn points(&self) -> impl Iterator> { MultiPointIterator::new(self, 0, self.num_points()) } diff --git a/geo-traits/src/multi_polygon.rs b/geo-traits/src/multi_polygon.rs index fc0256e6c4..a850ad9c83 100644 --- a/geo-traits/src/multi_polygon.rs +++ b/geo-traits/src/multi_polygon.rs @@ -15,7 +15,7 @@ pub trait MultiPolygonTrait: Sized { fn dim(&self) -> Dimension; /// An iterator over the Polygons in this MultiPolygon - fn polygons(&self) -> MultiPolygonIterator<'_, Self::T, Self::ItemType<'_>, Self> { + fn polygons(&self) -> impl Iterator> { MultiPolygonIterator::new(self, 0, self.num_polygons()) } diff --git a/geo-traits/src/polygon.rs b/geo-traits/src/polygon.rs index a1a3ff71b2..0973d5762f 100644 --- a/geo-traits/src/polygon.rs +++ b/geo-traits/src/polygon.rs @@ -18,7 +18,7 @@ pub trait PolygonTrait: Sized { fn exterior(&self) -> Option>; /// An iterator of the interior rings of this Polygon - fn interiors(&self) -> PolygonInteriorIterator<'_, Self::T, Self::ItemType<'_>, Self> { + fn interiors(&self) -> impl Iterator> { PolygonInteriorIterator::new(self, 0, self.num_interiors()) } From 03f66157bc860fe85b0903c284e8e0918c2dd9d0 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Sat, 12 Oct 2024 13:50:59 -0400 Subject: [PATCH 11/33] rename to min/max --- geo-traits/src/rect.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/geo-traits/src/rect.rs b/geo-traits/src/rect.rs index d9f348885a..a39b9b47fe 100644 --- a/geo-traits/src/rect.rs +++ b/geo-traits/src/rect.rs @@ -15,11 +15,11 @@ pub trait RectTrait { /// The dimension of this geometry fn dim(&self) -> Dimension; - /// The lower coordinate of this Rect - fn lower(&self) -> Self::ItemType<'_>; + /// The minimum coordinate of this Rect + fn min(&self) -> Self::ItemType<'_>; - /// The upper coordinate of this Rect - fn upper(&self) -> Self::ItemType<'_>; + /// The maximum coordinate of this Rect + fn max(&self) -> Self::ItemType<'_>; } impl<'a, T: CoordNum + 'a> RectTrait for Rect { @@ -30,12 +30,12 @@ impl<'a, T: CoordNum + 'a> RectTrait for Rect { Dimension::XY } - fn lower(&self) -> Self::ItemType<'_> { - self.min() + fn min(&self) -> Self::ItemType<'_> { + Rect::min(*self) } - fn upper(&self) -> Self::ItemType<'_> { - self.max() + fn max(&self) -> Self::ItemType<'_> { + Rect::max(*self) } } @@ -47,11 +47,11 @@ impl<'a, T: CoordNum + 'a> RectTrait for &'a Rect { Dimension::XY } - fn lower(&self) -> Self::ItemType<'_> { - self.min() + fn min(&self) -> Self::ItemType<'_> { + Rect::min(**self) } - fn upper(&self) -> Self::ItemType<'_> { - self.max() + fn max(&self) -> Self::ItemType<'_> { + Rect::max(**self) } } From 1d30066ae4297fe8d094ba4e584376dee541ab59 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Sun, 13 Oct 2024 12:07:18 -0400 Subject: [PATCH 12/33] Specialized implementations of GeometryTrait --- geo-traits/src/geometry.rs | 79 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/geo-traits/src/geometry.rs b/geo-traits/src/geometry.rs index 8233e5eae9..16222d6f17 100644 --- a/geo-traits/src/geometry.rs +++ b/geo-traits/src/geometry.rs @@ -189,3 +189,82 @@ impl<'a, T: CoordNum + 'a> GeometryTrait for &'a Geometry { } } } + +// Specialized implementations on each geo-types concrete type. + +macro_rules! impl_specialization { + ($geometry_type:ident) => { + impl GeometryTrait for $geometry_type { + type T = T; + type Point<'b> = Point where Self: 'b; + type LineString<'b> = LineString where Self: 'b; + type Polygon<'b> = Polygon where Self: 'b; + type MultiPoint<'b> = MultiPoint where Self: 'b; + type MultiLineString<'b> = MultiLineString where Self: 'b; + type MultiPolygon<'b> = MultiPolygon where Self: 'b; + type GeometryCollection<'b> = GeometryCollection where Self: 'b; + type Rect<'b> = Rect where Self: 'b; + + fn dim(&self) -> Dimension { + Dimension::XY + } + + fn as_type( + &self, + ) -> GeometryType< + '_, + Point, + LineString, + Polygon, + MultiPoint, + MultiLineString, + MultiPolygon, + GeometryCollection, + Rect, + > { + GeometryType::$geometry_type(self) + } + } + + impl<'a, T: CoordNum + 'a> GeometryTrait for &'a $geometry_type { + type T = T; + type Point<'b> = Point where Self: 'b; + type LineString<'b> = LineString where Self: 'b; + type Polygon<'b> = Polygon where Self: 'b; + type MultiPoint<'b> = MultiPoint where Self: 'b; + type MultiLineString<'b> = MultiLineString where Self: 'b; + type MultiPolygon<'b> = MultiPolygon where Self: 'b; + type GeometryCollection<'b> = GeometryCollection where Self: 'b; + type Rect<'b> = Rect where Self: 'b; + + fn dim(&self) -> Dimension { + Dimension::XY + } + + fn as_type( + &self, + ) -> GeometryType< + '_, + Point, + LineString, + Polygon, + MultiPoint, + MultiLineString, + MultiPolygon, + GeometryCollection, + Rect, + > { + GeometryType::$geometry_type(self) + } + } + }; +} + +impl_specialization!(Point); +impl_specialization!(LineString); +impl_specialization!(Polygon); +impl_specialization!(MultiPoint); +impl_specialization!(MultiLineString); +impl_specialization!(MultiPolygon); +impl_specialization!(GeometryCollection); +impl_specialization!(Rect); From ab0bf7b0d68b33421f138cd3010f39fddf321e0c Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Sun, 13 Oct 2024 12:18:27 -0400 Subject: [PATCH 13/33] clearer GeometryTrait naming --- geo-traits/src/geometry.rs | 96 +++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/geo-traits/src/geometry.rs b/geo-traits/src/geometry.rs index 16222d6f17..c38f1b509c 100644 --- a/geo-traits/src/geometry.rs +++ b/geo-traits/src/geometry.rs @@ -15,42 +15,42 @@ pub trait GeometryTrait { type T: CoordNum; /// The type of each underlying Point, which implements [PointTrait] - type Point<'a>: 'a + PointTrait + type PointType<'a>: 'a + PointTrait where Self: 'a; /// The type of each underlying LineString, which implements [LineStringTrait] - type LineString<'a>: 'a + LineStringTrait + type LineStringType<'a>: 'a + LineStringTrait where Self: 'a; /// The type of each underlying Polygon, which implements [PolygonTrait] - type Polygon<'a>: 'a + PolygonTrait + type PolygonType<'a>: 'a + PolygonTrait where Self: 'a; /// The type of each underlying MultiPoint, which implements [MultiPointTrait] - type MultiPoint<'a>: 'a + MultiPointTrait + type MultiPointType<'a>: 'a + MultiPointTrait where Self: 'a; /// The type of each underlying MultiLineString, which implements [MultiLineStringTrait] - type MultiLineString<'a>: 'a + MultiLineStringTrait + type MultiLineStringType<'a>: 'a + MultiLineStringTrait where Self: 'a; /// The type of each underlying MultiPolygon, which implements [MultiPolygonTrait] - type MultiPolygon<'a>: 'a + MultiPolygonTrait + type MultiPolygonType<'a>: 'a + MultiPolygonTrait where Self: 'a; /// The type of each underlying GeometryCollection, which implements [GeometryCollectionTrait] - type GeometryCollection<'a>: 'a + GeometryCollectionTrait + type GeometryCollectionType<'a>: 'a + GeometryCollectionTrait where Self: 'a; /// The type of each underlying Rect, which implements [RectTrait] - type Rect<'a>: 'a + RectTrait + type RectType<'a>: 'a + RectTrait where Self: 'a; @@ -63,14 +63,14 @@ pub trait GeometryTrait { &self, ) -> GeometryType< '_, - Self::Point<'_>, - Self::LineString<'_>, - Self::Polygon<'_>, - Self::MultiPoint<'_>, - Self::MultiLineString<'_>, - Self::MultiPolygon<'_>, - Self::GeometryCollection<'_>, - Self::Rect<'_>, + Self::PointType<'_>, + Self::LineStringType<'_>, + Self::PolygonType<'_>, + Self::MultiPointType<'_>, + Self::MultiLineStringType<'_>, + Self::MultiPolygonType<'_>, + Self::GeometryCollectionType<'_>, + Self::RectType<'_>, >; } @@ -108,14 +108,14 @@ where impl<'a, T: CoordNum + 'a> GeometryTrait for Geometry { type T = T; - type Point<'b> = Point where Self: 'b; - type LineString<'b> = LineString where Self: 'b; - type Polygon<'b> = Polygon where Self: 'b; - type MultiPoint<'b> = MultiPoint where Self: 'b; - type MultiLineString<'b> = MultiLineString where Self: 'b; - type MultiPolygon<'b> = MultiPolygon where Self: 'b; - type GeometryCollection<'b> = GeometryCollection where Self: 'b; - type Rect<'b> = Rect where Self: 'b; + type PointType<'b> = Point where Self: 'b; + type LineStringType<'b> = LineString where Self: 'b; + type PolygonType<'b> = Polygon where Self: 'b; + type MultiPointType<'b> = MultiPoint where Self: 'b; + type MultiLineStringType<'b> = MultiLineString where Self: 'b; + type MultiPolygonType<'b> = MultiPolygon where Self: 'b; + type GeometryCollectionType<'b> = GeometryCollection where Self: 'b; + type RectType<'b> = Rect where Self: 'b; fn dim(&self) -> Dimension { Dimension::XY @@ -150,14 +150,14 @@ impl<'a, T: CoordNum + 'a> GeometryTrait for Geometry { impl<'a, T: CoordNum + 'a> GeometryTrait for &'a Geometry { type T = T; - type Point<'b> = Point where Self: 'b; - type LineString<'b> = LineString where Self: 'b; - type Polygon<'b> = Polygon where Self: 'b; - type MultiPoint<'b> = MultiPoint where Self: 'b; - type MultiLineString<'b> = MultiLineString where Self: 'b; - type MultiPolygon<'b> = MultiPolygon where Self: 'b; - type GeometryCollection<'b> = GeometryCollection where Self: 'b; - type Rect<'b> = Rect where Self: 'b; + type PointType<'b> = Point where Self: 'b; + type LineStringType<'b> = LineString where Self: 'b; + type PolygonType<'b> = Polygon where Self: 'b; + type MultiPointType<'b> = MultiPoint where Self: 'b; + type MultiLineStringType<'b> = MultiLineString where Self: 'b; + type MultiPolygonType<'b> = MultiPolygon where Self: 'b; + type GeometryCollectionType<'b> = GeometryCollection where Self: 'b; + type RectType<'b> = Rect where Self: 'b; fn dim(&self) -> Dimension { Dimension::XY @@ -196,14 +196,14 @@ macro_rules! impl_specialization { ($geometry_type:ident) => { impl GeometryTrait for $geometry_type { type T = T; - type Point<'b> = Point where Self: 'b; - type LineString<'b> = LineString where Self: 'b; - type Polygon<'b> = Polygon where Self: 'b; - type MultiPoint<'b> = MultiPoint where Self: 'b; - type MultiLineString<'b> = MultiLineString where Self: 'b; - type MultiPolygon<'b> = MultiPolygon where Self: 'b; - type GeometryCollection<'b> = GeometryCollection where Self: 'b; - type Rect<'b> = Rect where Self: 'b; + type PointType<'b> = Point where Self: 'b; + type LineStringType<'b> = LineString where Self: 'b; + type PolygonType<'b> = Polygon where Self: 'b; + type MultiPointType<'b> = MultiPoint where Self: 'b; + type MultiLineStringType<'b> = MultiLineString where Self: 'b; + type MultiPolygonType<'b> = MultiPolygon where Self: 'b; + type GeometryCollectionType<'b> = GeometryCollection where Self: 'b; + type RectType<'b> = Rect where Self: 'b; fn dim(&self) -> Dimension { Dimension::XY @@ -228,14 +228,14 @@ macro_rules! impl_specialization { impl<'a, T: CoordNum + 'a> GeometryTrait for &'a $geometry_type { type T = T; - type Point<'b> = Point where Self: 'b; - type LineString<'b> = LineString where Self: 'b; - type Polygon<'b> = Polygon where Self: 'b; - type MultiPoint<'b> = MultiPoint where Self: 'b; - type MultiLineString<'b> = MultiLineString where Self: 'b; - type MultiPolygon<'b> = MultiPolygon where Self: 'b; - type GeometryCollection<'b> = GeometryCollection where Self: 'b; - type Rect<'b> = Rect where Self: 'b; + type PointType<'b> = Point where Self: 'b; + type LineStringType<'b> = LineString where Self: 'b; + type PolygonType<'b> = Polygon where Self: 'b; + type MultiPointType<'b> = MultiPoint where Self: 'b; + type MultiLineStringType<'b> = MultiLineString where Self: 'b; + type MultiPolygonType<'b> = MultiPolygon where Self: 'b; + type GeometryCollectionType<'b> = GeometryCollection where Self: 'b; + type RectType<'b> = Rect where Self: 'b; fn dim(&self) -> Dimension { Dimension::XY From 33c1ef99e50ac3b601ba93460d19d345b52d7602 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Sun, 13 Oct 2024 12:22:27 -0400 Subject: [PATCH 14/33] Rename ItemType --- geo-traits/src/geometry_collection.rs | 16 +++++----- geo-traits/src/iterator.rs | 44 +++++++++++++++------------ geo-traits/src/line_string.rs | 16 +++++----- geo-traits/src/multi_line_string.rs | 16 +++++----- geo-traits/src/multi_point.rs | 16 +++++----- geo-traits/src/multi_polygon.rs | 16 +++++----- geo-traits/src/polygon.rs | 22 +++++++------- 7 files changed, 76 insertions(+), 70 deletions(-) diff --git a/geo-traits/src/geometry_collection.rs b/geo-traits/src/geometry_collection.rs index f074297257..ac69302459 100644 --- a/geo-traits/src/geometry_collection.rs +++ b/geo-traits/src/geometry_collection.rs @@ -7,7 +7,7 @@ pub trait GeometryCollectionTrait: Sized { type T: CoordNum; /// The type of each underlying geometry, which implements [GeometryTrait] - type ItemType<'a>: 'a + GeometryTrait + type GeometryType<'a>: 'a + GeometryTrait where Self: 'a; @@ -15,7 +15,7 @@ pub trait GeometryCollectionTrait: Sized { fn dim(&self) -> Dimension; /// An iterator over the geometries in this GeometryCollection - fn geometries(&self) -> impl Iterator> { + fn geometries(&self) -> impl Iterator> { GeometryCollectionIterator::new(self, 0, self.num_geometries()) } @@ -24,7 +24,7 @@ pub trait GeometryCollectionTrait: Sized { /// Access to a specified geometry in this GeometryCollection /// Will return None if the provided index is out of bounds - fn geometry(&self, i: usize) -> Option> { + fn geometry(&self, i: usize) -> Option> { if i >= self.num_geometries() { None } else { @@ -37,12 +37,12 @@ pub trait GeometryCollectionTrait: Sized { /// # Safety /// /// Accessing an index out of bounds is UB. - unsafe fn geometry_unchecked(&self, i: usize) -> Self::ItemType<'_>; + unsafe fn geometry_unchecked(&self, i: usize) -> Self::GeometryType<'_>; } impl GeometryCollectionTrait for GeometryCollection { type T = T; - type ItemType<'a> = &'a Geometry + type GeometryType<'a> = &'a Geometry where Self: 'a; @@ -54,14 +54,14 @@ impl GeometryCollectionTrait for GeometryCollection { self.0.len() } - unsafe fn geometry_unchecked(&self, i: usize) -> Self::ItemType<'_> { + unsafe fn geometry_unchecked(&self, i: usize) -> Self::GeometryType<'_> { self.0.get_unchecked(i) } } impl<'a, T: CoordNum> GeometryCollectionTrait for &'a GeometryCollection { type T = T; - type ItemType<'b> = &'a Geometry where + type GeometryType<'b> = &'a Geometry where Self: 'b; fn dim(&self) -> Dimension { @@ -72,7 +72,7 @@ impl<'a, T: CoordNum> GeometryCollectionTrait for &'a GeometryCollection { self.0.len() } - unsafe fn geometry_unchecked(&self, i: usize) -> Self::ItemType<'_> { + unsafe fn geometry_unchecked(&self, i: usize) -> Self::GeometryType<'_> { self.0.get_unchecked(i) } } diff --git a/geo-traits/src/iterator.rs b/geo-traits/src/iterator.rs index c363132de4..aa5f62ffd7 100644 --- a/geo-traits/src/iterator.rs +++ b/geo-traits/src/iterator.rs @@ -5,13 +5,13 @@ use super::{ use geo_types::CoordNum; macro_rules! impl_iterator { - ($struct_name:ident, $self_trait:ident, $item_trait:ident, $access_method:ident) => { + ($struct_name:ident, $self_trait:ident, $item_trait:ident, $access_method:ident, $item_type:ident) => { /// An iterator over the parts of this geometry. pub struct $struct_name< 'a, T: CoordNum, - ItemType: 'a + $item_trait, - G: $self_trait = ItemType>, + $item_type: 'a + $item_trait, + G: $self_trait = $item_type>, > { geom: &'a G, index: usize, @@ -21,9 +21,9 @@ macro_rules! impl_iterator { impl< 'a, T: CoordNum, - ItemType: 'a + $item_trait, - G: $self_trait = ItemType>, - > $struct_name<'a, T, ItemType, G> + $item_type: 'a + $item_trait, + G: $self_trait = $item_type>, + > $struct_name<'a, T, $item_type, G> { /// Create a new iterator pub fn new(geom: &'a G, index: usize, end: usize) -> Self { @@ -34,11 +34,11 @@ macro_rules! impl_iterator { impl< 'a, T: CoordNum, - ItemType: 'a + $item_trait, - G: $self_trait = ItemType>, - > Iterator for $struct_name<'a, T, ItemType, G> + $item_type: 'a + $item_trait, + G: $self_trait = $item_type>, + > Iterator for $struct_name<'a, T, $item_type, G> { - type Item = ItemType; + type Item = $item_type; #[inline] fn next(&mut self) -> Option { @@ -59,9 +59,9 @@ macro_rules! impl_iterator { impl< 'a, T: CoordNum, - ItemType: 'a + $item_trait, - G: $self_trait = ItemType>, - > DoubleEndedIterator for $struct_name<'a, T, ItemType, G> + $item_type: 'a + $item_trait, + G: $self_trait = $item_type>, + > DoubleEndedIterator for $struct_name<'a, T, $item_type, G> { #[inline] fn next_back(&mut self) -> Option { @@ -80,35 +80,41 @@ impl_iterator!( LineStringIterator, LineStringTrait, PointTrait, - point_unchecked + point_unchecked, + PointType ); impl_iterator!( PolygonInteriorIterator, PolygonTrait, LineStringTrait, - interior_unchecked + interior_unchecked, + RingType ); impl_iterator!( MultiPointIterator, MultiPointTrait, PointTrait, - point_unchecked + point_unchecked, + PointType ); impl_iterator!( MultiLineStringIterator, MultiLineStringTrait, LineStringTrait, - line_string_unchecked + line_string_unchecked, + LineStringType ); impl_iterator!( MultiPolygonIterator, MultiPolygonTrait, PolygonTrait, - polygon_unchecked + polygon_unchecked, + PolygonType ); impl_iterator!( GeometryCollectionIterator, GeometryCollectionTrait, GeometryTrait, - geometry_unchecked + geometry_unchecked, + GeometryType ); diff --git a/geo-traits/src/line_string.rs b/geo-traits/src/line_string.rs index 0383da30e3..40eb55963e 100644 --- a/geo-traits/src/line_string.rs +++ b/geo-traits/src/line_string.rs @@ -7,7 +7,7 @@ pub trait LineStringTrait: Sized { type T: CoordNum; /// The type of each underlying coordinate, which implements [PointTrait] - type ItemType<'a>: 'a + PointTrait + type PointType<'a>: 'a + PointTrait where Self: 'a; @@ -15,7 +15,7 @@ pub trait LineStringTrait: Sized { fn dim(&self) -> Dimension; /// An iterator over the points in this LineString - fn points(&self) -> impl Iterator> { + fn points(&self) -> impl Iterator> { LineStringIterator::new(self, 0, self.num_points()) } @@ -25,7 +25,7 @@ pub trait LineStringTrait: Sized { /// Access to a specified point in this LineString /// Will return None if the provided index is out of bounds #[inline] - fn point(&self, i: usize) -> Option> { + fn point(&self, i: usize) -> Option> { if i >= self.num_points() { None } else { @@ -38,12 +38,12 @@ pub trait LineStringTrait: Sized { /// # Safety /// /// Accessing an index out of bounds is UB. - unsafe fn point_unchecked(&self, i: usize) -> Self::ItemType<'_>; + unsafe fn point_unchecked(&self, i: usize) -> Self::PointType<'_>; } impl LineStringTrait for LineString { type T = T; - type ItemType<'a> = &'a Coord where Self: 'a; + type PointType<'a> = &'a Coord where Self: 'a; fn dim(&self) -> Dimension { Dimension::XY @@ -53,14 +53,14 @@ impl LineStringTrait for LineString { self.0.len() } - unsafe fn point_unchecked(&self, i: usize) -> Self::ItemType<'_> { + unsafe fn point_unchecked(&self, i: usize) -> Self::PointType<'_> { self.0.get_unchecked(i) } } impl<'a, T: CoordNum> LineStringTrait for &'a LineString { type T = T; - type ItemType<'b> = &'a Coord where Self: 'b; + type PointType<'b> = &'a Coord where Self: 'b; fn dim(&self) -> Dimension { Dimension::XY @@ -70,7 +70,7 @@ impl<'a, T: CoordNum> LineStringTrait for &'a LineString { self.0.len() } - unsafe fn point_unchecked(&self, i: usize) -> Self::ItemType<'_> { + unsafe fn point_unchecked(&self, i: usize) -> Self::PointType<'_> { self.0.get_unchecked(i) } } diff --git a/geo-traits/src/multi_line_string.rs b/geo-traits/src/multi_line_string.rs index d3ebaac55c..bf5a92dd7b 100644 --- a/geo-traits/src/multi_line_string.rs +++ b/geo-traits/src/multi_line_string.rs @@ -7,7 +7,7 @@ pub trait MultiLineStringTrait: Sized { type T: CoordNum; /// The type of each underlying LineString, which implements [LineStringTrait] - type ItemType<'a>: 'a + LineStringTrait + type LineStringType<'a>: 'a + LineStringTrait where Self: 'a; @@ -15,7 +15,7 @@ pub trait MultiLineStringTrait: Sized { fn dim(&self) -> Dimension; /// An iterator over the LineStrings in this MultiLineString - fn line_strings(&self) -> impl Iterator> { + fn line_strings(&self) -> impl Iterator> { MultiLineStringIterator::new(self, 0, self.num_line_strings()) } @@ -24,7 +24,7 @@ pub trait MultiLineStringTrait: Sized { /// Access to a specified line_string in this MultiLineString /// Will return None if the provided index is out of bounds - fn line_string(&self, i: usize) -> Option> { + fn line_string(&self, i: usize) -> Option> { if i >= self.num_line_strings() { None } else { @@ -37,12 +37,12 @@ pub trait MultiLineStringTrait: Sized { /// # Safety /// /// Accessing an index out of bounds is UB. - unsafe fn line_string_unchecked(&self, i: usize) -> Self::ItemType<'_>; + unsafe fn line_string_unchecked(&self, i: usize) -> Self::LineStringType<'_>; } impl MultiLineStringTrait for MultiLineString { type T = T; - type ItemType<'a> = &'a LineString where Self: 'a; + type LineStringType<'a> = &'a LineString where Self: 'a; fn dim(&self) -> Dimension { Dimension::XY @@ -52,14 +52,14 @@ impl MultiLineStringTrait for MultiLineString { self.0.len() } - unsafe fn line_string_unchecked(&self, i: usize) -> Self::ItemType<'_> { + unsafe fn line_string_unchecked(&self, i: usize) -> Self::LineStringType<'_> { self.0.get_unchecked(i) } } impl<'a, T: CoordNum> MultiLineStringTrait for &'a MultiLineString { type T = T; - type ItemType<'b> = &'a LineString where Self: 'b; + type LineStringType<'b> = &'a LineString where Self: 'b; fn dim(&self) -> Dimension { Dimension::XY @@ -69,7 +69,7 @@ impl<'a, T: CoordNum> MultiLineStringTrait for &'a MultiLineString { self.0.len() } - unsafe fn line_string_unchecked(&self, i: usize) -> Self::ItemType<'_> { + unsafe fn line_string_unchecked(&self, i: usize) -> Self::LineStringType<'_> { self.0.get_unchecked(i) } } diff --git a/geo-traits/src/multi_point.rs b/geo-traits/src/multi_point.rs index 2fff588c3b..95c9af9ae9 100644 --- a/geo-traits/src/multi_point.rs +++ b/geo-traits/src/multi_point.rs @@ -7,7 +7,7 @@ pub trait MultiPointTrait: Sized { type T: CoordNum; /// The type of each underlying Point, which implements [PointTrait] - type ItemType<'a>: 'a + PointTrait + type PointType<'a>: 'a + PointTrait where Self: 'a; @@ -15,7 +15,7 @@ pub trait MultiPointTrait: Sized { fn dim(&self) -> Dimension; /// An iterator over the points in this MultiPoint - fn points(&self) -> impl Iterator> { + fn points(&self) -> impl Iterator> { MultiPointIterator::new(self, 0, self.num_points()) } @@ -24,7 +24,7 @@ pub trait MultiPointTrait: Sized { /// Access to a specified point in this MultiPoint /// Will return None if the provided index is out of bounds - fn point(&self, i: usize) -> Option> { + fn point(&self, i: usize) -> Option> { if i >= self.num_points() { None } else { @@ -37,12 +37,12 @@ pub trait MultiPointTrait: Sized { /// # Safety /// /// Accessing an index out of bounds is UB. - unsafe fn point_unchecked(&self, i: usize) -> Self::ItemType<'_>; + unsafe fn point_unchecked(&self, i: usize) -> Self::PointType<'_>; } impl MultiPointTrait for MultiPoint { type T = T; - type ItemType<'a> = &'a Point where Self: 'a; + type PointType<'a> = &'a Point where Self: 'a; fn dim(&self) -> Dimension { Dimension::XY @@ -52,14 +52,14 @@ impl MultiPointTrait for MultiPoint { self.0.len() } - unsafe fn point_unchecked(&self, i: usize) -> Self::ItemType<'_> { + unsafe fn point_unchecked(&self, i: usize) -> Self::PointType<'_> { self.0.get_unchecked(i) } } impl<'a, T: CoordNum> MultiPointTrait for &'a MultiPoint { type T = T; - type ItemType<'b> = &'a Point where Self: 'b; + type PointType<'b> = &'a Point where Self: 'b; fn dim(&self) -> Dimension { Dimension::XY @@ -69,7 +69,7 @@ impl<'a, T: CoordNum> MultiPointTrait for &'a MultiPoint { self.0.len() } - unsafe fn point_unchecked(&self, i: usize) -> Self::ItemType<'_> { + unsafe fn point_unchecked(&self, i: usize) -> Self::PointType<'_> { self.0.get_unchecked(i) } } diff --git a/geo-traits/src/multi_polygon.rs b/geo-traits/src/multi_polygon.rs index a850ad9c83..055484eb00 100644 --- a/geo-traits/src/multi_polygon.rs +++ b/geo-traits/src/multi_polygon.rs @@ -7,7 +7,7 @@ pub trait MultiPolygonTrait: Sized { type T: CoordNum; /// The type of each underlying Polygon, which implements [PolygonTrait] - type ItemType<'a>: 'a + PolygonTrait + type PolygonType<'a>: 'a + PolygonTrait where Self: 'a; @@ -15,7 +15,7 @@ pub trait MultiPolygonTrait: Sized { fn dim(&self) -> Dimension; /// An iterator over the Polygons in this MultiPolygon - fn polygons(&self) -> impl Iterator> { + fn polygons(&self) -> impl Iterator> { MultiPolygonIterator::new(self, 0, self.num_polygons()) } @@ -24,7 +24,7 @@ pub trait MultiPolygonTrait: Sized { /// Access to a specified polygon in this MultiPolygon /// Will return None if the provided index is out of bounds - fn polygon(&self, i: usize) -> Option> { + fn polygon(&self, i: usize) -> Option> { if i >= self.num_polygons() { None } else { @@ -37,12 +37,12 @@ pub trait MultiPolygonTrait: Sized { /// # Safety /// /// Accessing an index out of bounds is UB. - unsafe fn polygon_unchecked(&self, i: usize) -> Self::ItemType<'_>; + unsafe fn polygon_unchecked(&self, i: usize) -> Self::PolygonType<'_>; } impl MultiPolygonTrait for MultiPolygon { type T = T; - type ItemType<'a> = &'a Polygon where Self: 'a; + type PolygonType<'a> = &'a Polygon where Self: 'a; fn dim(&self) -> Dimension { Dimension::XY @@ -52,14 +52,14 @@ impl MultiPolygonTrait for MultiPolygon { self.0.len() } - unsafe fn polygon_unchecked(&self, i: usize) -> Self::ItemType<'_> { + unsafe fn polygon_unchecked(&self, i: usize) -> Self::PolygonType<'_> { self.0.get_unchecked(i) } } impl<'a, T: CoordNum> MultiPolygonTrait for &'a MultiPolygon { type T = T; - type ItemType<'b> = &'a Polygon where Self: 'b; + type PolygonType<'b> = &'a Polygon where Self: 'b; fn dim(&self) -> Dimension { Dimension::XY @@ -69,7 +69,7 @@ impl<'a, T: CoordNum> MultiPolygonTrait for &'a MultiPolygon { self.0.len() } - unsafe fn polygon_unchecked(&self, i: usize) -> Self::ItemType<'_> { + unsafe fn polygon_unchecked(&self, i: usize) -> Self::PolygonType<'_> { self.0.get_unchecked(i) } } diff --git a/geo-traits/src/polygon.rs b/geo-traits/src/polygon.rs index 0973d5762f..21c8456f52 100644 --- a/geo-traits/src/polygon.rs +++ b/geo-traits/src/polygon.rs @@ -7,7 +7,7 @@ pub trait PolygonTrait: Sized { type T: CoordNum; /// The type of each underlying ring, which implements [LineStringTrait] - type ItemType<'a>: 'a + LineStringTrait + type RingType<'a>: 'a + LineStringTrait where Self: 'a; @@ -15,10 +15,10 @@ pub trait PolygonTrait: Sized { fn dim(&self) -> Dimension; /// The exterior ring of the polygon - fn exterior(&self) -> Option>; + fn exterior(&self) -> Option>; /// An iterator of the interior rings of this Polygon - fn interiors(&self) -> impl Iterator> { + fn interiors(&self) -> impl Iterator> { PolygonInteriorIterator::new(self, 0, self.num_interiors()) } @@ -27,7 +27,7 @@ pub trait PolygonTrait: Sized { /// Access to a specified interior ring in this Polygon /// Will return None if the provided index is out of bounds - fn interior(&self, i: usize) -> Option> { + fn interior(&self, i: usize) -> Option> { if i >= self.num_interiors() { None } else { @@ -40,18 +40,18 @@ pub trait PolygonTrait: Sized { /// # Safety /// /// Accessing an index out of bounds is UB. - unsafe fn interior_unchecked(&self, i: usize) -> Self::ItemType<'_>; + unsafe fn interior_unchecked(&self, i: usize) -> Self::RingType<'_>; } impl PolygonTrait for Polygon { type T = T; - type ItemType<'a> = &'a LineString where Self: 'a; + type RingType<'a> = &'a LineString where Self: 'a; fn dim(&self) -> Dimension { Dimension::XY } - fn exterior(&self) -> Option> { + fn exterior(&self) -> Option> { // geo-types doesn't really have a way to describe an empty polygon Some(Polygon::exterior(self)) } @@ -60,21 +60,21 @@ impl PolygonTrait for Polygon { Polygon::interiors(self).len() } - unsafe fn interior_unchecked(&self, i: usize) -> Self::ItemType<'_> { + unsafe fn interior_unchecked(&self, i: usize) -> Self::RingType<'_> { unsafe { Polygon::interiors(self).get_unchecked(i) } } } impl<'a, T: CoordNum> PolygonTrait for &'a Polygon { type T = T; - type ItemType<'b> = &'a LineString where + type RingType<'b> = &'a LineString where Self: 'b; fn dim(&self) -> Dimension { Dimension::XY } - fn exterior(&self) -> Option> { + fn exterior(&self) -> Option> { // geo-types doesn't really have a way to describe an empty polygon Some(Polygon::exterior(self)) } @@ -83,7 +83,7 @@ impl<'a, T: CoordNum> PolygonTrait for &'a Polygon { Polygon::interiors(self).len() } - unsafe fn interior_unchecked(&self, i: usize) -> Self::ItemType<'_> { + unsafe fn interior_unchecked(&self, i: usize) -> Self::RingType<'_> { unsafe { Polygon::interiors(self).get_unchecked(i) } } } From 6363ad8671739ec9d3a4c476805f6398bda2c49c Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Mon, 14 Oct 2024 14:50:02 -0400 Subject: [PATCH 15/33] Unimplemented versions --- geo-traits/src/lib.rs | 14 ++++----- geo-traits/src/line_string.rs | 27 ++++++++++++++++- geo-traits/src/multi_line_string.rs | 26 +++++++++++++++++ geo-traits/src/multi_point.rs | 38 ++++++++++++++---------- geo-traits/src/multi_polygon.rs | 26 +++++++++++++++++ geo-traits/src/point.rs | 28 ++++++++++++++++-- geo-traits/src/polygon.rs | 30 +++++++++++++++++++ geo-traits/src/rect.rs | 45 ++++++++++++++++++++++------- 8 files changed, 199 insertions(+), 35 deletions(-) diff --git a/geo-traits/src/lib.rs b/geo-traits/src/lib.rs index b5ea8c6cd2..7c497e7bd1 100644 --- a/geo-traits/src/lib.rs +++ b/geo-traits/src/lib.rs @@ -22,13 +22,13 @@ pub use iterator::{ GeometryCollectionIterator, LineStringIterator, MultiLineStringIterator, MultiPointIterator, MultiPolygonIterator, PolygonInteriorIterator, }; -pub use line_string::LineStringTrait; -pub use multi_line_string::MultiLineStringTrait; -pub use multi_point::MultiPointTrait; -pub use multi_polygon::MultiPolygonTrait; -pub use point::PointTrait; -pub use polygon::PolygonTrait; -pub use rect::RectTrait; +pub use line_string::{LineStringTrait, UnimplementedLineString}; +pub use multi_line_string::{MultiLineStringTrait, UnimplementedMultiLineString}; +pub use multi_point::{MultiPointTrait, UnimplementedMultiPoint}; +pub use multi_polygon::{MultiPolygonTrait, UnimplementedMultiPolygon}; +pub use point::{PointTrait, UnimplementedPoint}; +pub use polygon::{PolygonTrait, UnimplementedPolygon}; +pub use rect::{RectTrait, UnimplementedRect}; mod dimension; mod geometry; diff --git a/geo-traits/src/line_string.rs b/geo-traits/src/line_string.rs index 40eb55963e..4e6db6d8a3 100644 --- a/geo-traits/src/line_string.rs +++ b/geo-traits/src/line_string.rs @@ -1,4 +1,6 @@ -use crate::{Dimension, LineStringIterator, PointTrait}; +use std::marker::PhantomData; + +use crate::{Dimension, LineStringIterator, PointTrait, UnimplementedPoint}; use geo_types::{Coord, CoordNum, LineString}; /// A trait for accessing data from a generic LineString. @@ -74,3 +76,26 @@ impl<'a, T: CoordNum> LineStringTrait for &'a LineString { self.0.get_unchecked(i) } } + +/// An empty struct that implements [LineStringTrait]. +/// +/// This can be used as the `LineStringType` of the `GeometryTrait` by implementations that don't +/// have a LineString concept +pub struct UnimplementedLineString(PhantomData); + +impl LineStringTrait for UnimplementedLineString { + type T = T; + type PointType<'a> = UnimplementedPoint where Self: 'a; + + fn dim(&self) -> Dimension { + unimplemented!() + } + + fn num_points(&self) -> usize { + unimplemented!() + } + + unsafe fn point_unchecked(&self, _i: usize) -> Self::PointType<'_> { + unimplemented!() + } +} diff --git a/geo-traits/src/multi_line_string.rs b/geo-traits/src/multi_line_string.rs index bf5a92dd7b..e1ba9526da 100644 --- a/geo-traits/src/multi_line_string.rs +++ b/geo-traits/src/multi_line_string.rs @@ -1,3 +1,6 @@ +use std::marker::PhantomData; + +use crate::line_string::UnimplementedLineString; use crate::{Dimension, LineStringTrait, MultiLineStringIterator}; use geo_types::{CoordNum, LineString, MultiLineString}; @@ -73,3 +76,26 @@ impl<'a, T: CoordNum> MultiLineStringTrait for &'a MultiLineString { self.0.get_unchecked(i) } } + +/// An empty struct that implements [MultiLineStringTrait]. +/// +/// This can be used as the `MultiLineStringType` of the `GeometryTrait` by implementations that +/// don't have a MultiLineString concept +pub struct UnimplementedMultiLineString(PhantomData); + +impl MultiLineStringTrait for UnimplementedMultiLineString { + type T = T; + type LineStringType<'a> = UnimplementedLineString where Self: 'a; + + fn dim(&self) -> Dimension { + unimplemented!() + } + + fn num_line_strings(&self) -> usize { + unimplemented!() + } + + unsafe fn line_string_unchecked(&self, _i: usize) -> Self::LineStringType<'_> { + unimplemented!() + } +} diff --git a/geo-traits/src/multi_point.rs b/geo-traits/src/multi_point.rs index 95c9af9ae9..0ba2f7fbbc 100644 --- a/geo-traits/src/multi_point.rs +++ b/geo-traits/src/multi_point.rs @@ -1,4 +1,6 @@ -use crate::{Dimension, MultiPointIterator, PointTrait}; +use std::marker::PhantomData; + +use crate::{Dimension, MultiPointIterator, PointTrait, UnimplementedPoint}; use geo_types::{CoordNum, MultiPoint, Point}; /// A trait for accessing data from a generic MultiPoint. @@ -74,19 +76,25 @@ impl<'a, T: CoordNum> MultiPointTrait for &'a MultiPoint { } } -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn tmp() { - let mp = MultiPoint::new(vec![ - Point::new(0.0, 1.0), - Point::new(2.0, 3.0), - Point::new(4.0, 5.0), - ]); - MultiPointTrait::points(&mp).for_each(|p| { - dbg!(p); - }); +/// An empty struct that implements [MultiPointTrait]. +/// +/// This can be used as the `MultiPointType` of the `GeometryTrait` by implementations that don't +/// have a MultiPoint concept +pub struct UnimplementedMultiPoint(PhantomData); + +impl MultiPointTrait for UnimplementedMultiPoint { + type T = T; + type PointType<'a> = UnimplementedPoint where Self: 'a; + + fn dim(&self) -> Dimension { + unimplemented!() + } + + fn num_points(&self) -> usize { + unimplemented!() + } + + unsafe fn point_unchecked(&self, _i: usize) -> Self::PointType<'_> { + unimplemented!() } } diff --git a/geo-traits/src/multi_polygon.rs b/geo-traits/src/multi_polygon.rs index 055484eb00..94b69cb09b 100644 --- a/geo-traits/src/multi_polygon.rs +++ b/geo-traits/src/multi_polygon.rs @@ -1,3 +1,6 @@ +use std::marker::PhantomData; + +use crate::polygon::UnimplementedPolygon; use crate::{Dimension, MultiPolygonIterator, PolygonTrait}; use geo_types::{CoordNum, MultiPolygon, Polygon}; @@ -73,3 +76,26 @@ impl<'a, T: CoordNum> MultiPolygonTrait for &'a MultiPolygon { self.0.get_unchecked(i) } } + +/// An empty struct that implements [MultiPolygonTrait]. +/// +/// This can be used as the `MultiPolygonType` of the `GeometryTrait` by implementations that don't +/// have a MultiPolygon concept +pub struct UnimplementedMultiPolygon(PhantomData); + +impl MultiPolygonTrait for UnimplementedMultiPolygon { + type T = T; + type PolygonType<'a> = UnimplementedPolygon where Self: 'a; + + fn dim(&self) -> Dimension { + unimplemented!() + } + + fn num_polygons(&self) -> usize { + unimplemented!() + } + + unsafe fn polygon_unchecked(&self, _i: usize) -> Self::PolygonType<'_> { + unimplemented!() + } +} diff --git a/geo-traits/src/point.rs b/geo-traits/src/point.rs index 599b3d2ba3..e208a7fb08 100644 --- a/geo-traits/src/point.rs +++ b/geo-traits/src/point.rs @@ -1,3 +1,5 @@ +use std::marker::PhantomData; + use geo_types::{Coord, CoordNum, Point}; use crate::Dimension; @@ -27,10 +29,14 @@ pub trait PointTrait { } /// x component of this point. - fn x(&self) -> Self::T; + fn x(&self) -> Self::T { + self.nth(0).unwrap() + } /// y component of this point. - fn y(&self) -> Self::T; + fn y(&self) -> Self::T { + self.nth(1).unwrap() + } /// Returns a tuple that contains the x/horizontal & y/vertical component of the point. fn x_y(&self) -> (Self::T, Self::T) { @@ -157,3 +163,21 @@ impl PointTrait for (T, T) { self.1 } } + +/// An empty struct that implements [PointTrait]. +/// +/// This can be used as the `PointType` of the `GeometryTrait` by implementations that don't have a +/// Point concept +pub struct UnimplementedPoint(PhantomData); + +impl PointTrait for UnimplementedPoint { + type T = T; + + fn dim(&self) -> Dimension { + unimplemented!() + } + + fn nth_unchecked(&self, _n: usize) -> Self::T { + unimplemented!() + } +} diff --git a/geo-traits/src/polygon.rs b/geo-traits/src/polygon.rs index 21c8456f52..6b1be902be 100644 --- a/geo-traits/src/polygon.rs +++ b/geo-traits/src/polygon.rs @@ -1,3 +1,6 @@ +use std::marker::PhantomData; + +use crate::line_string::UnimplementedLineString; use crate::{Dimension, LineStringTrait, PolygonInteriorIterator}; use geo_types::{CoordNum, LineString, Polygon}; @@ -87,3 +90,30 @@ impl<'a, T: CoordNum> PolygonTrait for &'a Polygon { unsafe { Polygon::interiors(self).get_unchecked(i) } } } + +/// An empty struct that implements [PolygonTrait]. +/// +/// This can be used as the `PolygonType` of the `GeometryTrait` by implementations that don't have a +/// Polygon concept +pub struct UnimplementedPolygon(PhantomData); + +impl PolygonTrait for UnimplementedPolygon { + type T = T; + type RingType<'a> = UnimplementedLineString where Self: 'a; + + fn dim(&self) -> Dimension { + unimplemented!() + } + + fn exterior(&self) -> Option> { + unimplemented!() + } + + fn num_interiors(&self) -> usize { + unimplemented!() + } + + unsafe fn interior_unchecked(&self, _i: usize) -> Self::RingType<'_> { + unimplemented!() + } +} diff --git a/geo-traits/src/rect.rs b/geo-traits/src/rect.rs index a39b9b47fe..ed5c1b479c 100644 --- a/geo-traits/src/rect.rs +++ b/geo-traits/src/rect.rs @@ -1,6 +1,8 @@ +use std::marker::PhantomData; + use geo_types::{Coord, CoordNum, Rect}; -use crate::{Dimension, PointTrait}; +use crate::{Dimension, PointTrait, UnimplementedPoint}; /// A trait for accessing data from a generic Rect. pub trait RectTrait { @@ -8,7 +10,7 @@ pub trait RectTrait { type T: CoordNum; /// The type of each underlying coordinate, which implements [PointTrait] - type ItemType<'a>: 'a + PointTrait + type PointType<'a>: 'a + PointTrait where Self: 'a; @@ -16,42 +18,65 @@ pub trait RectTrait { fn dim(&self) -> Dimension; /// The minimum coordinate of this Rect - fn min(&self) -> Self::ItemType<'_>; + fn min(&self) -> Self::PointType<'_>; /// The maximum coordinate of this Rect - fn max(&self) -> Self::ItemType<'_>; + fn max(&self) -> Self::PointType<'_>; } impl<'a, T: CoordNum + 'a> RectTrait for Rect { type T = T; - type ItemType<'b> = Coord where Self: 'b; + type PointType<'b> = Coord where Self: 'b; fn dim(&self) -> Dimension { Dimension::XY } - fn min(&self) -> Self::ItemType<'_> { + fn min(&self) -> Self::PointType<'_> { Rect::min(*self) } - fn max(&self) -> Self::ItemType<'_> { + fn max(&self) -> Self::PointType<'_> { Rect::max(*self) } } impl<'a, T: CoordNum + 'a> RectTrait for &'a Rect { type T = T; - type ItemType<'b> = Coord where Self: 'b; + type PointType<'b> = Coord where Self: 'b; fn dim(&self) -> Dimension { Dimension::XY } - fn min(&self) -> Self::ItemType<'_> { + fn min(&self) -> Self::PointType<'_> { Rect::min(**self) } - fn max(&self) -> Self::ItemType<'_> { + fn max(&self) -> Self::PointType<'_> { Rect::max(**self) } } + +/// An empty struct that implements [RectTrait]. +/// +/// This can be used as the `RectType` of the `GeometryTrait` by implementations that don't +/// have a Rect concept +pub struct UnimplementedRect(PhantomData); + +impl RectTrait for UnimplementedRect { + type T = T; + type PointType<'a> = UnimplementedPoint where Self: 'a; + + fn dim(&self) -> Dimension { + unimplemented!() + } + + fn min(&self) -> Self::PointType<'_> { + unimplemented!() + } + + fn max(&self) -> Self::PointType<'_> { + unimplemented!() + } +} From 9421e0530230246f231503495ca26a8d02d01218 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Mon, 14 Oct 2024 15:14:02 -0400 Subject: [PATCH 16/33] Add LineTrait and TriangleTrait and improve trait docs --- geo-traits/src/geometry.rs | 56 ++++++++++--- geo-traits/src/geometry_collection.rs | 2 + geo-traits/src/lib.rs | 4 + geo-traits/src/line.rs | 90 +++++++++++++++++++++ geo-traits/src/line_string.rs | 5 ++ geo-traits/src/multi_line_string.rs | 4 + geo-traits/src/multi_point.rs | 4 + geo-traits/src/multi_polygon.rs | 2 + geo-traits/src/point.rs | 2 + geo-traits/src/polygon.rs | 6 ++ geo-traits/src/rect.rs | 3 + geo-traits/src/triangle.rs | 111 ++++++++++++++++++++++++++ 12 files changed, 280 insertions(+), 9 deletions(-) create mode 100644 geo-traits/src/line.rs create mode 100644 geo-traits/src/triangle.rs diff --git a/geo-traits/src/geometry.rs b/geo-traits/src/geometry.rs index c38f1b509c..ac69470a06 100644 --- a/geo-traits/src/geometry.rs +++ b/geo-traits/src/geometry.rs @@ -1,11 +1,11 @@ use geo_types::{ - CoordNum, Geometry, GeometryCollection, LineString, MultiLineString, MultiPoint, MultiPolygon, - Point, Polygon, Rect, + CoordNum, Geometry, GeometryCollection, Line, LineString, MultiLineString, MultiPoint, + MultiPolygon, Point, Polygon, Rect, Triangle, }; use crate::{ - Dimension, GeometryCollectionTrait, LineStringTrait, MultiLineStringTrait, MultiPointTrait, - MultiPolygonTrait, PointTrait, PolygonTrait, RectTrait, + Dimension, GeometryCollectionTrait, LineStringTrait, LineTrait, MultiLineStringTrait, + MultiPointTrait, MultiPolygonTrait, PointTrait, PolygonTrait, RectTrait, TriangleTrait, }; /// A trait for accessing data from a generic Geometry. @@ -54,6 +54,16 @@ pub trait GeometryTrait { where Self: 'a; + /// The type of each underlying Triangle, which implements [TriangleTrait] + type TriangleType<'a>: 'a + TriangleTrait + where + Self: 'a; + + /// The type of each underlying Line, which implements [LineTrait] + type LineType<'a>: 'a + LineTrait + where + Self: 'a; + /// The dimension of this geometry fn dim(&self) -> Dimension; @@ -71,27 +81,31 @@ pub trait GeometryTrait { Self::MultiPolygonType<'_>, Self::GeometryCollectionType<'_>, Self::RectType<'_>, + Self::TriangleType<'_>, + Self::LineType<'_>, >; } /// An enumeration of all geometry types that can be contained inside a [GeometryTrait]. This is /// used for extracting concrete geometry types out of a [GeometryTrait]. #[derive(Debug)] -pub enum GeometryType<'a, P, L, Y, MP, ML, MY, GC, R> +pub enum GeometryType<'a, P, LS, Y, MP, ML, MY, GC, R, T, L> where P: PointTrait, - L: LineStringTrait, + LS: LineStringTrait, Y: PolygonTrait, MP: MultiPointTrait, ML: MultiLineStringTrait, MY: MultiPolygonTrait, GC: GeometryCollectionTrait, R: RectTrait, + T: TriangleTrait, + L: LineTrait, { /// A Point, which implements [PointTrait] Point(&'a P), /// A LineString, which implements [LineStringTrait] - LineString(&'a L), + LineString(&'a LS), /// A Polygon, which implements [PolygonTrait] Polygon(&'a Y), /// A MultiPoint, which implements [MultiPointTrait] @@ -104,6 +118,10 @@ where GeometryCollection(&'a GC), /// A Rect, which implements [RectTrait] Rect(&'a R), + /// A Triangle, which implements [TriangleTrait] + Triangle(&'a T), + /// A Line, which implements [LineTrait] + Line(&'a L), } impl<'a, T: CoordNum + 'a> GeometryTrait for Geometry { @@ -116,6 +134,8 @@ impl<'a, T: CoordNum + 'a> GeometryTrait for Geometry { type MultiPolygonType<'b> = MultiPolygon where Self: 'b; type GeometryCollectionType<'b> = GeometryCollection where Self: 'b; type RectType<'b> = Rect where Self: 'b; + type TriangleType<'b> = Triangle where Self: 'b; + type LineType<'b> = Line where Self: 'b; fn dim(&self) -> Dimension { Dimension::XY @@ -133,6 +153,8 @@ impl<'a, T: CoordNum + 'a> GeometryTrait for Geometry { MultiPolygon, GeometryCollection, Rect, + Triangle, + Line, > { match self { Geometry::Point(p) => GeometryType::Point(p), @@ -143,7 +165,8 @@ impl<'a, T: CoordNum + 'a> GeometryTrait for Geometry { Geometry::MultiPolygon(p) => GeometryType::MultiPolygon(p), Geometry::GeometryCollection(p) => GeometryType::GeometryCollection(p), Geometry::Rect(p) => GeometryType::Rect(p), - _ => todo!(), + Geometry::Triangle(p) => GeometryType::Triangle(p), + Geometry::Line(p) => GeometryType::Line(p), } } } @@ -158,6 +181,8 @@ impl<'a, T: CoordNum + 'a> GeometryTrait for &'a Geometry { type MultiPolygonType<'b> = MultiPolygon where Self: 'b; type GeometryCollectionType<'b> = GeometryCollection where Self: 'b; type RectType<'b> = Rect where Self: 'b; + type TriangleType<'b> = Triangle where Self: 'b; + type LineType<'b> = Line where Self: 'b; fn dim(&self) -> Dimension { Dimension::XY @@ -175,6 +200,8 @@ impl<'a, T: CoordNum + 'a> GeometryTrait for &'a Geometry { MultiPolygon, GeometryCollection, Rect, + Triangle, + Line, > { match self { Geometry::Point(p) => GeometryType::Point(p), @@ -185,7 +212,8 @@ impl<'a, T: CoordNum + 'a> GeometryTrait for &'a Geometry { Geometry::MultiPolygon(p) => GeometryType::MultiPolygon(p), Geometry::GeometryCollection(p) => GeometryType::GeometryCollection(p), Geometry::Rect(p) => GeometryType::Rect(p), - _ => todo!(), + Geometry::Triangle(p) => GeometryType::Triangle(p), + Geometry::Line(p) => GeometryType::Line(p), } } } @@ -204,6 +232,8 @@ macro_rules! impl_specialization { type MultiPolygonType<'b> = MultiPolygon where Self: 'b; type GeometryCollectionType<'b> = GeometryCollection where Self: 'b; type RectType<'b> = Rect where Self: 'b; + type TriangleType<'b> = Triangle where Self: 'b; + type LineType<'b> = Line where Self: 'b; fn dim(&self) -> Dimension { Dimension::XY @@ -221,6 +251,8 @@ macro_rules! impl_specialization { MultiPolygon, GeometryCollection, Rect, + Triangle, + Line, > { GeometryType::$geometry_type(self) } @@ -236,6 +268,8 @@ macro_rules! impl_specialization { type MultiPolygonType<'b> = MultiPolygon where Self: 'b; type GeometryCollectionType<'b> = GeometryCollection where Self: 'b; type RectType<'b> = Rect where Self: 'b; + type TriangleType<'b> = Triangle where Self: 'b; + type LineType<'b> = Line where Self: 'b; fn dim(&self) -> Dimension { Dimension::XY @@ -253,6 +287,8 @@ macro_rules! impl_specialization { MultiPolygon, GeometryCollection, Rect, + Triangle, + Line, > { GeometryType::$geometry_type(self) } @@ -268,3 +304,5 @@ impl_specialization!(MultiLineString); impl_specialization!(MultiPolygon); impl_specialization!(GeometryCollection); impl_specialization!(Rect); +impl_specialization!(Triangle); +impl_specialization!(Line); diff --git a/geo-traits/src/geometry_collection.rs b/geo-traits/src/geometry_collection.rs index ac69302459..0ee7586f2a 100644 --- a/geo-traits/src/geometry_collection.rs +++ b/geo-traits/src/geometry_collection.rs @@ -2,6 +2,8 @@ use crate::{Dimension, GeometryCollectionIterator, GeometryTrait}; use geo_types::{CoordNum, Geometry, GeometryCollection}; /// A trait for accessing data from a generic GeometryCollection. +/// +/// A GeometryCollection is a collection of [Geometry][GeometryTrait] types. pub trait GeometryCollectionTrait: Sized { /// The coordinate type of this geometry type T: CoordNum; diff --git a/geo-traits/src/lib.rs b/geo-traits/src/lib.rs index 7c497e7bd1..a4efc27f57 100644 --- a/geo-traits/src/lib.rs +++ b/geo-traits/src/lib.rs @@ -22,6 +22,7 @@ pub use iterator::{ GeometryCollectionIterator, LineStringIterator, MultiLineStringIterator, MultiPointIterator, MultiPolygonIterator, PolygonInteriorIterator, }; +pub use line::{LineTrait, UnimplementedLine}; pub use line_string::{LineStringTrait, UnimplementedLineString}; pub use multi_line_string::{MultiLineStringTrait, UnimplementedMultiLineString}; pub use multi_point::{MultiPointTrait, UnimplementedMultiPoint}; @@ -29,11 +30,13 @@ pub use multi_polygon::{MultiPolygonTrait, UnimplementedMultiPolygon}; pub use point::{PointTrait, UnimplementedPoint}; pub use polygon::{PolygonTrait, UnimplementedPolygon}; pub use rect::{RectTrait, UnimplementedRect}; +pub use triangle::{TriangleTrait, UnimplementedTriangle}; mod dimension; mod geometry; mod geometry_collection; mod iterator; +mod line; mod line_string; mod multi_line_string; mod multi_point; @@ -41,3 +44,4 @@ mod multi_polygon; mod point; mod polygon; mod rect; +mod triangle; diff --git a/geo-traits/src/line.rs b/geo-traits/src/line.rs new file mode 100644 index 0000000000..4ada0313df --- /dev/null +++ b/geo-traits/src/line.rs @@ -0,0 +1,90 @@ +use std::marker::PhantomData; + +use crate::{Dimension, PointTrait, UnimplementedPoint}; +use geo_types::{Coord, CoordNum, Line}; + +/// A trait for accessing data from a generic Line. +/// +/// A Line is a line segment made up of exactly two [points][PointTrait]. +/// +/// Refer to [geo_types::Line] for information about semantics and validity. +pub trait LineTrait: Sized { + /// The coordinate type of this geometry + type T: CoordNum; + + /// The type of each underlying coordinate, which implements [PointTrait] + type PointType<'a>: 'a + PointTrait + where + Self: 'a; + + /// The dimension of this geometry + fn dim(&self) -> Dimension; + + /// Access the start point in this Line + fn start(&self) -> Self::PointType<'_>; + + /// Access the start point in this Line + fn end(&self) -> Self::PointType<'_>; + + /// Access the three underlying points + fn points(&self) -> (Self::PointType<'_>, Self::PointType<'_>) { + (self.start(), self.end()) + } +} + +impl LineTrait for Line { + type T = T; + type PointType<'a> = &'a Coord where Self: 'a; + + fn dim(&self) -> Dimension { + Dimension::XY + } + + fn start(&self) -> Self::PointType<'_> { + &self.start + } + + fn end(&self) -> Self::PointType<'_> { + &self.end + } +} + +impl<'a, T: CoordNum> LineTrait for &'a Line { + type T = T; + type PointType<'b> = &'a Coord where Self: 'b; + + fn dim(&self) -> Dimension { + Dimension::XY + } + + fn start(&self) -> Self::PointType<'_> { + &self.start + } + + fn end(&self) -> Self::PointType<'_> { + &self.end + } +} + +/// An empty struct that implements [LineTrait]. +/// +/// This can be used as the `LineType` of the `GeometryTrait` by implementations that don't +/// have a Line concept +pub struct UnimplementedLine(PhantomData); + +impl LineTrait for UnimplementedLine { + type T = T; + type PointType<'a> = UnimplementedPoint where Self: 'a; + + fn dim(&self) -> Dimension { + unimplemented!() + } + + fn start(&self) -> Self::PointType<'_> { + unimplemented!() + } + + fn end(&self) -> Self::PointType<'_> { + unimplemented!() + } +} diff --git a/geo-traits/src/line_string.rs b/geo-traits/src/line_string.rs index 4e6db6d8a3..fde2b74fae 100644 --- a/geo-traits/src/line_string.rs +++ b/geo-traits/src/line_string.rs @@ -4,6 +4,11 @@ use crate::{Dimension, LineStringIterator, PointTrait, UnimplementedPoint}; use geo_types::{Coord, CoordNum, LineString}; /// A trait for accessing data from a generic LineString. +/// +/// A LineString is an ordered collection of two or more [points][PointTrait], representing a path +/// between locations. +/// +/// Refer to [geo_types::LineString] for information about semantics and validity. pub trait LineStringTrait: Sized { /// The coordinate type of this geometry type T: CoordNum; diff --git a/geo-traits/src/multi_line_string.rs b/geo-traits/src/multi_line_string.rs index e1ba9526da..36968808c6 100644 --- a/geo-traits/src/multi_line_string.rs +++ b/geo-traits/src/multi_line_string.rs @@ -5,6 +5,10 @@ use crate::{Dimension, LineStringTrait, MultiLineStringIterator}; use geo_types::{CoordNum, LineString, MultiLineString}; /// A trait for accessing data from a generic MultiLineString. +/// +/// A MultiLineString is a collection of [`LineString`s][LineStringTrait]. +/// +/// Refer to [geo_types::MultiLineString] for information about semantics and validity. pub trait MultiLineStringTrait: Sized { /// The coordinate type of this geometry type T: CoordNum; diff --git a/geo-traits/src/multi_point.rs b/geo-traits/src/multi_point.rs index 0ba2f7fbbc..554d3e67e2 100644 --- a/geo-traits/src/multi_point.rs +++ b/geo-traits/src/multi_point.rs @@ -4,6 +4,10 @@ use crate::{Dimension, MultiPointIterator, PointTrait, UnimplementedPoint}; use geo_types::{CoordNum, MultiPoint, Point}; /// A trait for accessing data from a generic MultiPoint. +/// +/// A MultiPoint is a collection of [`Point`s][PointTrait]. +/// +/// Refer to [geo_types::MultiPoint] for information about semantics and validity. pub trait MultiPointTrait: Sized { /// The coordinate type of this geometry type T: CoordNum; diff --git a/geo-traits/src/multi_polygon.rs b/geo-traits/src/multi_polygon.rs index 94b69cb09b..a83d79fac5 100644 --- a/geo-traits/src/multi_polygon.rs +++ b/geo-traits/src/multi_polygon.rs @@ -5,6 +5,8 @@ use crate::{Dimension, MultiPolygonIterator, PolygonTrait}; use geo_types::{CoordNum, MultiPolygon, Polygon}; /// A trait for accessing data from a generic MultiPolygon. +/// +/// Refer to [geo_types::MultiPolygon] for information about semantics and validity. pub trait MultiPolygonTrait: Sized { /// The coordinate type of this geometry type T: CoordNum; diff --git a/geo-traits/src/point.rs b/geo-traits/src/point.rs index e208a7fb08..626f402a8e 100644 --- a/geo-traits/src/point.rs +++ b/geo-traits/src/point.rs @@ -5,6 +5,8 @@ use geo_types::{Coord, CoordNum, Point}; use crate::Dimension; /// A trait for accessing data from a generic Point. +/// +/// Refer to [geo_types::Point] for information about semantics and validity. pub trait PointTrait { /// The coordinate type of this geometry type T: CoordNum; diff --git a/geo-traits/src/polygon.rs b/geo-traits/src/polygon.rs index 6b1be902be..82e9e7c9c9 100644 --- a/geo-traits/src/polygon.rs +++ b/geo-traits/src/polygon.rs @@ -5,6 +5,12 @@ use crate::{Dimension, LineStringTrait, PolygonInteriorIterator}; use geo_types::{CoordNum, LineString, Polygon}; /// A trait for accessing data from a generic Polygon. +/// +/// A `Polygon`’s outer boundary (_exterior ring_) is represented by a +/// [`LineString`][LineStringTrait]. It may contain zero or more holes (_interior rings_), also +/// represented by `LineString`s. +/// +/// Refer to [geo_types::Polygon] for information about semantics and validity. pub trait PolygonTrait: Sized { /// The coordinate type of this geometry type T: CoordNum; diff --git a/geo-traits/src/rect.rs b/geo-traits/src/rect.rs index ed5c1b479c..8d37a1d065 100644 --- a/geo-traits/src/rect.rs +++ b/geo-traits/src/rect.rs @@ -5,6 +5,9 @@ use geo_types::{Coord, CoordNum, Rect}; use crate::{Dimension, PointTrait, UnimplementedPoint}; /// A trait for accessing data from a generic Rect. +/// +/// A Rect is an _axis-aligned_ bounded 2D rectangle whose area is +/// defined by minimum and maximum [`Point`s][PointTrait]. pub trait RectTrait { /// The coordinate type of this geometry type T: CoordNum; diff --git a/geo-traits/src/triangle.rs b/geo-traits/src/triangle.rs new file mode 100644 index 0000000000..a59fc3b0f1 --- /dev/null +++ b/geo-traits/src/triangle.rs @@ -0,0 +1,111 @@ +use std::marker::PhantomData; + +use crate::{Dimension, PointTrait, UnimplementedPoint}; +use geo_types::{Coord, CoordNum, Triangle}; + +/// A trait for accessing data from a generic Triangle. +/// +/// A triangle is a bounded area whose three vertices are defined by [points][PointTrait]. +/// +/// Refer to [geo_types::Triangle] for information about semantics and validity. +pub trait TriangleTrait: Sized { + /// The coordinate type of this geometry + type T: CoordNum; + + /// The type of each underlying coordinate, which implements [PointTrait] + type PointType<'a>: 'a + PointTrait + where + Self: 'a; + + /// The dimension of this geometry + fn dim(&self) -> Dimension; + + /// Access the first point in this Triangle + fn first(&self) -> Self::PointType<'_>; + + /// Access the second point in this Triangle + fn second(&self) -> Self::PointType<'_>; + + /// Access the third point in this Triangle + fn third(&self) -> Self::PointType<'_>; + + /// Access the three underlying points + fn points( + &self, + ) -> ( + Self::PointType<'_>, + Self::PointType<'_>, + Self::PointType<'_>, + ) { + (self.first(), self.second(), self.third()) + } +} + +impl TriangleTrait for Triangle { + type T = T; + type PointType<'a> = &'a Coord where Self: 'a; + + fn dim(&self) -> Dimension { + Dimension::XY + } + + fn first(&self) -> Self::PointType<'_> { + &self.0 + } + + fn second(&self) -> Self::PointType<'_> { + &self.0 + } + + fn third(&self) -> Self::PointType<'_> { + &self.0 + } +} + +impl<'a, T: CoordNum> TriangleTrait for &'a Triangle { + type T = T; + type PointType<'b> = &'a Coord where Self: 'b; + + fn dim(&self) -> Dimension { + Dimension::XY + } + + fn first(&self) -> Self::PointType<'_> { + &self.0 + } + + fn second(&self) -> Self::PointType<'_> { + &self.0 + } + + fn third(&self) -> Self::PointType<'_> { + &self.0 + } +} + +/// An empty struct that implements [TriangleTrait]. +/// +/// This can be used as the `TriangleType` of the `GeometryTrait` by implementations that don't +/// have a Triangle concept +pub struct UnimplementedTriangle(PhantomData); + +impl TriangleTrait for UnimplementedTriangle { + type T = T; + type PointType<'a> = UnimplementedPoint where Self: 'a; + + fn dim(&self) -> Dimension { + unimplemented!() + } + + fn first(&self) -> Self::PointType<'_> { + unimplemented!() + } + + fn second(&self) -> Self::PointType<'_> { + unimplemented!() + } + + fn third(&self) -> Self::PointType<'_> { + unimplemented!() + } +} From 955270514d3c978dfea576685160db5f8b0131da Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Mon, 14 Oct 2024 15:15:37 -0400 Subject: [PATCH 17/33] Fix geo-types empty Polygon --- geo-traits/src/polygon.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/geo-traits/src/polygon.rs b/geo-traits/src/polygon.rs index 82e9e7c9c9..84c6f8bfdf 100644 --- a/geo-traits/src/polygon.rs +++ b/geo-traits/src/polygon.rs @@ -61,8 +61,12 @@ impl PolygonTrait for Polygon { } fn exterior(&self) -> Option> { - // geo-types doesn't really have a way to describe an empty polygon - Some(Polygon::exterior(self)) + let ext_ring = Polygon::exterior(self); + if ext_ring.num_points() == 0 { + None + } else { + Some(ext_ring) + } } fn num_interiors(&self) -> usize { @@ -84,8 +88,12 @@ impl<'a, T: CoordNum> PolygonTrait for &'a Polygon { } fn exterior(&self) -> Option> { - // geo-types doesn't really have a way to describe an empty polygon - Some(Polygon::exterior(self)) + let ext_ring = Polygon::exterior(self); + if ext_ring.num_points() == 0 { + None + } else { + Some(ext_ring) + } } fn num_interiors(&self) -> usize { From 7a2effd48f581b52b0ae450bc1be8e85754b468b Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Mon, 14 Oct 2024 17:50:08 -0400 Subject: [PATCH 18/33] Make iterators private --- geo-traits/src/geometry_collection.rs | 3 ++- geo-traits/src/iterator.rs | 2 +- geo-traits/src/lib.rs | 4 ---- geo-traits/src/line_string.rs | 3 ++- geo-traits/src/multi_line_string.rs | 3 ++- geo-traits/src/multi_point.rs | 3 ++- geo-traits/src/multi_polygon.rs | 3 ++- geo-traits/src/polygon.rs | 3 ++- 8 files changed, 13 insertions(+), 11 deletions(-) diff --git a/geo-traits/src/geometry_collection.rs b/geo-traits/src/geometry_collection.rs index 0ee7586f2a..697ad24022 100644 --- a/geo-traits/src/geometry_collection.rs +++ b/geo-traits/src/geometry_collection.rs @@ -1,4 +1,5 @@ -use crate::{Dimension, GeometryCollectionIterator, GeometryTrait}; +use crate::iterator::GeometryCollectionIterator; +use crate::{Dimension, GeometryTrait}; use geo_types::{CoordNum, Geometry, GeometryCollection}; /// A trait for accessing data from a generic GeometryCollection. diff --git a/geo-traits/src/iterator.rs b/geo-traits/src/iterator.rs index aa5f62ffd7..83266478d0 100644 --- a/geo-traits/src/iterator.rs +++ b/geo-traits/src/iterator.rs @@ -7,7 +7,7 @@ use geo_types::CoordNum; macro_rules! impl_iterator { ($struct_name:ident, $self_trait:ident, $item_trait:ident, $access_method:ident, $item_type:ident) => { /// An iterator over the parts of this geometry. - pub struct $struct_name< + pub(crate) struct $struct_name< 'a, T: CoordNum, $item_type: 'a + $item_trait, diff --git a/geo-traits/src/lib.rs b/geo-traits/src/lib.rs index a4efc27f57..3ff3dacd72 100644 --- a/geo-traits/src/lib.rs +++ b/geo-traits/src/lib.rs @@ -18,10 +18,6 @@ pub use dimension::Dimension; pub use geometry::{GeometryTrait, GeometryType}; pub use geometry_collection::GeometryCollectionTrait; -pub use iterator::{ - GeometryCollectionIterator, LineStringIterator, MultiLineStringIterator, MultiPointIterator, - MultiPolygonIterator, PolygonInteriorIterator, -}; pub use line::{LineTrait, UnimplementedLine}; pub use line_string::{LineStringTrait, UnimplementedLineString}; pub use multi_line_string::{MultiLineStringTrait, UnimplementedMultiLineString}; diff --git a/geo-traits/src/line_string.rs b/geo-traits/src/line_string.rs index fde2b74fae..269d68222e 100644 --- a/geo-traits/src/line_string.rs +++ b/geo-traits/src/line_string.rs @@ -1,6 +1,7 @@ use std::marker::PhantomData; -use crate::{Dimension, LineStringIterator, PointTrait, UnimplementedPoint}; +use crate::iterator::LineStringIterator; +use crate::{Dimension, PointTrait, UnimplementedPoint}; use geo_types::{Coord, CoordNum, LineString}; /// A trait for accessing data from a generic LineString. diff --git a/geo-traits/src/multi_line_string.rs b/geo-traits/src/multi_line_string.rs index 36968808c6..916e0ee7ed 100644 --- a/geo-traits/src/multi_line_string.rs +++ b/geo-traits/src/multi_line_string.rs @@ -1,7 +1,8 @@ use std::marker::PhantomData; +use crate::iterator::MultiLineStringIterator; use crate::line_string::UnimplementedLineString; -use crate::{Dimension, LineStringTrait, MultiLineStringIterator}; +use crate::{Dimension, LineStringTrait}; use geo_types::{CoordNum, LineString, MultiLineString}; /// A trait for accessing data from a generic MultiLineString. diff --git a/geo-traits/src/multi_point.rs b/geo-traits/src/multi_point.rs index 554d3e67e2..97b2d7f549 100644 --- a/geo-traits/src/multi_point.rs +++ b/geo-traits/src/multi_point.rs @@ -1,6 +1,7 @@ use std::marker::PhantomData; -use crate::{Dimension, MultiPointIterator, PointTrait, UnimplementedPoint}; +use crate::iterator::MultiPointIterator; +use crate::{Dimension, PointTrait, UnimplementedPoint}; use geo_types::{CoordNum, MultiPoint, Point}; /// A trait for accessing data from a generic MultiPoint. diff --git a/geo-traits/src/multi_polygon.rs b/geo-traits/src/multi_polygon.rs index a83d79fac5..125be4ee70 100644 --- a/geo-traits/src/multi_polygon.rs +++ b/geo-traits/src/multi_polygon.rs @@ -1,7 +1,8 @@ use std::marker::PhantomData; +use crate::iterator::MultiPolygonIterator; use crate::polygon::UnimplementedPolygon; -use crate::{Dimension, MultiPolygonIterator, PolygonTrait}; +use crate::{Dimension, PolygonTrait}; use geo_types::{CoordNum, MultiPolygon, Polygon}; /// A trait for accessing data from a generic MultiPolygon. diff --git a/geo-traits/src/polygon.rs b/geo-traits/src/polygon.rs index 84c6f8bfdf..86b0c14f7c 100644 --- a/geo-traits/src/polygon.rs +++ b/geo-traits/src/polygon.rs @@ -1,7 +1,8 @@ use std::marker::PhantomData; +use crate::iterator::PolygonInteriorIterator; use crate::line_string::UnimplementedLineString; -use crate::{Dimension, LineStringTrait, PolygonInteriorIterator}; +use crate::{Dimension, LineStringTrait}; use geo_types::{CoordNum, LineString, Polygon}; /// A trait for accessing data from a generic Polygon. From 8dcbe50d14daa4b1495b3fb78f4a1329b1a8bc4a Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Mon, 14 Oct 2024 17:58:47 -0400 Subject: [PATCH 19/33] Rename Dimension -> Dimensions --- geo-traits/src/dimension.rs | 4 ++-- geo-traits/src/geometry.rs | 20 +++++++++---------- geo-traits/src/geometry_collection.rs | 12 ++++++------ geo-traits/src/lib.rs | 2 +- geo-traits/src/line.rs | 14 +++++++------- geo-traits/src/line_string.rs | 14 +++++++------- geo-traits/src/multi_line_string.rs | 14 +++++++------- geo-traits/src/multi_point.rs | 14 +++++++------- geo-traits/src/multi_polygon.rs | 14 +++++++------- geo-traits/src/point.rs | 28 +++++++++++++-------------- geo-traits/src/polygon.rs | 14 +++++++------- geo-traits/src/rect.rs | 14 +++++++------- geo-traits/src/triangle.rs | 14 +++++++------- 13 files changed, 89 insertions(+), 89 deletions(-) diff --git a/geo-traits/src/dimension.rs b/geo-traits/src/dimension.rs index 856d7e16db..b1d1c6f241 100644 --- a/geo-traits/src/dimension.rs +++ b/geo-traits/src/dimension.rs @@ -3,7 +3,7 @@ /// #[allow(clippy::upper_case_acronyms)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum Dimension { +pub enum Dimensions { /// A two-dimensional geometry with X and Y values XY, @@ -21,7 +21,7 @@ pub enum Dimension { Unknown(usize), } -impl Dimension { +impl Dimensions { /// The physical number of dimensions in this geometry. pub fn size(&self) -> usize { match self { diff --git a/geo-traits/src/geometry.rs b/geo-traits/src/geometry.rs index ac69470a06..69fe299e6d 100644 --- a/geo-traits/src/geometry.rs +++ b/geo-traits/src/geometry.rs @@ -4,7 +4,7 @@ use geo_types::{ }; use crate::{ - Dimension, GeometryCollectionTrait, LineStringTrait, LineTrait, MultiLineStringTrait, + Dimensions, GeometryCollectionTrait, LineStringTrait, LineTrait, MultiLineStringTrait, MultiPointTrait, MultiPolygonTrait, PointTrait, PolygonTrait, RectTrait, TriangleTrait, }; @@ -65,7 +65,7 @@ pub trait GeometryTrait { Self: 'a; /// The dimension of this geometry - fn dim(&self) -> Dimension; + fn dim(&self) -> Dimensions; /// Cast this geometry to a [`GeometryType`] enum, which allows for downcasting to a specific /// type @@ -137,8 +137,8 @@ impl<'a, T: CoordNum + 'a> GeometryTrait for Geometry { type TriangleType<'b> = Triangle where Self: 'b; type LineType<'b> = Line where Self: 'b; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn as_type( @@ -184,8 +184,8 @@ impl<'a, T: CoordNum + 'a> GeometryTrait for &'a Geometry { type TriangleType<'b> = Triangle where Self: 'b; type LineType<'b> = Line where Self: 'b; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn as_type( @@ -235,8 +235,8 @@ macro_rules! impl_specialization { type TriangleType<'b> = Triangle where Self: 'b; type LineType<'b> = Line where Self: 'b; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn as_type( @@ -271,8 +271,8 @@ macro_rules! impl_specialization { type TriangleType<'b> = Triangle where Self: 'b; type LineType<'b> = Line where Self: 'b; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn as_type( diff --git a/geo-traits/src/geometry_collection.rs b/geo-traits/src/geometry_collection.rs index 697ad24022..ccfd881403 100644 --- a/geo-traits/src/geometry_collection.rs +++ b/geo-traits/src/geometry_collection.rs @@ -1,5 +1,5 @@ use crate::iterator::GeometryCollectionIterator; -use crate::{Dimension, GeometryTrait}; +use crate::{Dimensions, GeometryTrait}; use geo_types::{CoordNum, Geometry, GeometryCollection}; /// A trait for accessing data from a generic GeometryCollection. @@ -15,7 +15,7 @@ pub trait GeometryCollectionTrait: Sized { Self: 'a; /// The dimension of this geometry - fn dim(&self) -> Dimension; + fn dim(&self) -> Dimensions; /// An iterator over the geometries in this GeometryCollection fn geometries(&self) -> impl Iterator> { @@ -49,8 +49,8 @@ impl GeometryCollectionTrait for GeometryCollection { where Self: 'a; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn num_geometries(&self) -> usize { @@ -67,8 +67,8 @@ impl<'a, T: CoordNum> GeometryCollectionTrait for &'a GeometryCollection { type GeometryType<'b> = &'a Geometry where Self: 'b; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn num_geometries(&self) -> usize { diff --git a/geo-traits/src/lib.rs b/geo-traits/src/lib.rs index 3ff3dacd72..05b360bc64 100644 --- a/geo-traits/src/lib.rs +++ b/geo-traits/src/lib.rs @@ -15,7 +15,7 @@ //! different endianness than the current machine, so individual values may need to be cloned on //! read. -pub use dimension::Dimension; +pub use dimension::Dimensions; pub use geometry::{GeometryTrait, GeometryType}; pub use geometry_collection::GeometryCollectionTrait; pub use line::{LineTrait, UnimplementedLine}; diff --git a/geo-traits/src/line.rs b/geo-traits/src/line.rs index 4ada0313df..57b47d81cb 100644 --- a/geo-traits/src/line.rs +++ b/geo-traits/src/line.rs @@ -1,6 +1,6 @@ use std::marker::PhantomData; -use crate::{Dimension, PointTrait, UnimplementedPoint}; +use crate::{Dimensions, PointTrait, UnimplementedPoint}; use geo_types::{Coord, CoordNum, Line}; /// A trait for accessing data from a generic Line. @@ -18,7 +18,7 @@ pub trait LineTrait: Sized { Self: 'a; /// The dimension of this geometry - fn dim(&self) -> Dimension; + fn dim(&self) -> Dimensions; /// Access the start point in this Line fn start(&self) -> Self::PointType<'_>; @@ -36,8 +36,8 @@ impl LineTrait for Line { type T = T; type PointType<'a> = &'a Coord where Self: 'a; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn start(&self) -> Self::PointType<'_> { @@ -53,8 +53,8 @@ impl<'a, T: CoordNum> LineTrait for &'a Line { type T = T; type PointType<'b> = &'a Coord where Self: 'b; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn start(&self) -> Self::PointType<'_> { @@ -76,7 +76,7 @@ impl LineTrait for UnimplementedLine { type T = T; type PointType<'a> = UnimplementedPoint where Self: 'a; - fn dim(&self) -> Dimension { + fn dim(&self) -> Dimensions { unimplemented!() } diff --git a/geo-traits/src/line_string.rs b/geo-traits/src/line_string.rs index 269d68222e..16babafbdd 100644 --- a/geo-traits/src/line_string.rs +++ b/geo-traits/src/line_string.rs @@ -1,7 +1,7 @@ use std::marker::PhantomData; use crate::iterator::LineStringIterator; -use crate::{Dimension, PointTrait, UnimplementedPoint}; +use crate::{Dimensions, PointTrait, UnimplementedPoint}; use geo_types::{Coord, CoordNum, LineString}; /// A trait for accessing data from a generic LineString. @@ -20,7 +20,7 @@ pub trait LineStringTrait: Sized { Self: 'a; /// The dimension of this geometry - fn dim(&self) -> Dimension; + fn dim(&self) -> Dimensions; /// An iterator over the points in this LineString fn points(&self) -> impl Iterator> { @@ -53,8 +53,8 @@ impl LineStringTrait for LineString { type T = T; type PointType<'a> = &'a Coord where Self: 'a; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn num_points(&self) -> usize { @@ -70,8 +70,8 @@ impl<'a, T: CoordNum> LineStringTrait for &'a LineString { type T = T; type PointType<'b> = &'a Coord where Self: 'b; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn num_points(&self) -> usize { @@ -93,7 +93,7 @@ impl LineStringTrait for UnimplementedLineString { type T = T; type PointType<'a> = UnimplementedPoint where Self: 'a; - fn dim(&self) -> Dimension { + fn dim(&self) -> Dimensions { unimplemented!() } diff --git a/geo-traits/src/multi_line_string.rs b/geo-traits/src/multi_line_string.rs index 916e0ee7ed..e4afcb3997 100644 --- a/geo-traits/src/multi_line_string.rs +++ b/geo-traits/src/multi_line_string.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use crate::iterator::MultiLineStringIterator; use crate::line_string::UnimplementedLineString; -use crate::{Dimension, LineStringTrait}; +use crate::{Dimensions, LineStringTrait}; use geo_types::{CoordNum, LineString, MultiLineString}; /// A trait for accessing data from a generic MultiLineString. @@ -20,7 +20,7 @@ pub trait MultiLineStringTrait: Sized { Self: 'a; /// The dimension of this geometry - fn dim(&self) -> Dimension; + fn dim(&self) -> Dimensions; /// An iterator over the LineStrings in this MultiLineString fn line_strings(&self) -> impl Iterator> { @@ -52,8 +52,8 @@ impl MultiLineStringTrait for MultiLineString { type T = T; type LineStringType<'a> = &'a LineString where Self: 'a; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn num_line_strings(&self) -> usize { @@ -69,8 +69,8 @@ impl<'a, T: CoordNum> MultiLineStringTrait for &'a MultiLineString { type T = T; type LineStringType<'b> = &'a LineString where Self: 'b; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn num_line_strings(&self) -> usize { @@ -92,7 +92,7 @@ impl MultiLineStringTrait for UnimplementedMultiLineString { type T = T; type LineStringType<'a> = UnimplementedLineString where Self: 'a; - fn dim(&self) -> Dimension { + fn dim(&self) -> Dimensions { unimplemented!() } diff --git a/geo-traits/src/multi_point.rs b/geo-traits/src/multi_point.rs index 97b2d7f549..a37289e332 100644 --- a/geo-traits/src/multi_point.rs +++ b/geo-traits/src/multi_point.rs @@ -1,7 +1,7 @@ use std::marker::PhantomData; use crate::iterator::MultiPointIterator; -use crate::{Dimension, PointTrait, UnimplementedPoint}; +use crate::{Dimensions, PointTrait, UnimplementedPoint}; use geo_types::{CoordNum, MultiPoint, Point}; /// A trait for accessing data from a generic MultiPoint. @@ -19,7 +19,7 @@ pub trait MultiPointTrait: Sized { Self: 'a; /// The dimension of this geometry - fn dim(&self) -> Dimension; + fn dim(&self) -> Dimensions; /// An iterator over the points in this MultiPoint fn points(&self) -> impl Iterator> { @@ -51,8 +51,8 @@ impl MultiPointTrait for MultiPoint { type T = T; type PointType<'a> = &'a Point where Self: 'a; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn num_points(&self) -> usize { @@ -68,8 +68,8 @@ impl<'a, T: CoordNum> MultiPointTrait for &'a MultiPoint { type T = T; type PointType<'b> = &'a Point where Self: 'b; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn num_points(&self) -> usize { @@ -91,7 +91,7 @@ impl MultiPointTrait for UnimplementedMultiPoint { type T = T; type PointType<'a> = UnimplementedPoint where Self: 'a; - fn dim(&self) -> Dimension { + fn dim(&self) -> Dimensions { unimplemented!() } diff --git a/geo-traits/src/multi_polygon.rs b/geo-traits/src/multi_polygon.rs index 125be4ee70..804c072e59 100644 --- a/geo-traits/src/multi_polygon.rs +++ b/geo-traits/src/multi_polygon.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use crate::iterator::MultiPolygonIterator; use crate::polygon::UnimplementedPolygon; -use crate::{Dimension, PolygonTrait}; +use crate::{Dimensions, PolygonTrait}; use geo_types::{CoordNum, MultiPolygon, Polygon}; /// A trait for accessing data from a generic MultiPolygon. @@ -18,7 +18,7 @@ pub trait MultiPolygonTrait: Sized { Self: 'a; /// The dimension of this geometry - fn dim(&self) -> Dimension; + fn dim(&self) -> Dimensions; /// An iterator over the Polygons in this MultiPolygon fn polygons(&self) -> impl Iterator> { @@ -50,8 +50,8 @@ impl MultiPolygonTrait for MultiPolygon { type T = T; type PolygonType<'a> = &'a Polygon where Self: 'a; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn num_polygons(&self) -> usize { @@ -67,8 +67,8 @@ impl<'a, T: CoordNum> MultiPolygonTrait for &'a MultiPolygon { type T = T; type PolygonType<'b> = &'a Polygon where Self: 'b; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn num_polygons(&self) -> usize { @@ -90,7 +90,7 @@ impl MultiPolygonTrait for UnimplementedMultiPolygon { type T = T; type PolygonType<'a> = UnimplementedPolygon where Self: 'a; - fn dim(&self) -> Dimension { + fn dim(&self) -> Dimensions { unimplemented!() } diff --git a/geo-traits/src/point.rs b/geo-traits/src/point.rs index 626f402a8e..082d7de975 100644 --- a/geo-traits/src/point.rs +++ b/geo-traits/src/point.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use geo_types::{Coord, CoordNum, Point}; -use crate::Dimension; +use crate::Dimensions; /// A trait for accessing data from a generic Point. /// @@ -16,8 +16,8 @@ pub trait PointTrait { /// See also [`nth()`](Self::nth). fn nth_unchecked(&self, n: usize) -> Self::T; - /// Dimension of the coordinate tuple - fn dim(&self) -> Dimension; + /// Dimensions of the coordinate tuple + fn dim(&self) -> Dimensions; /// Access the n'th (0-based) element of the CoordinateTuple. /// Returns NaN if `n >= DIMENSION`. @@ -57,8 +57,8 @@ impl PointTrait for Point { } } - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn x(&self) -> Self::T { @@ -81,8 +81,8 @@ impl PointTrait for &Point { } } - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn x(&self) -> Self::T { @@ -105,8 +105,8 @@ impl PointTrait for Coord { } } - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn x(&self) -> Self::T { @@ -129,8 +129,8 @@ impl PointTrait for &Coord { } } - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn x(&self) -> Self::T { @@ -153,8 +153,8 @@ impl PointTrait for (T, T) { } } - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn x(&self) -> Self::T { @@ -175,7 +175,7 @@ pub struct UnimplementedPoint(PhantomData); impl PointTrait for UnimplementedPoint { type T = T; - fn dim(&self) -> Dimension { + fn dim(&self) -> Dimensions { unimplemented!() } diff --git a/geo-traits/src/polygon.rs b/geo-traits/src/polygon.rs index 86b0c14f7c..2ec17a5aa6 100644 --- a/geo-traits/src/polygon.rs +++ b/geo-traits/src/polygon.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use crate::iterator::PolygonInteriorIterator; use crate::line_string::UnimplementedLineString; -use crate::{Dimension, LineStringTrait}; +use crate::{Dimensions, LineStringTrait}; use geo_types::{CoordNum, LineString, Polygon}; /// A trait for accessing data from a generic Polygon. @@ -22,7 +22,7 @@ pub trait PolygonTrait: Sized { Self: 'a; /// The dimension of this geometry - fn dim(&self) -> Dimension; + fn dim(&self) -> Dimensions; /// The exterior ring of the polygon fn exterior(&self) -> Option>; @@ -57,8 +57,8 @@ impl PolygonTrait for Polygon { type T = T; type RingType<'a> = &'a LineString where Self: 'a; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn exterior(&self) -> Option> { @@ -84,8 +84,8 @@ impl<'a, T: CoordNum> PolygonTrait for &'a Polygon { type RingType<'b> = &'a LineString where Self: 'b; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn exterior(&self) -> Option> { @@ -116,7 +116,7 @@ impl PolygonTrait for UnimplementedPolygon { type T = T; type RingType<'a> = UnimplementedLineString where Self: 'a; - fn dim(&self) -> Dimension { + fn dim(&self) -> Dimensions { unimplemented!() } diff --git a/geo-traits/src/rect.rs b/geo-traits/src/rect.rs index 8d37a1d065..2a430eb7d8 100644 --- a/geo-traits/src/rect.rs +++ b/geo-traits/src/rect.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use geo_types::{Coord, CoordNum, Rect}; -use crate::{Dimension, PointTrait, UnimplementedPoint}; +use crate::{Dimensions, PointTrait, UnimplementedPoint}; /// A trait for accessing data from a generic Rect. /// @@ -18,7 +18,7 @@ pub trait RectTrait { Self: 'a; /// The dimension of this geometry - fn dim(&self) -> Dimension; + fn dim(&self) -> Dimensions; /// The minimum coordinate of this Rect fn min(&self) -> Self::PointType<'_>; @@ -31,8 +31,8 @@ impl<'a, T: CoordNum + 'a> RectTrait for Rect { type T = T; type PointType<'b> = Coord where Self: 'b; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn min(&self) -> Self::PointType<'_> { @@ -48,8 +48,8 @@ impl<'a, T: CoordNum + 'a> RectTrait for &'a Rect { type T = T; type PointType<'b> = Coord where Self: 'b; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn min(&self) -> Self::PointType<'_> { @@ -71,7 +71,7 @@ impl RectTrait for UnimplementedRect { type T = T; type PointType<'a> = UnimplementedPoint where Self: 'a; - fn dim(&self) -> Dimension { + fn dim(&self) -> Dimensions { unimplemented!() } diff --git a/geo-traits/src/triangle.rs b/geo-traits/src/triangle.rs index a59fc3b0f1..18669f0914 100644 --- a/geo-traits/src/triangle.rs +++ b/geo-traits/src/triangle.rs @@ -1,6 +1,6 @@ use std::marker::PhantomData; -use crate::{Dimension, PointTrait, UnimplementedPoint}; +use crate::{Dimensions, PointTrait, UnimplementedPoint}; use geo_types::{Coord, CoordNum, Triangle}; /// A trait for accessing data from a generic Triangle. @@ -18,7 +18,7 @@ pub trait TriangleTrait: Sized { Self: 'a; /// The dimension of this geometry - fn dim(&self) -> Dimension; + fn dim(&self) -> Dimensions; /// Access the first point in this Triangle fn first(&self) -> Self::PointType<'_>; @@ -45,8 +45,8 @@ impl TriangleTrait for Triangle { type T = T; type PointType<'a> = &'a Coord where Self: 'a; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn first(&self) -> Self::PointType<'_> { @@ -66,8 +66,8 @@ impl<'a, T: CoordNum> TriangleTrait for &'a Triangle { type T = T; type PointType<'b> = &'a Coord where Self: 'b; - fn dim(&self) -> Dimension { - Dimension::XY + fn dim(&self) -> Dimensions { + Dimensions::XY } fn first(&self) -> Self::PointType<'_> { @@ -93,7 +93,7 @@ impl TriangleTrait for UnimplementedTriangle { type T = T; type PointType<'a> = UnimplementedPoint where Self: 'a; - fn dim(&self) -> Dimension { + fn dim(&self) -> Dimensions { unimplemented!() } From 6889cae27f31ebea6213fbd65df9c60477625e07 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Mon, 14 Oct 2024 19:09:30 -0400 Subject: [PATCH 20/33] No default x() and y() --- geo-traits/src/point.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/geo-traits/src/point.rs b/geo-traits/src/point.rs index 082d7de975..a782f5ecc6 100644 --- a/geo-traits/src/point.rs +++ b/geo-traits/src/point.rs @@ -31,14 +31,10 @@ pub trait PointTrait { } /// x component of this point. - fn x(&self) -> Self::T { - self.nth(0).unwrap() - } + fn x(&self) -> Self::T; /// y component of this point. - fn y(&self) -> Self::T { - self.nth(1).unwrap() - } + fn y(&self) -> Self::T; /// Returns a tuple that contains the x/horizontal & y/vertical component of the point. fn x_y(&self) -> (Self::T, Self::T) { @@ -182,4 +178,12 @@ impl PointTrait for UnimplementedPoint { fn nth_unchecked(&self, _n: usize) -> Self::T { unimplemented!() } + + fn x(&self) -> Self::T { + unimplemented!() + } + + fn y(&self) -> Self::T { + unimplemented!() + } } From de7ca8a4f51e00ea2807f6642e24c78351f479bc Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Mon, 14 Oct 2024 19:11:04 -0400 Subject: [PATCH 21/33] More descriptive point panics --- geo-traits/src/point.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/geo-traits/src/point.rs b/geo-traits/src/point.rs index a782f5ecc6..67d22f25bd 100644 --- a/geo-traits/src/point.rs +++ b/geo-traits/src/point.rs @@ -49,7 +49,7 @@ impl PointTrait for Point { match n { 0 => self.x(), 1 => self.y(), - _ => panic!(), + _ => panic!("Point only supports 2 dimensions"), } } @@ -73,7 +73,7 @@ impl PointTrait for &Point { match n { 0 => self.x(), 1 => self.y(), - _ => panic!(), + _ => panic!("Point only supports 2 dimensions"), } } @@ -97,7 +97,7 @@ impl PointTrait for Coord { match n { 0 => self.x(), 1 => self.y(), - _ => panic!(), + _ => panic!("Point only supports 2 dimensions"), } } @@ -121,7 +121,7 @@ impl PointTrait for &Coord { match n { 0 => self.x(), 1 => self.y(), - _ => panic!(), + _ => panic!("Point only supports 2 dimensions"), } } @@ -145,7 +145,7 @@ impl PointTrait for (T, T) { match n { 0 => self.x(), 1 => self.y(), - _ => panic!(), + _ => panic!("(T, T) only supports 2 dimensions"), } } From 0fb5ab8456f849bb089f0e0beba033244907db46 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Tue, 15 Oct 2024 13:44:01 -0400 Subject: [PATCH 22/33] Change to DoubleEndedIterator + ExactSizeIterator --- geo-traits/src/geometry_collection.rs | 4 +++- geo-traits/src/iterator.rs | 9 +++++++++ geo-traits/src/line_string.rs | 2 +- geo-traits/src/multi_line_string.rs | 4 +++- geo-traits/src/multi_point.rs | 2 +- geo-traits/src/multi_polygon.rs | 4 +++- geo-traits/src/polygon.rs | 2 +- 7 files changed, 21 insertions(+), 6 deletions(-) diff --git a/geo-traits/src/geometry_collection.rs b/geo-traits/src/geometry_collection.rs index ccfd881403..b958a10658 100644 --- a/geo-traits/src/geometry_collection.rs +++ b/geo-traits/src/geometry_collection.rs @@ -18,7 +18,9 @@ pub trait GeometryCollectionTrait: Sized { fn dim(&self) -> Dimensions; /// An iterator over the geometries in this GeometryCollection - fn geometries(&self) -> impl Iterator> { + fn geometries( + &self, + ) -> impl DoubleEndedIterator + ExactSizeIterator> { GeometryCollectionIterator::new(self, 0, self.num_geometries()) } diff --git a/geo-traits/src/iterator.rs b/geo-traits/src/iterator.rs index 83266478d0..f4f665a843 100644 --- a/geo-traits/src/iterator.rs +++ b/geo-traits/src/iterator.rs @@ -56,6 +56,15 @@ macro_rules! impl_iterator { } } + impl< + 'a, + T: CoordNum, + $item_type: 'a + $item_trait, + G: $self_trait = $item_type>, + > ExactSizeIterator for $struct_name<'a, T, $item_type, G> + { + } + impl< 'a, T: CoordNum, diff --git a/geo-traits/src/line_string.rs b/geo-traits/src/line_string.rs index 16babafbdd..9b98499ce8 100644 --- a/geo-traits/src/line_string.rs +++ b/geo-traits/src/line_string.rs @@ -23,7 +23,7 @@ pub trait LineStringTrait: Sized { fn dim(&self) -> Dimensions; /// An iterator over the points in this LineString - fn points(&self) -> impl Iterator> { + fn points(&self) -> impl DoubleEndedIterator + ExactSizeIterator> { LineStringIterator::new(self, 0, self.num_points()) } diff --git a/geo-traits/src/multi_line_string.rs b/geo-traits/src/multi_line_string.rs index e4afcb3997..d7163f0cf3 100644 --- a/geo-traits/src/multi_line_string.rs +++ b/geo-traits/src/multi_line_string.rs @@ -23,7 +23,9 @@ pub trait MultiLineStringTrait: Sized { fn dim(&self) -> Dimensions; /// An iterator over the LineStrings in this MultiLineString - fn line_strings(&self) -> impl Iterator> { + fn line_strings( + &self, + ) -> impl DoubleEndedIterator + ExactSizeIterator> { MultiLineStringIterator::new(self, 0, self.num_line_strings()) } diff --git a/geo-traits/src/multi_point.rs b/geo-traits/src/multi_point.rs index a37289e332..66077fae0a 100644 --- a/geo-traits/src/multi_point.rs +++ b/geo-traits/src/multi_point.rs @@ -22,7 +22,7 @@ pub trait MultiPointTrait: Sized { fn dim(&self) -> Dimensions; /// An iterator over the points in this MultiPoint - fn points(&self) -> impl Iterator> { + fn points(&self) -> impl DoubleEndedIterator + ExactSizeIterator> { MultiPointIterator::new(self, 0, self.num_points()) } diff --git a/geo-traits/src/multi_polygon.rs b/geo-traits/src/multi_polygon.rs index 804c072e59..7ecce9d55e 100644 --- a/geo-traits/src/multi_polygon.rs +++ b/geo-traits/src/multi_polygon.rs @@ -21,7 +21,9 @@ pub trait MultiPolygonTrait: Sized { fn dim(&self) -> Dimensions; /// An iterator over the Polygons in this MultiPolygon - fn polygons(&self) -> impl Iterator> { + fn polygons( + &self, + ) -> impl DoubleEndedIterator + ExactSizeIterator> { MultiPolygonIterator::new(self, 0, self.num_polygons()) } diff --git a/geo-traits/src/polygon.rs b/geo-traits/src/polygon.rs index 2ec17a5aa6..cceb9ef731 100644 --- a/geo-traits/src/polygon.rs +++ b/geo-traits/src/polygon.rs @@ -28,7 +28,7 @@ pub trait PolygonTrait: Sized { fn exterior(&self) -> Option>; /// An iterator of the interior rings of this Polygon - fn interiors(&self) -> impl Iterator> { + fn interiors(&self) -> impl DoubleEndedIterator + ExactSizeIterator> { PolygonInteriorIterator::new(self, 0, self.num_interiors()) } From 58117ce0a405505a56da4085d921c17978a8e44f Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Tue, 15 Oct 2024 13:47:04 -0400 Subject: [PATCH 23/33] change dimensions case --- geo-traits/src/dimension.rs | 15 +++++++-------- geo-traits/src/geometry.rs | 8 ++++---- geo-traits/src/geometry_collection.rs | 4 ++-- geo-traits/src/line.rs | 4 ++-- geo-traits/src/line_string.rs | 4 ++-- geo-traits/src/multi_line_string.rs | 4 ++-- geo-traits/src/multi_point.rs | 4 ++-- geo-traits/src/multi_polygon.rs | 4 ++-- geo-traits/src/point.rs | 10 +++++----- geo-traits/src/polygon.rs | 4 ++-- geo-traits/src/rect.rs | 4 ++-- geo-traits/src/triangle.rs | 4 ++-- 12 files changed, 34 insertions(+), 35 deletions(-) diff --git a/geo-traits/src/dimension.rs b/geo-traits/src/dimension.rs index b1d1c6f241..d7eee3a01a 100644 --- a/geo-traits/src/dimension.rs +++ b/geo-traits/src/dimension.rs @@ -1,20 +1,19 @@ /// The logical dimension of the geometry. /// /// -#[allow(clippy::upper_case_acronyms)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Dimensions { /// A two-dimensional geometry with X and Y values - XY, + Xy, /// A three-dimensional geometry with X, Y, and Z values - XYZ, + Xyz, /// A three-dimensional geometry with X, Y, and M values - XYM, + Xym, /// A four-dimensional geometry with X, Y, Z, and M values - XYZM, + Xyzm, /// A geometry with unknown logical type. The contained `usize` value represents the number of /// physical dimensions. @@ -25,9 +24,9 @@ impl Dimensions { /// The physical number of dimensions in this geometry. pub fn size(&self) -> usize { match self { - Self::XY => 2, - Self::XYZ | Self::XYM => 3, - Self::XYZM => 4, + Self::Xy => 2, + Self::Xyz | Self::Xym => 3, + Self::Xyzm => 4, Self::Unknown(val) => *val, } } diff --git a/geo-traits/src/geometry.rs b/geo-traits/src/geometry.rs index 69fe299e6d..4e46d15b8c 100644 --- a/geo-traits/src/geometry.rs +++ b/geo-traits/src/geometry.rs @@ -138,7 +138,7 @@ impl<'a, T: CoordNum + 'a> GeometryTrait for Geometry { type LineType<'b> = Line where Self: 'b; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn as_type( @@ -185,7 +185,7 @@ impl<'a, T: CoordNum + 'a> GeometryTrait for &'a Geometry { type LineType<'b> = Line where Self: 'b; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn as_type( @@ -236,7 +236,7 @@ macro_rules! impl_specialization { type LineType<'b> = Line where Self: 'b; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn as_type( @@ -272,7 +272,7 @@ macro_rules! impl_specialization { type LineType<'b> = Line where Self: 'b; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn as_type( diff --git a/geo-traits/src/geometry_collection.rs b/geo-traits/src/geometry_collection.rs index b958a10658..997bfa54ad 100644 --- a/geo-traits/src/geometry_collection.rs +++ b/geo-traits/src/geometry_collection.rs @@ -52,7 +52,7 @@ impl GeometryCollectionTrait for GeometryCollection { Self: 'a; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn num_geometries(&self) -> usize { @@ -70,7 +70,7 @@ impl<'a, T: CoordNum> GeometryCollectionTrait for &'a GeometryCollection { Self: 'b; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn num_geometries(&self) -> usize { diff --git a/geo-traits/src/line.rs b/geo-traits/src/line.rs index 57b47d81cb..db8d4a36ce 100644 --- a/geo-traits/src/line.rs +++ b/geo-traits/src/line.rs @@ -37,7 +37,7 @@ impl LineTrait for Line { type PointType<'a> = &'a Coord where Self: 'a; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn start(&self) -> Self::PointType<'_> { @@ -54,7 +54,7 @@ impl<'a, T: CoordNum> LineTrait for &'a Line { type PointType<'b> = &'a Coord where Self: 'b; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn start(&self) -> Self::PointType<'_> { diff --git a/geo-traits/src/line_string.rs b/geo-traits/src/line_string.rs index 9b98499ce8..006749a921 100644 --- a/geo-traits/src/line_string.rs +++ b/geo-traits/src/line_string.rs @@ -54,7 +54,7 @@ impl LineStringTrait for LineString { type PointType<'a> = &'a Coord where Self: 'a; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn num_points(&self) -> usize { @@ -71,7 +71,7 @@ impl<'a, T: CoordNum> LineStringTrait for &'a LineString { type PointType<'b> = &'a Coord where Self: 'b; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn num_points(&self) -> usize { diff --git a/geo-traits/src/multi_line_string.rs b/geo-traits/src/multi_line_string.rs index d7163f0cf3..7e946ff440 100644 --- a/geo-traits/src/multi_line_string.rs +++ b/geo-traits/src/multi_line_string.rs @@ -55,7 +55,7 @@ impl MultiLineStringTrait for MultiLineString { type LineStringType<'a> = &'a LineString where Self: 'a; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn num_line_strings(&self) -> usize { @@ -72,7 +72,7 @@ impl<'a, T: CoordNum> MultiLineStringTrait for &'a MultiLineString { type LineStringType<'b> = &'a LineString where Self: 'b; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn num_line_strings(&self) -> usize { diff --git a/geo-traits/src/multi_point.rs b/geo-traits/src/multi_point.rs index 66077fae0a..0d8c711e62 100644 --- a/geo-traits/src/multi_point.rs +++ b/geo-traits/src/multi_point.rs @@ -52,7 +52,7 @@ impl MultiPointTrait for MultiPoint { type PointType<'a> = &'a Point where Self: 'a; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn num_points(&self) -> usize { @@ -69,7 +69,7 @@ impl<'a, T: CoordNum> MultiPointTrait for &'a MultiPoint { type PointType<'b> = &'a Point where Self: 'b; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn num_points(&self) -> usize { diff --git a/geo-traits/src/multi_polygon.rs b/geo-traits/src/multi_polygon.rs index 7ecce9d55e..fc559bd230 100644 --- a/geo-traits/src/multi_polygon.rs +++ b/geo-traits/src/multi_polygon.rs @@ -53,7 +53,7 @@ impl MultiPolygonTrait for MultiPolygon { type PolygonType<'a> = &'a Polygon where Self: 'a; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn num_polygons(&self) -> usize { @@ -70,7 +70,7 @@ impl<'a, T: CoordNum> MultiPolygonTrait for &'a MultiPolygon { type PolygonType<'b> = &'a Polygon where Self: 'b; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn num_polygons(&self) -> usize { diff --git a/geo-traits/src/point.rs b/geo-traits/src/point.rs index 67d22f25bd..a73cbf8882 100644 --- a/geo-traits/src/point.rs +++ b/geo-traits/src/point.rs @@ -54,7 +54,7 @@ impl PointTrait for Point { } fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn x(&self) -> Self::T { @@ -78,7 +78,7 @@ impl PointTrait for &Point { } fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn x(&self) -> Self::T { @@ -102,7 +102,7 @@ impl PointTrait for Coord { } fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn x(&self) -> Self::T { @@ -126,7 +126,7 @@ impl PointTrait for &Coord { } fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn x(&self) -> Self::T { @@ -150,7 +150,7 @@ impl PointTrait for (T, T) { } fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn x(&self) -> Self::T { diff --git a/geo-traits/src/polygon.rs b/geo-traits/src/polygon.rs index cceb9ef731..99dcc53af5 100644 --- a/geo-traits/src/polygon.rs +++ b/geo-traits/src/polygon.rs @@ -58,7 +58,7 @@ impl PolygonTrait for Polygon { type RingType<'a> = &'a LineString where Self: 'a; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn exterior(&self) -> Option> { @@ -85,7 +85,7 @@ impl<'a, T: CoordNum> PolygonTrait for &'a Polygon { Self: 'b; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn exterior(&self) -> Option> { diff --git a/geo-traits/src/rect.rs b/geo-traits/src/rect.rs index 2a430eb7d8..a96d25ab7c 100644 --- a/geo-traits/src/rect.rs +++ b/geo-traits/src/rect.rs @@ -32,7 +32,7 @@ impl<'a, T: CoordNum + 'a> RectTrait for Rect { type PointType<'b> = Coord where Self: 'b; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn min(&self) -> Self::PointType<'_> { @@ -49,7 +49,7 @@ impl<'a, T: CoordNum + 'a> RectTrait for &'a Rect { type PointType<'b> = Coord where Self: 'b; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn min(&self) -> Self::PointType<'_> { diff --git a/geo-traits/src/triangle.rs b/geo-traits/src/triangle.rs index 18669f0914..21a0a49b8e 100644 --- a/geo-traits/src/triangle.rs +++ b/geo-traits/src/triangle.rs @@ -46,7 +46,7 @@ impl TriangleTrait for Triangle { type PointType<'a> = &'a Coord where Self: 'a; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn first(&self) -> Self::PointType<'_> { @@ -67,7 +67,7 @@ impl<'a, T: CoordNum> TriangleTrait for &'a Triangle { type PointType<'b> = &'a Coord where Self: 'b; fn dim(&self) -> Dimensions { - Dimensions::XY + Dimensions::Xy } fn first(&self) -> Self::PointType<'_> { From 6b697dd7d3f3017e7d92e36cb9b9feb27006335c Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Wed, 16 Oct 2024 11:44:47 -0400 Subject: [PATCH 24/33] Update geo-traits/src/point.rs Co-authored-by: Corey Farwell --- geo-traits/src/point.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geo-traits/src/point.rs b/geo-traits/src/point.rs index a73cbf8882..9c10b7d54a 100644 --- a/geo-traits/src/point.rs +++ b/geo-traits/src/point.rs @@ -21,7 +21,7 @@ pub trait PointTrait { /// Access the n'th (0-based) element of the CoordinateTuple. /// Returns NaN if `n >= DIMENSION`. - /// See also [`nth()`](Self::nth_unchecked). + /// See also [`nth_unchecked()`](Self::nth_unchecked). fn nth(&self, n: usize) -> Option { if n < self.dim().size() { Some(self.nth_unchecked(n)) From 2eb3b03317259165d740ebc5deca1b910086501d Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Wed, 16 Oct 2024 12:13:00 -0400 Subject: [PATCH 25/33] reorder unchecked --- geo-traits/src/point.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/geo-traits/src/point.rs b/geo-traits/src/point.rs index 9c10b7d54a..14a0277bda 100644 --- a/geo-traits/src/point.rs +++ b/geo-traits/src/point.rs @@ -11,11 +11,6 @@ pub trait PointTrait { /// The coordinate type of this geometry type T: CoordNum; - /// Access the n'th (0-based) element of the CoordinateTuple. - /// May panic if n >= DIMENSION. - /// See also [`nth()`](Self::nth). - fn nth_unchecked(&self, n: usize) -> Self::T; - /// Dimensions of the coordinate tuple fn dim(&self) -> Dimensions; @@ -40,6 +35,11 @@ pub trait PointTrait { fn x_y(&self) -> (Self::T, Self::T) { (self.x(), self.y()) } + + /// Access the n'th (0-based) element of the CoordinateTuple. + /// May panic if n >= DIMENSION. + /// See also [`nth()`](Self::nth). + fn nth_unchecked(&self, n: usize) -> Self::T; } impl PointTrait for Point { From 1f68cc358f76af81ccf93f77c8042a851522dd9c Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Wed, 16 Oct 2024 12:19:20 -0400 Subject: [PATCH 26/33] `PointTrait::is_empty` --- geo-traits/src/lib.rs | 2 ++ geo-traits/src/point.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/geo-traits/src/lib.rs b/geo-traits/src/lib.rs index 05b360bc64..293a00755f 100644 --- a/geo-traits/src/lib.rs +++ b/geo-traits/src/lib.rs @@ -15,6 +15,8 @@ //! different endianness than the current machine, so individual values may need to be cloned on //! read. +#![deny(missing_docs)] + pub use dimension::Dimensions; pub use geometry::{GeometryTrait, GeometryType}; pub use geometry_collection::GeometryCollectionTrait; diff --git a/geo-traits/src/point.rs b/geo-traits/src/point.rs index 14a0277bda..f1600c5067 100644 --- a/geo-traits/src/point.rs +++ b/geo-traits/src/point.rs @@ -25,6 +25,14 @@ pub trait PointTrait { } } + /// Whether this point is `empty` or not. + /// + /// According to Simple Features, a Point can have zero coordinates and be considered `empty`. + /// + /// If `is_empty` returns `true`, then the values of `x()`, `y()`, `nth()` and `nth_unchecked` + /// have no semantic meaning. + fn is_empty(&self) -> bool; + /// x component of this point. fn x(&self) -> Self::T; @@ -53,6 +61,10 @@ impl PointTrait for Point { } } + fn is_empty(&self) -> bool { + false + } + fn dim(&self) -> Dimensions { Dimensions::Xy } @@ -77,6 +89,10 @@ impl PointTrait for &Point { } } + fn is_empty(&self) -> bool { + false + } + fn dim(&self) -> Dimensions { Dimensions::Xy } @@ -101,6 +117,10 @@ impl PointTrait for Coord { } } + fn is_empty(&self) -> bool { + false + } + fn dim(&self) -> Dimensions { Dimensions::Xy } @@ -125,6 +145,10 @@ impl PointTrait for &Coord { } } + fn is_empty(&self) -> bool { + false + } + fn dim(&self) -> Dimensions { Dimensions::Xy } @@ -149,6 +173,10 @@ impl PointTrait for (T, T) { } } + fn is_empty(&self) -> bool { + false + } + fn dim(&self) -> Dimensions { Dimensions::Xy } @@ -171,6 +199,10 @@ pub struct UnimplementedPoint(PhantomData); impl PointTrait for UnimplementedPoint { type T = T; + fn is_empty(&self) -> bool { + unimplemented!() + } + fn dim(&self) -> Dimensions { unimplemented!() } From d49873ba33084ee1a3391199809be4aaf405beb7 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Wed, 16 Oct 2024 12:26:39 -0400 Subject: [PATCH 27/33] Add sentence to is_empty --- geo-traits/src/point.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/geo-traits/src/point.rs b/geo-traits/src/point.rs index f1600c5067..2e87705c0f 100644 --- a/geo-traits/src/point.rs +++ b/geo-traits/src/point.rs @@ -31,6 +31,10 @@ pub trait PointTrait { /// /// If `is_empty` returns `true`, then the values of `x()`, `y()`, `nth()` and `nth_unchecked` /// have no semantic meaning. + /// + /// Only a top-level geometry can be empty. That is, when this point is contained within + /// another geometry, such as a [`LineStringTrait`][geo_traits::LineStringTrait], those points + /// can never be empty, and a consumer does not need to check this method. fn is_empty(&self) -> bool; /// x component of this point. From 7c0e90fe450220aac82ccb3aa0d7487ab3172b27 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Wed, 16 Oct 2024 12:54:45 -0400 Subject: [PATCH 28/33] fix doc link --- geo-traits/src/point.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geo-traits/src/point.rs b/geo-traits/src/point.rs index 2e87705c0f..ff2ef448e0 100644 --- a/geo-traits/src/point.rs +++ b/geo-traits/src/point.rs @@ -33,7 +33,7 @@ pub trait PointTrait { /// have no semantic meaning. /// /// Only a top-level geometry can be empty. That is, when this point is contained within - /// another geometry, such as a [`LineStringTrait`][geo_traits::LineStringTrait], those points + /// another geometry, such as a [`LineStringTrait`][crate::LineStringTrait], those points /// can never be empty, and a consumer does not need to check this method. fn is_empty(&self) -> bool; From 09de278a6d5eec3f84593cbce3a3bcddaa66790f Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Thu, 17 Oct 2024 23:03:20 -0400 Subject: [PATCH 29/33] Use array --- geo-traits/src/triangle.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/geo-traits/src/triangle.rs b/geo-traits/src/triangle.rs index 21a0a49b8e..6322e19d66 100644 --- a/geo-traits/src/triangle.rs +++ b/geo-traits/src/triangle.rs @@ -30,14 +30,8 @@ pub trait TriangleTrait: Sized { fn third(&self) -> Self::PointType<'_>; /// Access the three underlying points - fn points( - &self, - ) -> ( - Self::PointType<'_>, - Self::PointType<'_>, - Self::PointType<'_>, - ) { - (self.first(), self.second(), self.third()) + fn points(&self) -> [Self::PointType<'_>; 3] { + [self.first(), self.second(), self.third()] } } From 8418780e85d074a0ac2deed3882de0b07b7bbfb7 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Fri, 18 Oct 2024 00:53:04 -0400 Subject: [PATCH 30/33] Update geo-traits/src/line.rs Co-authored-by: Corey Farwell --- geo-traits/src/line.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/geo-traits/src/line.rs b/geo-traits/src/line.rs index db8d4a36ce..bf895fd0d8 100644 --- a/geo-traits/src/line.rs +++ b/geo-traits/src/line.rs @@ -27,8 +27,8 @@ pub trait LineTrait: Sized { fn end(&self) -> Self::PointType<'_>; /// Access the three underlying points - fn points(&self) -> (Self::PointType<'_>, Self::PointType<'_>) { - (self.start(), self.end()) + fn points(&self) -> [Self::PointType<'_>; 2] { + [self.start(), self.end()] } } From 4a9b3cc150483275d2738392efe87fd9dc1f47be Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Tue, 22 Oct 2024 10:56:54 -0400 Subject: [PATCH 31/33] typo --- geo-traits/src/line.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geo-traits/src/line.rs b/geo-traits/src/line.rs index bf895fd0d8..b882958dda 100644 --- a/geo-traits/src/line.rs +++ b/geo-traits/src/line.rs @@ -26,7 +26,7 @@ pub trait LineTrait: Sized { /// Access the start point in this Line fn end(&self) -> Self::PointType<'_>; - /// Access the three underlying points + /// Access the two underlying points fn points(&self) -> [Self::PointType<'_>; 2] { [self.start(), self.end()] } From 47643430f043e4aa72bbccf7015d94a10ce69014 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Thu, 24 Oct 2024 15:01:39 -0400 Subject: [PATCH 32/33] Restore CoordTrait, PointTrait yields Option --- geo-traits/src/coord.rs | 141 +++++++++++++++++++++++++++ geo-traits/src/iterator.rs | 8 +- geo-traits/src/lib.rs | 2 + geo-traits/src/line.rs | 38 ++++---- geo-traits/src/line_string.rs | 48 ++++----- geo-traits/src/point.rs | 177 +++------------------------------- geo-traits/src/polygon.rs | 4 +- geo-traits/src/rect.rs | 30 +++--- geo-traits/src/triangle.rs | 48 ++++----- 9 files changed, 247 insertions(+), 249 deletions(-) create mode 100644 geo-traits/src/coord.rs diff --git a/geo-traits/src/coord.rs b/geo-traits/src/coord.rs new file mode 100644 index 0000000000..c70b708589 --- /dev/null +++ b/geo-traits/src/coord.rs @@ -0,0 +1,141 @@ +use std::marker::PhantomData; + +use geo_types::{Coord, CoordNum}; + +use crate::Dimensions; + +/// A trait for accessing data from a generic Coord. +/// +/// Refer to [geo_types::Coord] for information about semantics and validity. +pub trait CoordTrait { + /// The coordinate type of this geometry + type T: CoordNum; + + /// Dimensions of the coordinate tuple + fn dim(&self) -> Dimensions; + + /// Access the n'th (0-based) element of the CoordinateTuple. + /// Returns NaN if `n >= DIMENSION`. + /// See also [`nth_unchecked()`](Self::nth_unchecked). + fn nth(&self, n: usize) -> Option { + if n < self.dim().size() { + Some(self.nth_unchecked(n)) + } else { + None + } + } + + /// x component of this coord. + fn x(&self) -> Self::T; + + /// y component of this coord. + fn y(&self) -> Self::T; + + /// Returns a tuple that contains the x/horizontal & y/vertical component of the coord. + fn x_y(&self) -> (Self::T, Self::T) { + (self.x(), self.y()) + } + + /// Access the n'th (0-based) element of the CoordinateTuple. + /// May panic if n >= DIMENSION. + /// See also [`nth()`](Self::nth). + fn nth_unchecked(&self, n: usize) -> Self::T; +} + +impl CoordTrait for Coord { + type T = T; + + fn nth_unchecked(&self, n: usize) -> Self::T { + match n { + 0 => self.x(), + 1 => self.y(), + _ => panic!("Coord only supports 2 dimensions"), + } + } + + fn dim(&self) -> Dimensions { + Dimensions::Xy + } + + fn x(&self) -> Self::T { + self.x + } + + fn y(&self) -> Self::T { + self.y + } +} + +impl CoordTrait for &Coord { + type T = T; + + fn nth_unchecked(&self, n: usize) -> Self::T { + match n { + 0 => self.x(), + 1 => self.y(), + _ => panic!("Coord only supports 2 dimensions"), + } + } + + fn dim(&self) -> Dimensions { + Dimensions::Xy + } + + fn x(&self) -> Self::T { + self.x + } + + fn y(&self) -> Self::T { + self.y + } +} + +impl CoordTrait for (T, T) { + type T = T; + + fn nth_unchecked(&self, n: usize) -> Self::T { + match n { + 0 => self.x(), + 1 => self.y(), + _ => panic!("(T, T) only supports 2 dimensions"), + } + } + + fn dim(&self) -> Dimensions { + Dimensions::Xy + } + + fn x(&self) -> Self::T { + self.0 + } + + fn y(&self) -> Self::T { + self.1 + } +} + +/// An empty struct that implements [CoordTrait]. +/// +/// This can be used as the `CoordType` of the `GeometryTrait` by implementations that don't have a +/// Coord concept +pub struct UnimplementedCoord(PhantomData); + +impl CoordTrait for UnimplementedCoord { + type T = T; + + fn dim(&self) -> Dimensions { + unimplemented!() + } + + fn nth_unchecked(&self, _n: usize) -> Self::T { + unimplemented!() + } + + fn x(&self) -> Self::T { + unimplemented!() + } + + fn y(&self) -> Self::T { + unimplemented!() + } +} diff --git a/geo-traits/src/iterator.rs b/geo-traits/src/iterator.rs index f4f665a843..1edc8b8187 100644 --- a/geo-traits/src/iterator.rs +++ b/geo-traits/src/iterator.rs @@ -1,3 +1,5 @@ +use crate::CoordTrait; + use super::{ GeometryCollectionTrait, GeometryTrait, LineStringTrait, MultiLineStringTrait, MultiPointTrait, MultiPolygonTrait, PointTrait, PolygonTrait, @@ -88,9 +90,9 @@ macro_rules! impl_iterator { impl_iterator!( LineStringIterator, LineStringTrait, - PointTrait, - point_unchecked, - PointType + CoordTrait, + coord_unchecked, + CoordType ); impl_iterator!( PolygonInteriorIterator, diff --git a/geo-traits/src/lib.rs b/geo-traits/src/lib.rs index 293a00755f..de24bd2638 100644 --- a/geo-traits/src/lib.rs +++ b/geo-traits/src/lib.rs @@ -17,6 +17,7 @@ #![deny(missing_docs)] +pub use coord::{CoordTrait, UnimplementedCoord}; pub use dimension::Dimensions; pub use geometry::{GeometryTrait, GeometryType}; pub use geometry_collection::GeometryCollectionTrait; @@ -30,6 +31,7 @@ pub use polygon::{PolygonTrait, UnimplementedPolygon}; pub use rect::{RectTrait, UnimplementedRect}; pub use triangle::{TriangleTrait, UnimplementedTriangle}; +mod coord; mod dimension; mod geometry; mod geometry_collection; diff --git a/geo-traits/src/line.rs b/geo-traits/src/line.rs index b882958dda..b67b573ef2 100644 --- a/geo-traits/src/line.rs +++ b/geo-traits/src/line.rs @@ -1,67 +1,67 @@ use std::marker::PhantomData; -use crate::{Dimensions, PointTrait, UnimplementedPoint}; +use crate::{CoordTrait, Dimensions, UnimplementedCoord}; use geo_types::{Coord, CoordNum, Line}; /// A trait for accessing data from a generic Line. /// -/// A Line is a line segment made up of exactly two [points][PointTrait]. +/// A Line is a line segment made up of exactly two [coordinates][CoordTrait]. /// /// Refer to [geo_types::Line] for information about semantics and validity. pub trait LineTrait: Sized { /// The coordinate type of this geometry type T: CoordNum; - /// The type of each underlying coordinate, which implements [PointTrait] - type PointType<'a>: 'a + PointTrait + /// The type of each underlying coordinate, which implements [CoordTrait] + type CoordType<'a>: 'a + CoordTrait where Self: 'a; /// The dimension of this geometry fn dim(&self) -> Dimensions; - /// Access the start point in this Line - fn start(&self) -> Self::PointType<'_>; + /// Access the start coordinate in this Line + fn start(&self) -> Self::CoordType<'_>; - /// Access the start point in this Line - fn end(&self) -> Self::PointType<'_>; + /// Access the start coordinate in this Line + fn end(&self) -> Self::CoordType<'_>; - /// Access the two underlying points - fn points(&self) -> [Self::PointType<'_>; 2] { + /// Access the two underlying coordinates + fn coords(&self) -> [Self::CoordType<'_>; 2] { [self.start(), self.end()] } } impl LineTrait for Line { type T = T; - type PointType<'a> = &'a Coord where Self: 'a; + type CoordType<'a> = &'a Coord where Self: 'a; fn dim(&self) -> Dimensions { Dimensions::Xy } - fn start(&self) -> Self::PointType<'_> { + fn start(&self) -> Self::CoordType<'_> { &self.start } - fn end(&self) -> Self::PointType<'_> { + fn end(&self) -> Self::CoordType<'_> { &self.end } } impl<'a, T: CoordNum> LineTrait for &'a Line { type T = T; - type PointType<'b> = &'a Coord where Self: 'b; + type CoordType<'b> = &'a Coord where Self: 'b; fn dim(&self) -> Dimensions { Dimensions::Xy } - fn start(&self) -> Self::PointType<'_> { + fn start(&self) -> Self::CoordType<'_> { &self.start } - fn end(&self) -> Self::PointType<'_> { + fn end(&self) -> Self::CoordType<'_> { &self.end } } @@ -74,17 +74,17 @@ pub struct UnimplementedLine(PhantomData); impl LineTrait for UnimplementedLine { type T = T; - type PointType<'a> = UnimplementedPoint where Self: 'a; + type CoordType<'a> = UnimplementedCoord where Self: 'a; fn dim(&self) -> Dimensions { unimplemented!() } - fn start(&self) -> Self::PointType<'_> { + fn start(&self) -> Self::CoordType<'_> { unimplemented!() } - fn end(&self) -> Self::PointType<'_> { + fn end(&self) -> Self::CoordType<'_> { unimplemented!() } } diff --git a/geo-traits/src/line_string.rs b/geo-traits/src/line_string.rs index 006749a921..28eb9b3ca0 100644 --- a/geo-traits/src/line_string.rs +++ b/geo-traits/src/line_string.rs @@ -1,12 +1,12 @@ use std::marker::PhantomData; use crate::iterator::LineStringIterator; -use crate::{Dimensions, PointTrait, UnimplementedPoint}; +use crate::{CoordTrait, Dimensions, UnimplementedCoord}; use geo_types::{Coord, CoordNum, LineString}; /// A trait for accessing data from a generic LineString. /// -/// A LineString is an ordered collection of two or more [points][PointTrait], representing a path +/// A LineString is an ordered collection of two or more [points][CoordTrait], representing a path /// between locations. /// /// Refer to [geo_types::LineString] for information about semantics and validity. @@ -14,71 +14,71 @@ pub trait LineStringTrait: Sized { /// The coordinate type of this geometry type T: CoordNum; - /// The type of each underlying coordinate, which implements [PointTrait] - type PointType<'a>: 'a + PointTrait + /// The type of each underlying coordinate, which implements [CoordTrait] + type CoordType<'a>: 'a + CoordTrait where Self: 'a; /// The dimension of this geometry fn dim(&self) -> Dimensions; - /// An iterator over the points in this LineString - fn points(&self) -> impl DoubleEndedIterator + ExactSizeIterator> { - LineStringIterator::new(self, 0, self.num_points()) + /// An iterator over the coordinates in this LineString + fn coords(&self) -> impl DoubleEndedIterator + ExactSizeIterator> { + LineStringIterator::new(self, 0, self.num_coords()) } - /// The number of points in this LineString - fn num_points(&self) -> usize; + /// The number of coordinates in this LineString + fn num_coords(&self) -> usize; - /// Access to a specified point in this LineString + /// Access to a specified coordinate in this LineString /// Will return None if the provided index is out of bounds #[inline] - fn point(&self, i: usize) -> Option> { - if i >= self.num_points() { + fn coord(&self, i: usize) -> Option> { + if i >= self.num_coords() { None } else { - unsafe { Some(self.point_unchecked(i)) } + unsafe { Some(self.coord_unchecked(i)) } } } - /// Access to a specified point in this LineString + /// Access to a specified coordinate in this LineString /// /// # Safety /// /// Accessing an index out of bounds is UB. - unsafe fn point_unchecked(&self, i: usize) -> Self::PointType<'_>; + unsafe fn coord_unchecked(&self, i: usize) -> Self::CoordType<'_>; } impl LineStringTrait for LineString { type T = T; - type PointType<'a> = &'a Coord where Self: 'a; + type CoordType<'a> = &'a Coord where Self: 'a; fn dim(&self) -> Dimensions { Dimensions::Xy } - fn num_points(&self) -> usize { + fn num_coords(&self) -> usize { self.0.len() } - unsafe fn point_unchecked(&self, i: usize) -> Self::PointType<'_> { + unsafe fn coord_unchecked(&self, i: usize) -> Self::CoordType<'_> { self.0.get_unchecked(i) } } impl<'a, T: CoordNum> LineStringTrait for &'a LineString { type T = T; - type PointType<'b> = &'a Coord where Self: 'b; + type CoordType<'b> = &'a Coord where Self: 'b; fn dim(&self) -> Dimensions { Dimensions::Xy } - fn num_points(&self) -> usize { + fn num_coords(&self) -> usize { self.0.len() } - unsafe fn point_unchecked(&self, i: usize) -> Self::PointType<'_> { + unsafe fn coord_unchecked(&self, i: usize) -> Self::CoordType<'_> { self.0.get_unchecked(i) } } @@ -91,17 +91,17 @@ pub struct UnimplementedLineString(PhantomData); impl LineStringTrait for UnimplementedLineString { type T = T; - type PointType<'a> = UnimplementedPoint where Self: 'a; + type CoordType<'a> = UnimplementedCoord where Self: 'a; fn dim(&self) -> Dimensions { unimplemented!() } - fn num_points(&self) -> usize { + fn num_coords(&self) -> usize { unimplemented!() } - unsafe fn point_unchecked(&self, _i: usize) -> Self::PointType<'_> { + unsafe fn coord_unchecked(&self, _i: usize) -> Self::CoordType<'_> { unimplemented!() } } diff --git a/geo-traits/src/point.rs b/geo-traits/src/point.rs index ff2ef448e0..883315e507 100644 --- a/geo-traits/src/point.rs +++ b/geo-traits/src/point.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use geo_types::{Coord, CoordNum, Point}; -use crate::Dimensions; +use crate::{CoordTrait, Dimensions, UnimplementedCoord}; /// A trait for accessing data from a generic Point. /// @@ -11,20 +11,14 @@ pub trait PointTrait { /// The coordinate type of this geometry type T: CoordNum; + /// The type of the underlying coordinate, which implements [CoordTrait] + type CoordType<'a>: 'a + CoordTrait + where + Self: 'a; + /// Dimensions of the coordinate tuple fn dim(&self) -> Dimensions; - /// Access the n'th (0-based) element of the CoordinateTuple. - /// Returns NaN if `n >= DIMENSION`. - /// See also [`nth_unchecked()`](Self::nth_unchecked). - fn nth(&self, n: usize) -> Option { - if n < self.dim().size() { - Some(self.nth_unchecked(n)) - } else { - None - } - } - /// Whether this point is `empty` or not. /// /// According to Simple Features, a Point can have zero coordinates and be considered `empty`. @@ -35,163 +29,33 @@ pub trait PointTrait { /// Only a top-level geometry can be empty. That is, when this point is contained within /// another geometry, such as a [`LineStringTrait`][crate::LineStringTrait], those points /// can never be empty, and a consumer does not need to check this method. - fn is_empty(&self) -> bool; - - /// x component of this point. - fn x(&self) -> Self::T; - - /// y component of this point. - fn y(&self) -> Self::T; - - /// Returns a tuple that contains the x/horizontal & y/vertical component of the point. - fn x_y(&self) -> (Self::T, Self::T) { - (self.x(), self.y()) - } - - /// Access the n'th (0-based) element of the CoordinateTuple. - /// May panic if n >= DIMENSION. - /// See also [`nth()`](Self::nth). - fn nth_unchecked(&self, n: usize) -> Self::T; + fn coord(&self) -> Option>; } impl PointTrait for Point { type T = T; + type CoordType<'a> = &'a Coord where Self: 'a; - fn nth_unchecked(&self, n: usize) -> Self::T { - match n { - 0 => self.x(), - 1 => self.y(), - _ => panic!("Point only supports 2 dimensions"), - } - } - - fn is_empty(&self) -> bool { - false + fn coord(&self) -> Option> { + Some(&self.0) } fn dim(&self) -> Dimensions { Dimensions::Xy } - - fn x(&self) -> Self::T { - self.0.x - } - - fn y(&self) -> Self::T { - self.0.y - } } impl PointTrait for &Point { type T = T; + type CoordType<'a> = &'a Coord where Self: 'a; - fn nth_unchecked(&self, n: usize) -> Self::T { - match n { - 0 => self.x(), - 1 => self.y(), - _ => panic!("Point only supports 2 dimensions"), - } - } - - fn is_empty(&self) -> bool { - false - } - - fn dim(&self) -> Dimensions { - Dimensions::Xy - } - - fn x(&self) -> Self::T { - self.0.x - } - - fn y(&self) -> Self::T { - self.0.y - } -} - -impl PointTrait for Coord { - type T = T; - - fn nth_unchecked(&self, n: usize) -> Self::T { - match n { - 0 => self.x(), - 1 => self.y(), - _ => panic!("Point only supports 2 dimensions"), - } - } - - fn is_empty(&self) -> bool { - false - } - - fn dim(&self) -> Dimensions { - Dimensions::Xy - } - - fn x(&self) -> Self::T { - self.x - } - - fn y(&self) -> Self::T { - self.y - } -} - -impl PointTrait for &Coord { - type T = T; - - fn nth_unchecked(&self, n: usize) -> Self::T { - match n { - 0 => self.x(), - 1 => self.y(), - _ => panic!("Point only supports 2 dimensions"), - } - } - - fn is_empty(&self) -> bool { - false + fn coord(&self) -> Option> { + Some(&self.0) } fn dim(&self) -> Dimensions { Dimensions::Xy } - - fn x(&self) -> Self::T { - self.x - } - - fn y(&self) -> Self::T { - self.y - } -} - -impl PointTrait for (T, T) { - type T = T; - - fn nth_unchecked(&self, n: usize) -> Self::T { - match n { - 0 => self.x(), - 1 => self.y(), - _ => panic!("(T, T) only supports 2 dimensions"), - } - } - - fn is_empty(&self) -> bool { - false - } - - fn dim(&self) -> Dimensions { - Dimensions::Xy - } - - fn x(&self) -> Self::T { - self.0 - } - - fn y(&self) -> Self::T { - self.1 - } } /// An empty struct that implements [PointTrait]. @@ -202,24 +66,13 @@ pub struct UnimplementedPoint(PhantomData); impl PointTrait for UnimplementedPoint { type T = T; + type CoordType<'a> = UnimplementedCoord where Self: 'a; - fn is_empty(&self) -> bool { + fn coord(&self) -> Option> { unimplemented!() } fn dim(&self) -> Dimensions { unimplemented!() } - - fn nth_unchecked(&self, _n: usize) -> Self::T { - unimplemented!() - } - - fn x(&self) -> Self::T { - unimplemented!() - } - - fn y(&self) -> Self::T { - unimplemented!() - } } diff --git a/geo-traits/src/polygon.rs b/geo-traits/src/polygon.rs index 99dcc53af5..18669e0083 100644 --- a/geo-traits/src/polygon.rs +++ b/geo-traits/src/polygon.rs @@ -63,7 +63,7 @@ impl PolygonTrait for Polygon { fn exterior(&self) -> Option> { let ext_ring = Polygon::exterior(self); - if ext_ring.num_points() == 0 { + if LineStringTrait::num_coords(&ext_ring) == 0 { None } else { Some(ext_ring) @@ -90,7 +90,7 @@ impl<'a, T: CoordNum> PolygonTrait for &'a Polygon { fn exterior(&self) -> Option> { let ext_ring = Polygon::exterior(self); - if ext_ring.num_points() == 0 { + if LineStringTrait::num_coords(&ext_ring) == 0 { None } else { Some(ext_ring) diff --git a/geo-traits/src/rect.rs b/geo-traits/src/rect.rs index a96d25ab7c..a0b60832f1 100644 --- a/geo-traits/src/rect.rs +++ b/geo-traits/src/rect.rs @@ -2,18 +2,18 @@ use std::marker::PhantomData; use geo_types::{Coord, CoordNum, Rect}; -use crate::{Dimensions, PointTrait, UnimplementedPoint}; +use crate::{CoordTrait, Dimensions, UnimplementedCoord}; /// A trait for accessing data from a generic Rect. /// /// A Rect is an _axis-aligned_ bounded 2D rectangle whose area is -/// defined by minimum and maximum [`Point`s][PointTrait]. +/// defined by minimum and maximum [`Point`s][CoordTrait]. pub trait RectTrait { /// The coordinate type of this geometry type T: CoordNum; - /// The type of each underlying coordinate, which implements [PointTrait] - type PointType<'a>: 'a + PointTrait + /// The type of each underlying coordinate, which implements [CoordTrait] + type CoordType<'a>: 'a + CoordTrait where Self: 'a; @@ -21,42 +21,42 @@ pub trait RectTrait { fn dim(&self) -> Dimensions; /// The minimum coordinate of this Rect - fn min(&self) -> Self::PointType<'_>; + fn min(&self) -> Self::CoordType<'_>; /// The maximum coordinate of this Rect - fn max(&self) -> Self::PointType<'_>; + fn max(&self) -> Self::CoordType<'_>; } impl<'a, T: CoordNum + 'a> RectTrait for Rect { type T = T; - type PointType<'b> = Coord where Self: 'b; + type CoordType<'b> = Coord where Self: 'b; fn dim(&self) -> Dimensions { Dimensions::Xy } - fn min(&self) -> Self::PointType<'_> { + fn min(&self) -> Self::CoordType<'_> { Rect::min(*self) } - fn max(&self) -> Self::PointType<'_> { + fn max(&self) -> Self::CoordType<'_> { Rect::max(*self) } } impl<'a, T: CoordNum + 'a> RectTrait for &'a Rect { type T = T; - type PointType<'b> = Coord where Self: 'b; + type CoordType<'b> = Coord where Self: 'b; fn dim(&self) -> Dimensions { Dimensions::Xy } - fn min(&self) -> Self::PointType<'_> { + fn min(&self) -> Self::CoordType<'_> { Rect::min(**self) } - fn max(&self) -> Self::PointType<'_> { + fn max(&self) -> Self::CoordType<'_> { Rect::max(**self) } } @@ -69,17 +69,17 @@ pub struct UnimplementedRect(PhantomData); impl RectTrait for UnimplementedRect { type T = T; - type PointType<'a> = UnimplementedPoint where Self: 'a; + type CoordType<'a> = UnimplementedCoord where Self: 'a; fn dim(&self) -> Dimensions { unimplemented!() } - fn min(&self) -> Self::PointType<'_> { + fn min(&self) -> Self::CoordType<'_> { unimplemented!() } - fn max(&self) -> Self::PointType<'_> { + fn max(&self) -> Self::CoordType<'_> { unimplemented!() } } diff --git a/geo-traits/src/triangle.rs b/geo-traits/src/triangle.rs index 6322e19d66..8934e4e3f8 100644 --- a/geo-traits/src/triangle.rs +++ b/geo-traits/src/triangle.rs @@ -1,78 +1,78 @@ use std::marker::PhantomData; -use crate::{Dimensions, PointTrait, UnimplementedPoint}; +use crate::{CoordTrait, Dimensions, UnimplementedCoord}; use geo_types::{Coord, CoordNum, Triangle}; /// A trait for accessing data from a generic Triangle. /// -/// A triangle is a bounded area whose three vertices are defined by [points][PointTrait]. +/// A triangle is a bounded area whose three vertices are defined by [coordinates][CoordTrait]. /// /// Refer to [geo_types::Triangle] for information about semantics and validity. pub trait TriangleTrait: Sized { /// The coordinate type of this geometry type T: CoordNum; - /// The type of each underlying coordinate, which implements [PointTrait] - type PointType<'a>: 'a + PointTrait + /// The type of each underlying coordinate, which implements [CoordTrait] + type CoordType<'a>: 'a + CoordTrait where Self: 'a; /// The dimension of this geometry fn dim(&self) -> Dimensions; - /// Access the first point in this Triangle - fn first(&self) -> Self::PointType<'_>; + /// Access the first coordinate in this Triangle + fn first(&self) -> Self::CoordType<'_>; - /// Access the second point in this Triangle - fn second(&self) -> Self::PointType<'_>; + /// Access the second coordinate in this Triangle + fn second(&self) -> Self::CoordType<'_>; - /// Access the third point in this Triangle - fn third(&self) -> Self::PointType<'_>; + /// Access the third coordinate in this Triangle + fn third(&self) -> Self::CoordType<'_>; - /// Access the three underlying points - fn points(&self) -> [Self::PointType<'_>; 3] { + /// Access the three underlying coordinates + fn coords(&self) -> [Self::CoordType<'_>; 3] { [self.first(), self.second(), self.third()] } } impl TriangleTrait for Triangle { type T = T; - type PointType<'a> = &'a Coord where Self: 'a; + type CoordType<'a> = &'a Coord where Self: 'a; fn dim(&self) -> Dimensions { Dimensions::Xy } - fn first(&self) -> Self::PointType<'_> { + fn first(&self) -> Self::CoordType<'_> { &self.0 } - fn second(&self) -> Self::PointType<'_> { + fn second(&self) -> Self::CoordType<'_> { &self.0 } - fn third(&self) -> Self::PointType<'_> { + fn third(&self) -> Self::CoordType<'_> { &self.0 } } impl<'a, T: CoordNum> TriangleTrait for &'a Triangle { type T = T; - type PointType<'b> = &'a Coord where Self: 'b; + type CoordType<'b> = &'a Coord where Self: 'b; fn dim(&self) -> Dimensions { Dimensions::Xy } - fn first(&self) -> Self::PointType<'_> { + fn first(&self) -> Self::CoordType<'_> { &self.0 } - fn second(&self) -> Self::PointType<'_> { + fn second(&self) -> Self::CoordType<'_> { &self.0 } - fn third(&self) -> Self::PointType<'_> { + fn third(&self) -> Self::CoordType<'_> { &self.0 } } @@ -85,21 +85,21 @@ pub struct UnimplementedTriangle(PhantomData); impl TriangleTrait for UnimplementedTriangle { type T = T; - type PointType<'a> = UnimplementedPoint where Self: 'a; + type CoordType<'a> = UnimplementedCoord where Self: 'a; fn dim(&self) -> Dimensions { unimplemented!() } - fn first(&self) -> Self::PointType<'_> { + fn first(&self) -> Self::CoordType<'_> { unimplemented!() } - fn second(&self) -> Self::PointType<'_> { + fn second(&self) -> Self::CoordType<'_> { unimplemented!() } - fn third(&self) -> Self::PointType<'_> { + fn third(&self) -> Self::CoordType<'_> { unimplemented!() } } From 711dfacd900e39f3201cfd79d3535eead3787298 Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Thu, 24 Oct 2024 20:01:46 -0400 Subject: [PATCH 33/33] Update geo-traits/src/coord.rs Co-authored-by: Corey Farwell --- geo-traits/src/coord.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geo-traits/src/coord.rs b/geo-traits/src/coord.rs index c70b708589..053f8874e3 100644 --- a/geo-traits/src/coord.rs +++ b/geo-traits/src/coord.rs @@ -15,7 +15,7 @@ pub trait CoordTrait { fn dim(&self) -> Dimensions; /// Access the n'th (0-based) element of the CoordinateTuple. - /// Returns NaN if `n >= DIMENSION`. + /// Returns `None` if `n >= DIMENSION`. /// See also [`nth_unchecked()`](Self::nth_unchecked). fn nth(&self, n: usize) -> Option { if n < self.dim().size() {