use geo::{CoordFloat, EuclideanLength, HaversineLength};
use num_traits::FromPrimitive;
use std::iter::Sum;
use crate::core::TransitEdge;
pub trait EdgeLength<T: CoordFloat + Sum> {
fn length(&self) -> T;
}
impl<T: CoordFloat + FromPrimitive + Sum> EdgeLength<T> for TransitEdge<T> {
fn length(&self) -> T {
self.euclidean_length()
}
}
impl<T: CoordFloat + Sum> EuclideanLength<T> for TransitEdge<T> {
fn euclidean_length(&self) -> T {
self.path.euclidean_length()
}
}
impl<T: CoordFloat + FromPrimitive> HaversineLength<T> for TransitEdge<T> {
fn haversine_length(&self) -> T {
self.path.haversine_length()
}
}
#[cfg(test)]
mod tests {
use super::*;
use geo::LineString;
#[test]
fn test_edge_length() {
let line = LineString::from(vec![(0.0, 0.0), (1.0, 1.0)]);
let edge = TransitEdge {
id: 1,
source: 1,
target: 2,
length: 1.0,
path: line.clone(),
};
assert_eq!(edge.length(), (2f64).sqrt());
}
#[test]
fn test_euclidean_length() {
let line = LineString::from(vec![(0.0, 0.0), (1.0, 1.0)]);
let edge = TransitEdge {
id: 1,
source: 1,
target: 2,
length: 1.0,
path: line.clone(),
};
assert_eq!(edge.euclidean_length(), (2f64).sqrt());
}
#[test]
fn test_haversine_length() {
let line = LineString::from(vec![(-179.9, 0.0), (179.9, 0.0)]);
let edge = TransitEdge {
id: 1,
source: 1,
target: 2,
length: 1.0,
path: line.clone(),
};
let approx_circumference = 2.0 * std::f64::consts::PI * 6371.0 * 1000.0; let expected_length = approx_circumference * (0.2 / 360.0); assert!((edge.haversine_length() - expected_length).abs() < 1.0); }
}