georust / geo

Geospatial primitives and algorithms for Rust
https://crates.io/crates/geo
Other
1.49k stars 194 forks source link

Add rhumb-line operations #1090

Closed apendleton closed 9 months ago

apendleton commented 9 months ago

The code layout is a little different from the haversine ones (everything is in a new rhumb module), mainly because I wanted to share code between several of these since there's a lot of overlap. In particular, all of the operations that work on two points (so, bearing, distance, and intermediate) use a common calculations struct that does a bunch of the up-front shared setup. Obviously this is all rearrange-able though if there's a different preferred layout.

The RhumbBearing, RhumbDestination, and RhumbDistance implementations are heavily inspired by their Turf.js equivalents (bearing, destination, and distance, respectively), which seem in turn to largely be inspired by the Movable Type rhumb line formula descriptions.

Turf doesn't have an intermediate operation for rhumb lines, so what's I've done here is "find the rhumb distance and rhumb bearing, calculate a fraction along that distance, and then calculate a rhumb destination," with (hopefully) most of the redundant trig factored out, as there's a fair bit of overlap between those operations. There might well be a more-direct trigonometric solution to this problem, though? Movable Type has a "rhumb midpoint" formula, but it doesn't seem to generalize to fractions other than 0.5; pygeodesy does seem to implement this concept, and special-cases 0.5 with the formula from Movable Type but also has a more general one, but honestly I found the code to be very difficult to understand. Hopefully what I've got is good enough for a first pass.

Tests are mostly appropriated from the equivalent Haversine traits and then adjusted so the values look right. I also separately confirmed that at least for the functions where Turf has equivalents, these implementations produce (approximately, allowing for float differences, etc.) the same values.

A couple of other odds and ends:

urschrei commented 9 months ago

Attribution: as these are ports and refactors of existing code, I'm not sure if I should put references in comments in these files to where they came from and what their licenses originally were. It doesn't look like existing code that's of similar provenance does so now for the most part, but if that would be a good thing to do, let me know where it's preferred that it go, and I can add it.

Any time this question arises, I think about https://macwright.com/2013/02/18/literate-jenks (Even though nobody should be using Jenks in this day and age, but I digress). So in answer to your question: you never know who's going to be spelunking in this code in 30 years, so any breadcrumbs you can leave will be appreciated – if you have time, please add them.

Otherwise, this seems like a clean well-organised module to me, and a great addition to the crate. Thank you!

apendleton commented 9 months ago

@urschrei added an attribution block to rhumb/mod.rs .