Skip to main content

transit_grid/algorithms/
edge_length.rs

1//! Edge length functions for `TransitEdge`.
2use geo::{CoordFloat, Euclidean, Haversine, Length};
3use num_traits::FromPrimitive;
4use std::iter::Sum;
5
6use crate::core::TransitEdge;
7
8/// EdgeLength trait provides the length of an element.
9/// It is designed to work with types that implement the `CoordFloat`, `FromPrimitive`, and `Sum` traits.
10pub trait EdgeLength<T: CoordFloat + Sum> {
11    /// Returns the Euclidean length of the element.
12    fn length(&self) -> T;
13
14    /// Returns the Euclidean length of the element.
15    fn euclidean_length(&self) -> T;
16
17    /// Returns the Haversine (great-circle) length of the element.
18    fn haversine_length(&self) -> T;
19}
20
21/// EdgeLength trait implementation for `TransitEdge`.
22/// Returns the Euclidean length of the `TransitEdge`.
23impl<T: CoordFloat + FromPrimitive + Sum> EdgeLength<T> for TransitEdge<T> {
24    fn length(&self) -> T {
25        self.euclidean_length()
26    }
27
28    fn euclidean_length(&self) -> T {
29        Euclidean.length(&self.path)
30    }
31
32    fn haversine_length(&self) -> T {
33        Haversine.length(&self.path)
34    }
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40    use geo::LineString;
41
42    #[test]
43    fn test_edge_length() {
44        let line = LineString::from(vec![(0.0, 0.0), (1.0, 1.0)]);
45        let edge = TransitEdge {
46            id: 1,
47            source: 1,
48            target: 2,
49            length: 1.0,
50            path: line.clone(),
51        };
52
53        assert_eq!(edge.length(), (2f64).sqrt());
54    }
55
56    #[test]
57    fn test_euclidean_length() {
58        let line = LineString::from(vec![(0.0, 0.0), (1.0, 1.0)]);
59        let edge = TransitEdge {
60            id: 1,
61            source: 1,
62            target: 2,
63            length: 1.0,
64            path: line.clone(),
65        };
66
67        assert_eq!(edge.euclidean_length(), (2f64).sqrt());
68    }
69
70    #[test]
71    fn test_haversine_length() {
72        let line = LineString::from(vec![(-179.9, 0.0), (179.9, 0.0)]);
73        let edge = TransitEdge {
74            id: 1,
75            source: 1,
76            target: 2,
77            length: 1.0,
78            path: line.clone(),
79        };
80
81        let approx_circumference = 2.0 * std::f64::consts::PI * 6371.0 * 1000.0; // Approx. Earth radius in m
82        let expected_length = approx_circumference * (0.2 / 360.0); // 0.2 degrees out of 360 degrees
83        assert!((edge.haversine_length() - expected_length).abs() < 1.0); // Allow 1 km error
84    }
85}