-
Notifications
You must be signed in to change notification settings - Fork 25
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
Implement geo-traits for writing to WKT & perf improvement #124
base: kyle/geo-traits
Are you sure you want to change the base?
Conversation
All existing tests pass; just a question of whether |
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.
In general, can you address the todo!
before marking a PR as ready for review? I don't want to accidentally miss one and then merge code that willfully explodes on the happy path. It seems like a good way to get users to not trust you.
Well I consider the Is there a better way to signify this? |
Draft PRs are a great way to get line by line feedback and signify "please don't merge this" as is. I'll also often leave comments on my own PR with specific questions and relevant context at the spot I'm seeking help. |
Another alternative / complementary approach is to deny |
Ok! I've found different expectations in different communities on github of whether draft means "don't look at this yet" or "I'm soliciting feedback on things, but it's not yet ready for merge" |
Here the remaining questions are:
I should be able to fix the rect and triangle issues separately |
Other questions:
|
let max_coord = rect.max(); | ||
|
||
// Note: Even if the rect has more than 2 dimensions, we omit the other dimensions when | ||
// converting to a Polygon. |
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.
Why do we do this for Rect's?
Instead can it look more like the triangle impl which avoids this loss of dims and heap allocation?
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.
Triangle
and Line
store all coordinates, just with the simplifying case that they only have a specific number of points. Rect
doesn't do that, or else Rect
would store 4 coordinates, not 2. We need to do some sort of conversion from the min
and max
coordinates to a continuous ring.
It's obvious how to do this for 2D input, but less clear how to do this for 3D or 4D. I'd suggest that we should error for 3D/4D, as the user can choose how to transform a 3D or 4D Rect.
Or perhaps we could even change the RectTrait
so that it doesn't have the same dimensionality as the others. Because Rect
means "axis aligned bounding box" and when you have 3 or 4 axes, it's less clear how that maps to simple-features.
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.
oh geeze, yeah that's a mess.
Given that we're only handling 2d, can we at least avoid the vec allocation in that case?
As for erroring on 3-d/4-d, that seems reasonable, assuming you mean a runtime error.
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.
Yeah, we can avoid the vec allocation, just makes the code slightly more complicated.
Also, what should we do with the error? Currently it returns std::fmt::Error
and there's no error type in this crate.
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.
Feel free to propose something.
src/to_wkt/geo_trait_impl.rs
Outdated
} | ||
} | ||
|
||
pub fn point_to_wkt<T: CoordNum + WktNum + fmt::Display, G: PointTrait<T = T>, W: Write>( |
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.
naming nit for all the foo_to_wkt
methods: Idiomatically, I'd expect point_to_wkt
to do something like From::from(point) -> Wkt
.
But this doesn't convert to Wkt. Internally it conceptually converts to something like a String of wkt, but we don't return that either.
A closer analogy might be the Format::write
method or write
macro, implying something like:
write_wkt_point(&mut writer, &my_point)?;
write_wkt_polygon(&mut writer, &my_polygon)?;
In fact, I think we can exclude wkt
from the method names since it's redundant with the crate.
write_point(&mut writer, &my_point)?;
write_polygon(&mut writer, &my_polygon)?;
If calling users want to be explicit about the fact that it's wkt at the callsite, they could:
wkt::write_point(&mut writer, &my_point)?;
wkt::write_polygon(&mut writer, &my_point)?;
Note: this would entail re-exporting all these methods at the top-level of the crate.
Additionally, taking advantage of georust/geo#1157 (comment) maybe there should be a plain old:
fn write(&mut writer, any_geometry: impl GeometryTrait) {
write_geometry(writer, any_geometry)
}
So the caller can do:
wkt::write(&mut writer, &my_point);
wkt::write(&mut writer, &my_polygon);
I think that'd work, right? It'd be slightly less performant if you already know the type, but probably negligible for most, and nicer to write.
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, this is a good point. I had the same realization when cleaning up my wkb
crate: kylebarron/wkb#4
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 shortened names but didn't shorten write_geometry
to write
. We should be able to just pub use write_geometry as write
?
@@ -31,22 +30,6 @@ where | |||
pub m: Option<T>, | |||
} | |||
|
|||
impl<T> fmt::Display for Coord<T> |
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.
Though it seems unlikely anyone is using it, can we leave it as it was and deprecate it first, for sake of avoiding a breaking change?
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.
is it possible to deprecate a trait impl? Seems not.
https://users.rust-lang.org/t/deprecate-an-implementation/90350
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.
Darn. Sorry for the noise!
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.
Well we could just leave this trait impl in even though it's no longer used 🤷♂️
src/to_wkt/mod.rs
Outdated
@@ -1,5 +1,7 @@ | |||
use crate::{Wkt, WktNum}; | |||
|
|||
pub mod geo_trait_impl; |
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 love the name of this module. Especially if it's becoming the de-facto writer.
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.
In case you're copying this naming convention from the geojson
crate pull request, I went with this name knowing that it wouldn't be exposed publicly. I didn't put a lot of thought into it so feel free to stray from 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.
I think this really depends on georust/geo#1241 and/or requiring a geo-types
dependency here. With this PR all writing goes through the trait impl, but the traits currently depend on geo-types
.
In that case, we could make geo_trait_impl
private and re-export the functions through wkt::to_wkt::*
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.
ref f3434f5
(#124)
CHANGES.md
if knowledge of this change could be valuable to users.Changes:
This slightly changes the implementation for writing to WKT, partially based on @b4l's PR here geoarrow/geoarrow-rs#788.
While porting the code to use traits, I realized that there was an awful lot of string concatenation being performed. So for example, when writing a Polygon to WKT, every single coordinate would be allocated to a separate string, and then the coords of each ring would be concatenated and then all rings would be concatenated.
wkt/src/types/polygon.rs
Lines 42 to 52 in e1d838d
This instead writes coordinates directly to the output writer. So perhaps the performance differences in the discussion here #118 were not primarily due to
ryu
.This PR also implements writing for geo-traits objects, and delegates the
std::fmt::Display
implementation to the underlying geo-traits impl.Benchmark against
main
:I also added another bench for writing the
geo::Geometry
object directly instead of first converting it to awkt::Wkt
. It's not 100% apples to oranges because I can't usestd::io::sink()
for astd::fmt::Write
trait input. But it's still faster 🤷♂️