Skip to content
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 new Transform algorithm for transforming a geometry with PROJ. #718

Merged
merged 2 commits into from
Feb 6, 2022

Conversation

frewsxcv
Copy link
Member

@frewsxcv frewsxcv commented Jan 29, 2022

  • I agree to follow the project's code of conduct.
  • I added an entry to CHANGES.md if knowledge of this change could be valuable to users.
    • I will do this if we decide we want this
  • Add entry to table of contents in lib.rs

@frewsxcv frewsxcv force-pushed the frewsxcv-transform branch 2 times, most recently from f02bb07 to 48048ea Compare January 29, 2022 17:46
@lnicola
Copy link
Member

lnicola commented Jan 29, 2022

This is nice to have, but I'm wondering if it's better to take the transform instead of the two CRSes. I don't know how long these take to instantiate in practice, but it seems like you'd want to reuse them when possible.

@urschrei
Copy link
Member

the transform instead of the two CRSes
it seems like you'd want to reuse them when possible.

I agree, even though the trade-off is a less-nice API. However, without something that takes a Proj instance, you can't use a ProjBuilder to enable grid downloads (etc.) requiring network access, which is common for people who need higher-accuracy transforms:

let pb = ProjBuilder::new();
pb.enable_network().unwrap();
let transform = pb.proj_known_crs("EPSG:4326", "EPSG:3857").unwrap(); // Proj instance!

@frewsxcv
Copy link
Member Author

frewsxcv commented Jan 29, 2022

What if the argument was transform(transformer: TryInto<Proj>)? So you could pass it a Proj directly, and we could also consider adding a TryFrom<(&str, &str)> for Proj implementation in the proj crate, so you could do transform(("EPSG:4326", "EPSG:3857")) here.

@urschrei
Copy link
Member

What if the argument was transform(transformer: TryInto)? So you could pass it a Proj directly, and we could also consider adding a TryFrom<(&str, &str)> for Proj implementation in the proj crate, so you could do transform(("EPSG:4326", "EPSG:3857")) here.

I like it.

@lnicola
Copy link
Member

lnicola commented Jan 29, 2022

It's okay, but not really discoverable.

@frewsxcv
Copy link
Member Author

frewsxcv commented Jan 29, 2022

I agree the TryFrom and TryInto trait implementations are hard to discover, so I would add documentation examples demonstrating you can use multiple options here. I added similar docs for ToSocketAddr a while back, which has multiple implementations.

@michaelkirk
Copy link
Member

michaelkirk commented Jan 30, 2022

To recap, I agree that accepting a TryInto<Proj> param is the most flexible.

And ("EPSG:4326", "EPSG:3857").try_into() is concise, but I don't think that I'd guess for it to exist. The docs you're planning to add will help.

But I usually go to the docs only after I fail to intuit the API. If we think that often people will want to use the initially proposed interface (from: &str, to: &str), then I think it makes sense to expose a more discoverable helper method, like this:

pub trait Transform<T> {
    type Output;

    /// naming insperation from  https://proj.org/development/reference/functions.html#c.proj_create_crs_to_crs
    fn transform_crs_to_crs(&self, from: &str, to: &str)
        -> Result<Self::Output, TransformError> {
        self.transform((from, to).try_into()?)
    }

    fn transform(&self, proj: TryInto<Proj>)
         -> Result<Self::Output, TransformError>;
 }

WDYT?

If it's controversial, don't worry about it. We could always add it later.

@phayes
Copy link
Contributor

phayes commented Feb 3, 2022

I tried this out and it works great!

Question: Does it make sense to use Proj::convert_array instead of converting each point individually? Could be faster to make one call to Proj instead of many, especially on large polygons etc.

@michaelkirk
Copy link
Member

Great point @phayes!

I think it's possible with the current API's we have (poly.interiors_mut(), line_string.0)... and if it's not possible we should consider making it so.

It's a perf improvement that doesn't seem like it would impact the API proposed here, so I'd also be fine with leaving that for a followup PR depending on how much time @frewsxcv wants to sink into this right now.

@frewsxcv
Copy link
Member Author

frewsxcv commented Feb 3, 2022

I don't have much time to push this over the finish line over the next few days. If anyone wants to take over and push to my branch, I'd say go for it. I'm also not opposed to merging as-is (ish) and following up with some of these changes.

@phayes
Copy link
Contributor

phayes commented Feb 3, 2022

Thinking about the best performance here again, and I think the long-term solution is actually to add a convert_inter_mut method to Proj. If you look at the array processing code here (https://github.com/georust/proj/blob/83fca44d25b0def3fe7b313d85cf638aa7fdf493/src/proj.rs#L802-L865), we could avoid some allocations by passing an Into<Iterator> where Item: &'a mut Coord<F> or something similar. It also might make sense to grab num_coords first and do the simple thing if there's a small number of coords.

Anyways, long-term idea that doesn't affect the API surface here.

@frewsxcv
Copy link
Member Author

frewsxcv commented Feb 4, 2022

This is semi-blocked on georust/proj#100 and a proj release

@phayes
Copy link
Contributor

phayes commented Feb 4, 2022

What do folks think of doing something like this?

georust/proj#105

@frewsxcv frewsxcv force-pushed the frewsxcv-transform branch 2 times, most recently from 36664c6 to 83a4664 Compare February 5, 2022 04:52
@frewsxcv frewsxcv changed the title Add new Transform algorithm for transforming a geometry's CRS. Add new Transform algorithm for transforming a geometry with PROJ. Feb 5, 2022
@frewsxcv
Copy link
Member Author

frewsxcv commented Feb 5, 2022

Once georust/proj#103 is reviewed, I will merge it and do a proj crate release. Then this PR will be ready for review.

@frewsxcv frewsxcv force-pushed the frewsxcv-transform branch 2 times, most recently from 7ccecce to efce819 Compare February 6, 2022 16:09
@frewsxcv
Copy link
Member Author

frewsxcv commented Feb 6, 2022

This is ready for review!

geo/src/algorithm/transform.rs Outdated Show resolved Hide resolved
@frewsxcv
Copy link
Member Author

frewsxcv commented Feb 6, 2022

bors r=lnicola

@bors
Copy link
Contributor

bors bot commented Feb 6, 2022

Build succeeded:

@bors bors bot merged commit 73af924 into master Feb 6, 2022
@frewsxcv frewsxcv deleted the frewsxcv-transform branch February 6, 2022 17:58
bors bot added a commit to georust/proj that referenced this pull request Feb 20, 2022
109: Port transform trait from geo and add a mutable flavor r=frewsxcv a=michaelkirk

Fixes #101, #108

An alternative to #106, but as proposed in #108, I've done so by porting the [Transform trait from geo](georust/geo#718 ) to proj so that we won't need similar-but-different code in two places.

I chose to double down on a trait-based approach since it seemed idiomatic to our other georust code. However, like proposed in #106, I leveraged proj_array in more places.

/cc `@x4d3` 

corresponding PRs:
- georust/geo#730
- frewsxcv/rgis#47

Co-authored-by: Michael Kirk <michael.code@endoftheworl.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants