-
Notifications
You must be signed in to change notification settings - Fork 202
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add geo-traits crate #1157
Add geo-traits crate #1157
Changes from 11 commits
e337d8a
7f68df2
34ed5be
d57995e
7308df3
ee04201
ad48ee1
4261836
449b39f
f54fffc
db08c55
7ecdb7e
03f6615
31435e8
1d30066
ab0bf7b
33c1ef9
6363ad8
9421e05
9552705
3725844
7a2effd
8dcbe50
6889cae
de7ca8a
0fb5ab8
58117ce
6b697dd
2eb3b03
1f68cc3
b1364ef
d49873b
7c0e90f
09de278
8418780
4a9b3cc
ba9bf98
4764343
2b77691
711dfac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
[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] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/// The logical dimension of the geometry. | ||
/// | ||
/// | ||
#[allow(clippy::upper_case_acronyms)] | ||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
pub enum Dimension { | ||
/// A two-dimensional geometry with X and Y values | ||
XY, | ||
kylebarron marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/// 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, | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I personally would appreciate There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the |
||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,191 @@ | ||||||||||||||||||||
use geo_types::{ | ||||||||||||||||||||
CoordNum, Geometry, GeometryCollection, LineString, MultiLineString, MultiPoint, MultiPolygon, | ||||||||||||||||||||
Point, Polygon, Rect, | ||||||||||||||||||||
}; | ||||||||||||||||||||
|
||||||||||||||||||||
use crate::{ | ||||||||||||||||||||
Dimension, GeometryCollectionTrait, LineStringTrait, MultiLineStringTrait, MultiPointTrait, | ||||||||||||||||||||
MultiPolygonTrait, PointTrait, PolygonTrait, RectTrait, | ||||||||||||||||||||
}; | ||||||||||||||||||||
|
||||||||||||||||||||
/// 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<T = Self::T> | ||||||||||||||||||||
where | ||||||||||||||||||||
Self: 'a; | ||||||||||||||||||||
|
||||||||||||||||||||
/// The type of each underlying LineString, which implements [LineStringTrait] | ||||||||||||||||||||
type LineString<'a>: 'a + LineStringTrait<T = Self::T> | ||||||||||||||||||||
where | ||||||||||||||||||||
Self: 'a; | ||||||||||||||||||||
|
||||||||||||||||||||
/// The type of each underlying Polygon, which implements [PolygonTrait] | ||||||||||||||||||||
type Polygon<'a>: 'a + PolygonTrait<T = Self::T> | ||||||||||||||||||||
where | ||||||||||||||||||||
Self: 'a; | ||||||||||||||||||||
|
||||||||||||||||||||
/// The type of each underlying MultiPoint, which implements [MultiPointTrait] | ||||||||||||||||||||
type MultiPoint<'a>: 'a + MultiPointTrait<T = Self::T> | ||||||||||||||||||||
where | ||||||||||||||||||||
Self: 'a; | ||||||||||||||||||||
|
||||||||||||||||||||
/// The type of each underlying MultiLineString, which implements [MultiLineStringTrait] | ||||||||||||||||||||
type MultiLineString<'a>: 'a + MultiLineStringTrait<T = Self::T> | ||||||||||||||||||||
where | ||||||||||||||||||||
Self: 'a; | ||||||||||||||||||||
|
||||||||||||||||||||
/// The type of each underlying MultiPolygon, which implements [MultiPolygonTrait] | ||||||||||||||||||||
type MultiPolygon<'a>: 'a + MultiPolygonTrait<T = Self::T> | ||||||||||||||||||||
where | ||||||||||||||||||||
Self: 'a; | ||||||||||||||||||||
|
||||||||||||||||||||
/// The type of each underlying GeometryCollection, which implements [GeometryCollectionTrait] | ||||||||||||||||||||
type GeometryCollection<'a>: 'a + GeometryCollectionTrait<T = Self::T> | ||||||||||||||||||||
where | ||||||||||||||||||||
Self: 'a; | ||||||||||||||||||||
|
||||||||||||||||||||
/// The type of each underlying Rect, which implements [RectTrait] | ||||||||||||||||||||
type Rect<'a>: 'a + RectTrait<T = Self::T> | ||||||||||||||||||||
where | ||||||||||||||||||||
Self: 'a; | ||||||||||||||||||||
|
||||||||||||||||||||
/// The dimension of this geometry | ||||||||||||||||||||
fn dim(&self) -> Dimension; | ||||||||||||||||||||
|
||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||
/// Cast this geometry to a [`GeometryType`] enum, which allows for downcasting to a specific | ||||||||||||||||||||
/// type | ||||||||||||||||||||
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, | ||||||||||||||||||||
{ | ||||||||||||||||||||
/// 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), | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
impl<'a, T: CoordNum + 'a> GeometryTrait for Geometry<T> { | ||||||||||||||||||||
type T = T; | ||||||||||||||||||||
type Point<'b> = Point<Self::T> where Self: 'b; | ||||||||||||||||||||
type LineString<'b> = LineString<Self::T> where Self: 'b; | ||||||||||||||||||||
type Polygon<'b> = Polygon<Self::T> where Self: 'b; | ||||||||||||||||||||
type MultiPoint<'b> = MultiPoint<Self::T> where Self: 'b; | ||||||||||||||||||||
type MultiLineString<'b> = MultiLineString<Self::T> where Self: 'b; | ||||||||||||||||||||
type MultiPolygon<'b> = MultiPolygon<Self::T> where Self: 'b; | ||||||||||||||||||||
type GeometryCollection<'b> = GeometryCollection<Self::T> where Self: 'b; | ||||||||||||||||||||
type Rect<'b> = Rect<Self::T> where Self: 'b; | ||||||||||||||||||||
|
||||||||||||||||||||
fn dim(&self) -> Dimension { | ||||||||||||||||||||
Dimension::XY | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
fn as_type( | ||||||||||||||||||||
&self, | ||||||||||||||||||||
) -> GeometryType< | ||||||||||||||||||||
'_, | ||||||||||||||||||||
Point<T>, | ||||||||||||||||||||
LineString<T>, | ||||||||||||||||||||
Polygon<T>, | ||||||||||||||||||||
MultiPoint<T>, | ||||||||||||||||||||
MultiLineString<T>, | ||||||||||||||||||||
MultiPolygon<T>, | ||||||||||||||||||||
GeometryCollection<T>, | ||||||||||||||||||||
Rect<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), | ||||||||||||||||||||
Geometry::Rect(p) => GeometryType::Rect(p), | ||||||||||||||||||||
_ => todo!(), | ||||||||||||||||||||
kylebarron marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
impl<'a, T: CoordNum + 'a> GeometryTrait for &'a Geometry<T> { | ||||||||||||||||||||
type T = T; | ||||||||||||||||||||
type Point<'b> = Point<Self::T> where Self: 'b; | ||||||||||||||||||||
type LineString<'b> = LineString<Self::T> where Self: 'b; | ||||||||||||||||||||
type Polygon<'b> = Polygon<Self::T> where Self: 'b; | ||||||||||||||||||||
type MultiPoint<'b> = MultiPoint<Self::T> where Self: 'b; | ||||||||||||||||||||
type MultiLineString<'b> = MultiLineString<Self::T> where Self: 'b; | ||||||||||||||||||||
type MultiPolygon<'b> = MultiPolygon<Self::T> where Self: 'b; | ||||||||||||||||||||
type GeometryCollection<'b> = GeometryCollection<Self::T> where Self: 'b; | ||||||||||||||||||||
type Rect<'b> = Rect<Self::T> where Self: 'b; | ||||||||||||||||||||
|
||||||||||||||||||||
fn dim(&self) -> Dimension { | ||||||||||||||||||||
Dimension::XY | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
fn as_type( | ||||||||||||||||||||
&self, | ||||||||||||||||||||
) -> GeometryType< | ||||||||||||||||||||
'_, | ||||||||||||||||||||
Point<T>, | ||||||||||||||||||||
LineString<T>, | ||||||||||||||||||||
Polygon<T>, | ||||||||||||||||||||
MultiPoint<T>, | ||||||||||||||||||||
MultiLineString<T>, | ||||||||||||||||||||
MultiPolygon<T>, | ||||||||||||||||||||
GeometryCollection<T>, | ||||||||||||||||||||
Rect<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), | ||||||||||||||||||||
Geometry::Rect(p) => GeometryType::Rect(p), | ||||||||||||||||||||
_ => todo!(), | ||||||||||||||||||||
kylebarron marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
use crate::{Dimension, GeometryCollectionIterator, GeometryTrait}; | ||
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<T = Self::T> | ||
where | ||
Self: 'a; | ||
|
||
/// 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> { | ||
GeometryCollectionIterator::new(self, 0, self.num_geometries()) | ||
} | ||
|
||
/// The number of geometries in this GeometryCollection | ||
fn num_geometries(&self) -> usize; | ||
Comment on lines
+27
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm more of an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I feel like I don't commonly see Even (@JosiahParry perfect time for us to pull out that "bikeshedding" definition 😆) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think of |
||
|
||
/// 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<Self::ItemType<'_>> { | ||
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<T: CoordNum> GeometryCollectionTrait for GeometryCollection<T> { | ||
type T = T; | ||
type ItemType<'a> = &'a Geometry<Self::T> | ||
where | ||
Self: 'a; | ||
|
||
fn dim(&self) -> Dimension { | ||
Dimension::XY | ||
} | ||
|
||
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<T> { | ||
type T = T; | ||
type ItemType<'b> = &'a Geometry<Self::T> where | ||
Self: 'b; | ||
|
||
fn dim(&self) -> Dimension { | ||
Dimension::XY | ||
} | ||
|
||
fn num_geometries(&self) -> usize { | ||
self.0.len() | ||
} | ||
|
||
unsafe fn geometry_unchecked(&self, i: usize) -> Self::ItemType<'_> { | ||
self.0.get_unchecked(i) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm willing to walk this back.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. X is a single dimension Y is a single dimension. There wouldn't be support for X or Y only only XY at minimum which would be two dimensions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't feel that strongly about this, but to me "Dimensions" means "you have multiple geometries, what is the dimension of each of them" and "Dimension" means "you have one geometry, what's its dimension?"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to throw more fuel on the fire 😆:
I wonder if there's anything we can do to avoid confusion with https://github.com/georust/geo/blob/main/geo/src/algorithm/dimensions.rs#L25
Calling it something like
DimensionalOrdering
might be clearer, but it's such a mouthful!It does make me realize that
YX
wouldn't be totally out of place in this enum, though I'm not sure if there's much utility in it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately
Dimension
is a very overloaded term.HasDimensions
refers to the topological dimension, while theDimensions
here refers to what each topological dimension represents?I don't think
YX
would make sense. Instead you should useXY
with a CRS that defines the two dimensions asY, X
, like EPSG:4326, which defines the coordinate ordering as latitude, then longitude.