-
Notifications
You must be signed in to change notification settings - Fork 198
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Unified Length trait, generic over MetricSpace
- Loading branch information
1 parent
1cafb00
commit 3cb3f0e
Showing
6 changed files
with
149 additions
and
0 deletions.
There are no files selected for viewing
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
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,130 @@ | ||
use super::Distance; | ||
use crate::{CoordFloat, Line, LineString, MultiLineString, Point}; | ||
|
||
/// Calculate the length of a `Line`, `LineString`, or `MultiLineString` in a given [metric space](crate::algorithm::line_measures::metric_spaces). | ||
/// | ||
/// # Examples | ||
/// ``` | ||
/// use geo::algorithm::line_measures::{Length, Euclidean, Haversine}; | ||
/// | ||
/// let line_string = geo::wkt!(LINESTRING( | ||
/// 0.0 0.0, | ||
/// 3.0 4.0, | ||
/// 3.0 5.0 | ||
/// )); | ||
/// assert_eq!(line_string.length::<Euclidean>(), 6.); | ||
/// | ||
/// let line_string_lon_lat = geo::wkt!(LINESTRING ( | ||
/// -47.9292 -15.7801f64, | ||
/// -58.4173 -34.6118, | ||
/// -70.6483 -33.4489 | ||
/// )); | ||
/// assert_eq!(line_string_lon_lat.length::<Haversine>().round(), 3_474_956.0); | ||
/// ``` | ||
pub trait Length<F: CoordFloat> { | ||
fn length<MetricSpace: Distance<F, Point<F>, Point<F>>>(&self) -> F; | ||
} | ||
|
||
impl<F: CoordFloat> Length<F> for Line<F> { | ||
fn length<MetricSpace: Distance<F, Point<F>, Point<F>>>(&self) -> F { | ||
MetricSpace::distance(self.start_point(), self.end_point()) | ||
} | ||
} | ||
|
||
impl<F: CoordFloat> Length<F> for LineString<F> { | ||
fn length<MetricSpace: Distance<F, Point<F>, Point<F>>>(&self) -> F { | ||
let mut length = F::zero(); | ||
for line in self.lines() { | ||
length = length + line.length::<MetricSpace>(); | ||
} | ||
length | ||
} | ||
} | ||
|
||
impl<F: CoordFloat> Length<F> for MultiLineString<F> { | ||
fn length<MetricSpace: Distance<F, Point<F>, Point<F>>>(&self) -> F { | ||
let mut length = F::zero(); | ||
for line in self { | ||
length = length + line.length::<MetricSpace>(); | ||
} | ||
length | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use crate::{coord, Euclidean, Geodesic, Haversine, Rhumb}; | ||
|
||
#[test] | ||
fn lines() { | ||
// london to paris | ||
let line = Line::new( | ||
coord!(x: -0.1278f64, y: 51.5074), | ||
coord!(x: 2.3522, y: 48.8566), | ||
); | ||
|
||
assert_eq!( | ||
343_923., // meters | ||
line.length::<Geodesic>().round() | ||
); | ||
assert_eq!( | ||
341_088., // meters | ||
line.length::<Rhumb>().round() | ||
); | ||
assert_eq!( | ||
343_557., // meters | ||
line.length::<Haversine>().round() | ||
); | ||
|
||
// computing Euclidean length of an unprojected (lng/lat) line gives a nonsense answer | ||
assert_eq!( | ||
4., // nonsense! | ||
line.length::<Euclidean>().round() | ||
); | ||
// london to paris in EPSG:3035 | ||
let projected_line = Line::new( | ||
coord!(x: 3620451.74f64, y: 3203901.44), | ||
coord!(x: 3760771.86, y: 2889484.80), | ||
); | ||
assert_eq!(344_307., projected_line.length::<Euclidean>().round()); | ||
} | ||
|
||
#[test] | ||
fn line_strings() { | ||
let line_string = LineString::new(vec![ | ||
coord!(x: -58.3816f64, y: -34.6037), // Buenos Aires, Argentina | ||
coord!(x: -77.0428, y: -12.0464), // Lima, Peru | ||
coord!(x: -47.9292, y: -15.7801), // Brasília, Brazil | ||
]); | ||
|
||
assert_eq!( | ||
6_302_220., // meters | ||
line_string.length::<Geodesic>().round() | ||
); | ||
assert_eq!( | ||
6_332_790., // meters | ||
line_string.length::<Rhumb>().round() | ||
); | ||
assert_eq!( | ||
6_304_387., // meters | ||
line_string.length::<Haversine>().round() | ||
); | ||
|
||
// computing Euclidean length of an unprojected (lng/lat) gives a nonsense answer | ||
assert_eq!( | ||
59., // nonsense! | ||
line_string.length::<Euclidean>().round() | ||
); | ||
// EPSG:102033 | ||
let projected_line_string = LineString::from(vec![ | ||
coord!(x: 143042.46f64, y: -1932485.45), // Buenos Aires, Argentina | ||
coord!(x: -1797084.08, y: 583528.84), // Lima, Peru | ||
coord!(x: 1240052.27, y: 207169.12), // Brasília, Brazil | ||
]); | ||
assert_eq!( | ||
6_237_538., | ||
projected_line_string.length::<Euclidean>().round() | ||
); | ||
} | ||
} |
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