Skip to content

Commit

Permalink
Merge #1011
Browse files Browse the repository at this point in the history
1011: Initial geo-traits implementation r=frewsxcv a=kylebarron

- [x] I agree to follow the project's [code of conduct](https://github.com/georust/geo/blob/main/CODE_OF_CONDUCT.md).
- [ ] I added an entry to `CHANGES.md` if knowledge of this change could be valuable to users.
---

As discussed on the discord, in https://github.com/georust/geo/discussions/838, and originally in #67, this is an initial bare-bones implementation of geometry access traits for discussion. As `@frewsxcv` suggested, for now this is a separate crate in the workspace to let us iterate on some ideas.

### Future work

#### Minimize cloning in the geo-types implementation

I got lost in lifetime errors so to get things to compile I added cloning to the geo-types implementations. I.e. for `MultiPoint` each point is cloned when accessed.

Co-authored-by: Kyle Barron <kylebarron2@gmail.com>
  • Loading branch information
bors[bot] and kylebarron committed Jun 21, 2023
2 parents 138e4b3 + 10cdce0 commit 1b9557f
Show file tree
Hide file tree
Showing 12 changed files with 598 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["geo", "geo-types", "geo-postgis", "geo-test-fixtures", "jts-test-runner", "geo-bool-ops-benches"]
members = ["geo", "geo-types", "geo-traits", "geo-postgis", "geo-test-fixtures", "jts-test-runner", "geo-bool-ops-benches"]

[patch.crates-io]

Expand Down
19 changes: 19 additions & 0 deletions geo-traits/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[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"

[features]

[dependencies]
geo-types = "0.7.9"

[dev-dependencies]
approx = ">= 0.4.0, < 0.6.0"
64 changes: 64 additions & 0 deletions geo-traits/src/coord.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use geo_types::{Coord, CoordNum, Point};

pub trait CoordTrait: Send + Sync {
type T: CoordNum + Send + Sync;

/// 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<T: CoordNum + Send + Sync> CoordTrait for Point<T> {
type T = T;

fn x(&self) -> T {
self.0.x
}

fn y(&self) -> T {
self.0.y
}
}

impl<T: CoordNum + Send + Sync> CoordTrait for &Point<T> {
type T = T;

fn x(&self) -> T {
self.0.x
}

fn y(&self) -> T {
self.0.y
}
}

impl<T: CoordNum + Send + Sync> CoordTrait for Coord<T> {
type T = T;

fn x(&self) -> T {
self.x
}

fn y(&self) -> T {
self.y
}
}

impl<T: CoordNum + Send + Sync> CoordTrait for &Coord<T> {
type T = T;

fn x(&self) -> T {
self.x
}

fn y(&self) -> T {
self.y
}
}
87 changes: 87 additions & 0 deletions geo-traits/src/geometry.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use geo_types::{
CoordNum, Geometry, GeometryCollection, LineString, MultiLineString, MultiPoint, MultiPolygon,
Point, Polygon,
};

use super::{
GeometryCollectionTrait, LineStringTrait, MultiLineStringTrait, MultiPointTrait,
MultiPolygonTrait, PointTrait, PolygonTrait,
};

#[allow(clippy::type_complexity)]
pub trait GeometryTrait<'a>: Send + Sync {
type Point: 'a + PointTrait;
type LineString: 'a + LineStringTrait<'a>;
type Polygon: 'a + PolygonTrait<'a>;
type MultiPoint: 'a + MultiPointTrait<'a>;
type MultiLineString: 'a + MultiLineStringTrait<'a>;
type MultiPolygon: 'a + MultiPolygonTrait<'a>;
type GeometryCollection: 'a + GeometryCollectionTrait<'a>;

fn as_type(
&'a self,
) -> GeometryType<
'a,
Self::Point,
Self::LineString,
Self::Polygon,
Self::MultiPoint,
Self::MultiLineString,
Self::MultiPolygon,
Self::GeometryCollection,
>;
}

#[derive(Debug)]
pub enum GeometryType<'a, P, L, Y, MP, ML, MY, GC>
where
P: 'a + PointTrait,
L: 'a + LineStringTrait<'a>,
Y: 'a + PolygonTrait<'a>,
MP: 'a + MultiPointTrait<'a>,
ML: 'a + MultiLineStringTrait<'a>,
MY: 'a + MultiPolygonTrait<'a>,
GC: 'a + GeometryCollectionTrait<'a>,
{
Point(&'a P),
LineString(&'a L),
Polygon(&'a Y),
MultiPoint(&'a MP),
MultiLineString(&'a ML),
MultiPolygon(&'a MY),
GeometryCollection(&'a GC),
}

impl<'a, T: CoordNum + Send + Sync + 'a> GeometryTrait<'a> for Geometry<T> {
type Point = Point<T>;
type LineString = LineString<T>;
type Polygon = Polygon<T>;
type MultiPoint = MultiPoint<T>;
type MultiLineString = MultiLineString<T>;
type MultiPolygon = MultiPolygon<T>;
type GeometryCollection = GeometryCollection<T>;

fn as_type(
&'a self,
) -> GeometryType<
'a,
Point<T>,
LineString<T>,
Polygon<T>,
MultiPoint<T>,
MultiLineString<T>,
MultiPolygon<T>,
GeometryCollection<T>,
> {
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),
_ => todo!(),
}
}
}
53 changes: 53 additions & 0 deletions geo-traits/src/geometry_collection.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use super::GeometryTrait;
use geo_types::{CoordNum, Geometry, GeometryCollection};
use std::iter::Cloned;
use std::slice::Iter;

pub trait GeometryCollectionTrait<'a>: Send + Sync {
type ItemType: 'a + GeometryTrait<'a>;
type Iter: ExactSizeIterator<Item = Self::ItemType>;

/// An iterator over the geometries in this GeometryCollection
fn geometries(&'a self) -> Self::Iter;

/// The number of geometries in this GeometryCollection
fn num_geometries(&'a self) -> usize;

/// Access to a specified geometry in this GeometryCollection
/// Will return None if the provided index is out of bounds
fn geometry(&'a self, i: usize) -> Option<Self::ItemType>;
}

impl<'a, T: CoordNum + Send + Sync + 'a> GeometryCollectionTrait<'a> for GeometryCollection<T> {
type ItemType = Geometry<T>;
type Iter = Cloned<Iter<'a, Self::ItemType>>;

fn geometries(&'a self) -> Self::Iter {
self.0.iter().cloned()
}

fn num_geometries(&'a self) -> usize {
self.0.len()
}

fn geometry(&'a self, i: usize) -> Option<Self::ItemType> {
self.0.get(i).cloned()
}
}

impl<'a, T: CoordNum + Send + Sync + 'a> GeometryCollectionTrait<'a> for &GeometryCollection<T> {
type ItemType = Geometry<T>;
type Iter = Cloned<Iter<'a, Self::ItemType>>;

fn geometries(&'a self) -> Self::Iter {
self.0.iter().cloned()
}

fn num_geometries(&'a self) -> usize {
self.0.len()
}

fn geometry(&'a self, i: usize) -> Option<Self::ItemType> {
self.0.get(i).cloned()
}
}
19 changes: 19 additions & 0 deletions geo-traits/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
pub use coord::CoordTrait;
pub use geometry::{GeometryTrait, GeometryType};
pub use geometry_collection::GeometryCollectionTrait;
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;

mod coord;
mod geometry;
mod geometry_collection;
mod line_string;
mod multi_line_string;
mod multi_point;
mod multi_polygon;
mod point;
mod polygon;
54 changes: 54 additions & 0 deletions geo-traits/src/line_string.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use geo_types::{Coord, CoordNum, LineString};

use super::CoordTrait;
use std::iter::Cloned;
use std::slice::Iter;

pub trait LineStringTrait<'a>: Send + Sync {
type ItemType: 'a + CoordTrait;
type Iter: ExactSizeIterator<Item = Self::ItemType>;

/// An iterator over the coords in this LineString
fn coords(&'a self) -> Self::Iter;

/// The number of coords in this LineString
fn num_coords(&'a self) -> usize;

/// Access to a specified point in this LineString
/// Will return None if the provided index is out of bounds
fn coord(&'a self, i: usize) -> Option<Self::ItemType>;
}

impl<'a, T: CoordNum + Send + Sync + 'a> LineStringTrait<'a> for LineString<T> {
type ItemType = Coord<T>;
type Iter = Cloned<Iter<'a, Self::ItemType>>;

fn coords(&'a self) -> Self::Iter {
self.0.iter().cloned()
}

fn num_coords(&self) -> usize {
self.0.len()
}

fn coord(&'a self, i: usize) -> Option<Self::ItemType> {
self.0.get(i).cloned()
}
}

impl<'a, T: CoordNum + Send + Sync + 'a> LineStringTrait<'a> for &LineString<T> {
type ItemType = Coord<T>;
type Iter = Cloned<Iter<'a, Self::ItemType>>;

fn coords(&'a self) -> Self::Iter {
self.0.iter().cloned()
}

fn num_coords(&self) -> usize {
self.0.len()
}

fn coord(&'a self, i: usize) -> Option<Self::ItemType> {
self.0.get(i).cloned()
}
}
53 changes: 53 additions & 0 deletions geo-traits/src/multi_line_string.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use super::line_string::LineStringTrait;
use geo_types::{CoordNum, LineString, MultiLineString};
use std::iter::Cloned;
use std::slice::Iter;

pub trait MultiLineStringTrait<'a>: Send + Sync {
type ItemType: 'a + LineStringTrait<'a>;
type Iter: ExactSizeIterator<Item = Self::ItemType>;

/// An iterator over the LineStrings in this MultiLineString
fn lines(&'a self) -> Self::Iter;

/// The number of lines in this MultiLineString
fn num_lines(&'a self) -> usize;

/// Access to a specified line in this MultiLineString
/// Will return None if the provided index is out of bounds
fn line(&'a self, i: usize) -> Option<Self::ItemType>;
}

impl<'a, T: CoordNum + Send + Sync + 'a> MultiLineStringTrait<'a> for MultiLineString<T> {
type ItemType = LineString<T>;
type Iter = Cloned<Iter<'a, Self::ItemType>>;

fn lines(&'a self) -> Self::Iter {
self.0.iter().cloned()
}

fn num_lines(&'a self) -> usize {
self.0.len()
}

fn line(&'a self, i: usize) -> Option<Self::ItemType> {
self.0.get(i).cloned()
}
}

impl<'a, T: CoordNum + Send + Sync + 'a> MultiLineStringTrait<'a> for &MultiLineString<T> {
type ItemType = LineString<T>;
type Iter = Cloned<Iter<'a, Self::ItemType>>;

fn lines(&'a self) -> Self::Iter {
self.0.iter().cloned()
}

fn num_lines(&'a self) -> usize {
self.0.len()
}

fn line(&'a self, i: usize) -> Option<Self::ItemType> {
self.0.get(i).cloned()
}
}

0 comments on commit 1b9557f

Please sign in to comment.