geo/algorithm/haversine_length.rs
1use num_traits::FromPrimitive;
2
3use crate::HaversineDistance;
4use crate::{CoordFloat, Line, LineString, MultiLineString};
5
6/// Determine the length of a geometry using the [haversine formula].
7///
8/// [haversine formula]: https://en.wikipedia.org/wiki/Haversine_formula
9///
10/// *Note*: this implementation uses a mean earth radius of 6371.088 km, based on the [recommendation of
11/// the IUGG](ftp://athena.fsv.cvut.cz/ZFG/grs80-Moritz.pdf)
12pub trait HaversineLength<T, RHS = Self> {
13 /// Determine the length of a geometry using the [haversine formula].
14 ///
15 /// # Units
16 ///
17 /// - return value: meters
18 ///
19 /// # Examples
20 ///
21 /// ```
22 /// use geo::prelude::*;
23 /// use geo::LineString;
24 ///
25 /// let linestring = LineString::<f64>::from(vec![
26 /// // New York City
27 /// (-74.006, 40.7128),
28 /// // London
29 /// (-0.1278, 51.5074),
30 /// ]);
31 ///
32 /// let length = linestring.haversine_length();
33 ///
34 /// assert_eq!(
35 /// 5_570_230., // meters
36 /// length.round()
37 /// );
38 /// ```
39 ///
40 /// [haversine formula]: https://en.wikipedia.org/wiki/Haversine_formula
41 fn haversine_length(&self) -> T;
42}
43
44impl<T> HaversineLength<T> for Line<T>
45where
46 T: CoordFloat + FromPrimitive,
47{
48 fn haversine_length(&self) -> T {
49 let (start, end) = self.points();
50 start.haversine_distance(&end)
51 }
52}
53
54impl<T> HaversineLength<T> for LineString<T>
55where
56 T: CoordFloat + FromPrimitive,
57{
58 fn haversine_length(&self) -> T {
59 self.lines().fold(T::zero(), |total_length, line| {
60 total_length + line.haversine_length()
61 })
62 }
63}
64
65impl<T> HaversineLength<T> for MultiLineString<T>
66where
67 T: CoordFloat + FromPrimitive,
68{
69 fn haversine_length(&self) -> T {
70 self.0
71 .iter()
72 .fold(T::zero(), |total, line| total + line.haversine_length())
73 }
74}