-
Notifications
You must be signed in to change notification settings - Fork 199
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
All of these algorithm implementations already existed, but I'm proposing a new way to organize them which I hope will be more consistent and discoverable. Note: The new Haversine::bearing and Geodesic::bearing return 0..360, the legacy traits HaversineBearing and GeodesicBearing returned -180..180 Additional changes: Deleted the deprecated `Bearing` trait which was previously superceeded by the unambiguous `HaversineBearing` trait, but now is re-defined as `Haversine::bearing` = Future Work = In an effort to minimize this PR, while keeping the change reasonably coherent, I've left some things out == Methods on Euclidean == -[ ] bearing (doesn't currently exist) -[ ] destination (doesn't currently exist) -[ ] intermediate (exists, but InterpolatePoint trait also needs intermediate_fill) -[ ] intermediate_fill (doesn't currently exist) == Deprecate Legacy Traits == -[ ] Deprecate Legacy impls -[ ] Switcheroo the actual implementation: move the actual implementation to the new traits, and have the legacy traits delegate to the new traits. -[ ] Move over any tests from the legacy implementation to the new home == Methods on Geoms (Future PR) == -[ ] Length -[ ] Haversine -[ ] Rhumb -[ ] Geodesic -[ ] Euclidean -[ ] Densify -[ ] Haversine -[ ] Rhumb -[ ] Geodesic -[ ] Euclidean FIXES #1210 FIXES #1181
- Loading branch information
1 parent
68f80f8
commit a635f84
Showing
15 changed files
with
1,173 additions
and
47 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
use geo_types::{CoordFloat, Point}; | ||
|
||
/// Calculate the bearing between two points | ||
pub trait Bearing<F: CoordFloat> { | ||
/// Calculate the bearing from `origin` to `destination` in degrees. | ||
/// | ||
/// See [specific implementations](#implementors) for details. | ||
/// | ||
/// # Units | ||
/// - `origin`, `destination`: Point where the units of x/y depend on the [trait implementation](#implementors). | ||
/// - returns: degrees, where: North: 0°, East: 90°, South: 180°, West: 270° | ||
fn bearing(origin: Point<F>, destination: Point<F>) -> F; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
use geo_types::{CoordFloat, Point}; | ||
|
||
/// Calculate the destination point from an origin point, a bearing and a distance. | ||
pub trait Destination<F: CoordFloat> { | ||
/// Returns a new point having travelled the `distance` along a line | ||
/// from the `origin` point with the given `bearing`. | ||
/// | ||
/// See [specific implementations](#implementors) for details. | ||
/// | ||
/// # Units | ||
/// | ||
/// - `origin`: Point where the units of x/y depend on the [trait implementation](#implementors). | ||
/// - `bearing`: degrees, where: North: 0°, East: 90°, South: 180°, West: 270° | ||
/// - `distance`: depends on the [trait implementation](#implementors). | ||
/// - returns: Point where the units of x/y depend on the [trait implementation](#implementors). | ||
/// | ||
/// [`metric_spaces`]: super::metric_spaces | ||
fn destination(origin: Point<F>, bearing: F, distance: F) -> Point<F>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
/// Calculate the distance between the `Origin` and `Destination` geometry. | ||
pub trait Distance<F, Origin, Destination> { | ||
/// Note that not all implementations support all geometry combinations, but at least `Point` to `Point` | ||
/// is supported. | ||
/// See [specific implementations](#implementors) for details. | ||
/// | ||
/// # Units | ||
/// | ||
/// - `origin`, `destination`: geometry where the units of x/y depend on the trait implementation. | ||
/// - returns: depends on the trait implementation. | ||
fn distance(origin: Origin, destination: Destination) -> F; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
use crate::{CoordFloat, Point}; | ||
|
||
// REVIEW: Naming alternatives: | ||
// - LinearReferencing | ||
// - PointAlongLine | ||
// - LineInterpolatePoint (postgis) | ||
// - Interpolate (shapely) | ||
// - Position (geographiclib) | ||
// - Intermediate (georust::geo) | ||
pub trait InterpolatePoint<F: CoordFloat> { | ||
/// Returns a new Point along a line between two existing points | ||
/// | ||
/// See [specific implementations](#implementors) for details. | ||
fn point_at_ratio_between(start: Point<F>, end: Point<F>, ratio_from_start: F) -> Point<F>; | ||
|
||
// TODO: | ||
// fn point_at_distance_between(start: Point<F>, end: Point<F>, distance_from_start: F) -> Point<F>; | ||
|
||
/// Interpolates `Point`s along a line between `start` and `end`. | ||
/// | ||
/// See [specific implementations](#implementors) for details. | ||
/// | ||
/// As many points as necessary will be added such that the distance between points | ||
/// never exceeds `max_distance`. If the distance between start and end is less than | ||
/// `max_distance`, no additional points will be included in the output. | ||
/// | ||
/// `include_ends`: Should the start and end points be included in the output? | ||
fn points_along_line( | ||
start: Point<F>, | ||
end: Point<F>, | ||
max_distance: F, | ||
include_ends: bool, | ||
) -> impl Iterator<Item = Point<F>>; | ||
} |
106 changes: 106 additions & 0 deletions
106
geo/src/algorithm/line_measures/metric_spaces/euclidean.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
use super::super::Distance; | ||
use crate::{GeoFloat, Point}; | ||
|
||
/// Euclidean space measures distance with the pythagorean formula - what you'd measure with a ruler. | ||
/// | ||
/// You must use projected coordinates with Euclidean space — | ||
/// for lon/lat points, use the [`Haversine`], [`Geodesic`], or other [metric spaces]. | ||
/// | ||
/// [`Haversine`]: super::Haversine | ||
/// [`Geodesic`]: super::Geodesic | ||
/// [metric spaces]: super | ||
pub struct Euclidean; | ||
|
||
/// Calculate the Euclidean distance (a.k.a. pythagorean distance) between two Points | ||
impl<F: GeoFloat> Distance<F, Point<F>, Point<F>> for Euclidean { | ||
/// Calculate the Euclidean distance (a.k.a. pythagorean distance) between two Points | ||
/// | ||
/// # Units | ||
/// - `origin`, `destination`: Point where the units of x/y represent non-angular units | ||
/// — e.g. meters or miles, not lon/lat. For lon/lat points, use the | ||
/// [`Haversine`] or [`Geodesic`] [metric spaces]. | ||
/// - returns: distance in the same units as the `origin` and `destination` points | ||
/// | ||
/// # Example | ||
/// ``` | ||
/// use geo::{Euclidean, Distance}; | ||
/// use geo::Point; | ||
/// // web mercator | ||
/// let new_york_city = Point::new(-8238310.24, 4942194.78); | ||
/// // web mercator | ||
/// let london = Point::new(-14226.63, 6678077.70); | ||
/// let distance: f64 = Euclidean::distance(new_york_city, london); | ||
/// | ||
/// assert_eq!( | ||
/// 8_405_286., // meters in web mercator | ||
/// distance.round() | ||
/// ); | ||
/// ``` | ||
/// | ||
/// [`Haversine`]: super::Haversine | ||
/// [`Geodesic`]: super::Geodesic | ||
/// [metric spaces]: super | ||
fn distance(origin: Point<F>, destination: Point<F>) -> F { | ||
crate::EuclideanDistance::euclidean_distance(&origin, &destination) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
type MetricSpace = Euclidean; | ||
|
||
mod distance { | ||
use super::*; | ||
|
||
#[test] | ||
fn new_york_to_london() { | ||
// web mercator | ||
let new_york_city = Point::new(-8238310.24, 4942194.78); | ||
// web mercator | ||
let london = Point::new(-14226.63, 6678077.70); | ||
let distance: f64 = MetricSpace::distance(new_york_city, london); | ||
|
||
assert_relative_eq!( | ||
8_405_286., // meters in web mercator | ||
distance.round() | ||
); | ||
} | ||
} | ||
/* | ||
mod interpolate_point { | ||
use super::*; | ||
#[test] | ||
fn point_at_ratio_between_midpoint() { | ||
let start = Point::new(10.0, 20.0); | ||
let end = Point::new(125.0, 25.0); | ||
let midpoint = MetricSpace::point_at_ratio_between(start, end, 0.5); | ||
assert_relative_eq!(midpoint, Point::new(65.87394172511485, 37.61809316888599)); | ||
} | ||
#[test] | ||
fn points_along_line_with_endpoints() { | ||
let start = Point::new(10.0, 20.0); | ||
let end = Point::new(125.0, 25.0); | ||
let max_dist = 1000000.0; // meters | ||
let route = | ||
MetricSpace::points_along_line(start, end, max_dist, true).collect::<Vec<_>>(); | ||
assert_eq!(route.len(), 13); | ||
assert_eq!(route[0], start); | ||
assert_eq!(route.last().unwrap(), &end); | ||
assert_relative_eq!(route[1], Point::new(17.882467331860965, 24.435542998803793)); | ||
} | ||
#[test] | ||
fn points_along_line_without_endpoints() { | ||
let start = Point::new(10.0, 20.0); | ||
let end = Point::new(125.0, 25.0); | ||
let max_dist = 1000000.0; // meters | ||
let route = | ||
MetricSpace::points_along_line(start, end, max_dist, false).collect::<Vec<_>>(); | ||
assert_eq!(route.len(), 11); | ||
assert_relative_eq!(route[0], Point::new(17.882467331860965, 24.435542998803793)); | ||
} | ||
} | ||
*/ | ||
} |
Oops, something went wrong.