-
Notifications
You must be signed in to change notification settings - Fork 228
feat(geo-traits): Provide basic structs implementing geo-traits' traits #1441
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
base: main
Are you sure you want to change the base?
feat(geo-traits): Provide basic structs implementing geo-traits' traits #1441
Conversation
kylebarron
left a comment
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.
Thanks for the PR! Some quick notes
geo-traits/src/structs/coord.rs
Outdated
| let y = coord.y(); | ||
|
|
||
| match coord.dim() { | ||
| Dimensions::Xyzm | Dimensions::Unknown(_) => Self { |
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 know how people intend to use Dimensions::Unknown; I usually pass them into XY if 2 dimensions; into XYZ if 3 dimensions; into XYZM if 4 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.
Thanks, I'll follow the convention. How do you handle other irregular numbers? Should this function return Option<Self> to choose None for such cases?
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 know... I find it really annoying that there is a Dimensions::Unknown at all, but then again I only work with xy/xyz/xym/xyzm data
geo-traits/src/structs/geometry.rs
Outdated
| } | ||
|
|
||
| /// Create a new Geometry from an objects implementing [GeometryTrait]. The | ||
| /// result is `None` if the geometry is `Line`, `Rect`, or `Triangle`. |
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 think either we could convert Line to LineString, Rect to Polygon, Triangle to Polygon, or potentially it would make sense to also have those concepts here
| /// | ||
| /// To handle empty input iterators, consider calling `unwrap_or` on the result and defaulting | ||
| /// to an [empty][Self::empty] geometry with specified dimension. | ||
| pub fn from_coords(coords: impl IntoIterator<Item = impl CoordTrait<T = T>>) -> Option<Self> { |
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.
This doesn't need to be impl IntoIterator; it can just be impl Iterator, right?
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 think you are right. I couldn't make it due to some compiler error, but I'll try again...
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.
Sorry, probably I too was confused, but probably you meant we want .iter() rather than .into_iter() so that we don't need to consume the object, right? If so, it's not about IntoIterator vs Iterator, and currently it should already be possible because &Coord<T> implements CoordTrait.
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.
Yes, we don't need to consume the object. But taking in impl IntoIterator means that the input needs to be able to be consumed into an iterator. If we take in an impl Iterator instead, then the input doesn't need to be consumed
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.
Sorry, I still don't understand your point. For example, if we have Vec<(f64, f64)>, I think we typically pass &[(f64, 64)] to impl IntoIterator argument because the slice implements IntoIterator. I think it's fine to have the slice consumed because we still hold the original Vec, no? Do you mean changing it to impl Iterator might save us from accidentally passing Vec itself...?
This might be because I'm not familiar with designing such interface. Do you have some good example of a signature that takes Iterator instead of IntoIterator?
geo-traits/src/structs/linestring.rs
Outdated
|
|
||
| /// Create a new LineString from an objects implementing [LineStringTrait]. | ||
| pub fn from_linestring(linestring: &impl LineStringTrait<T = T>) -> Self { | ||
| Self::from_coords(linestring.coords()).unwrap() |
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 think this unwrap is ok, because empty linestrings are valid
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.
Thanks for catching!
| .line_strings() | ||
| .map(|l| LineString::from_linestring(&l)) | ||
| .collect::<Vec<_>>(); | ||
| let dim = line_strings[0].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.
ditto, we can't assume input objects are non-empty
yutannihilation
left a comment
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.
Thanks for reviewing! I'll address the comments.
| /// | ||
| /// To handle empty input iterators, consider calling `unwrap_or` on the result and defaulting | ||
| /// to an [empty][Self::empty] geometry with specified dimension. | ||
| pub fn from_coords(coords: impl IntoIterator<Item = impl CoordTrait<T = T>>) -> Option<Self> { |
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 think you are right. I couldn't make it due to some compiler error, but I'll try again...
geo-traits/src/structs/linestring.rs
Outdated
|
|
||
| /// Create a new LineString from an objects implementing [LineStringTrait]. | ||
| pub fn from_linestring(linestring: &impl LineStringTrait<T = T>) -> Self { | ||
| Self::from_coords(linestring.coords()).unwrap() |
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.
Thanks for catching!
geo-traits/src/structs/coord.rs
Outdated
| let y = coord.y(); | ||
|
|
||
| match coord.dim() { | ||
| Dimensions::Xyzm | Dimensions::Unknown(_) => Self { |
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.
Thanks, I'll follow the convention. How do you handle other irregular numbers? Should this function return Option<Self> to choose None for such cases?
|
I think the main question here is what the scope of Another possible worry is that if we add more structs to the Another option is to create and publish a separate crate with just these structs. That doesn't expand the maintenance burden of crates in the In my own work I don't find it that burdensome to use the I'd like to hear from other maintainers too |
CHANGES.mdif knowledge of this change could be valuable to users.This pull request adds structs like
Coord,Point,LineString, etc to geo-traits. These structs implement the corresponding trait (i.e.CoordTrait,PointTrait,LineStringTrait, etc) and the conversion from the objects implementing these traits so that we can use these structs to store the geometry data.The code is mostly derived from the wkt crate. I don't know how to add attribution properly, sorry..., but I'm not sure if I can finish this anyway. The main purpose of this pull request is to sho what the implementation would be.
The main differences from wkt are:
Displayand conversion from text.LineString::from_linestring(linestring: impl LineStringTrait<T = T>))CoordandPointFromconversions forCoordandPoint