-
Notifications
You must be signed in to change notification settings - Fork 230
Add geo-traits crate #1157
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
Changes from 39 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,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<Self::T> { | ||
| 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; | ||
|
Member
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. When I first read this, I thought this would behave similarly to My first though was, what if we had a naming convention like this: fn nth_checked(n) -> Option<T> {}
fn nth(n) -> T {} // Panics
unsafe fn nth_unchecked(n) -> TBut that may psychologically push people to use the panic'ing version. I don't know what the right answer is, just wanted to call out that I was surprised when implementing
Member
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. Another option 🤷🏻 fn nth(n) -> Option<T> {}
fn nth_or_panic(n) -> T {} // Panics
unsafe fn nth_unchecked(n) -> T
Member
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. But we also definitely don't need to have an
Member
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. That's nice. 👏 - coord.nth_unchecked(3);
+ coord.nth(3).unwrap();We could also just leave out the
Member
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. Although I didn't find it in the stdlib, apparently there's quite a bit of precedent for
Member
Author
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. Open to suggestions here. I suppose it's worthwhile having a variant that is actually unsafe (e.g. doesn't even do the bounds check), for situations where you know you're in bounds (like the iterator) |
||
| } | ||
|
|
||
| impl<T: CoordNum> CoordTrait for Coord<T> { | ||
| 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<T: CoordNum> CoordTrait for &Coord<T> { | ||
| 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<T: CoordNum> 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<T: CoordNum>(PhantomData<T>); | ||
|
|
||
| impl<T: CoordNum> CoordTrait for UnimplementedCoord<T> { | ||
| 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!() | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| /// The logical dimension of the geometry. | ||
| /// | ||
| /// | ||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
| pub enum Dimensions { | ||
| /// 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 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::Unknown(val) => *val, | ||
| } | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.