use super::Distance;
use crate::{CoordFloat, Line, LineString, MultiLineString, Point};
pub trait Length<F: CoordFloat> {
fn length(&self, geometry: &impl LengthMeasurable<F>) -> F;
}
pub trait LengthMeasurable<F: CoordFloat> {
fn length(&self, metric_space: &impl Distance<F, Point<F>, Point<F>>) -> F;
}
impl<F: CoordFloat, PointDistance: Distance<F, Point<F>, Point<F>>> Length<F> for PointDistance {
fn length(&self, geometry: &impl LengthMeasurable<F>) -> F {
geometry.length(self)
}
}
impl<F: CoordFloat> LengthMeasurable<F> for Line<F> {
fn length(&self, metric_space: &impl Distance<F, Point<F>, Point<F>>) -> F {
metric_space.distance(self.start_point(), self.end_point())
}
}
impl<F: CoordFloat> LengthMeasurable<F> for LineString<F> {
fn length(&self, metric_space: &impl Distance<F, Point<F>, Point<F>>) -> F {
let mut length = F::zero();
for line in self.lines() {
length = length + line.length(metric_space);
}
length
}
}
impl<F: CoordFloat> LengthMeasurable<F> for MultiLineString<F> {
fn length(&self, metric_space: &impl Distance<F, Point<F>, Point<F>>) -> F {
let mut length = F::zero();
for line in self {
length = length + line.length(metric_space);
}
length
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Euclidean, Geodesic, Haversine, Rhumb, coord};
#[test]
fn lines() {
let line = Line::new(
coord!(x: -0.1278f64, y: 51.5074),
coord!(x: 2.3522, y: 48.8566),
);
assert_eq!(
343_923., Geodesic.length(&line).round()
);
assert_eq!(
343_572., Rhumb.length(&line).round()
);
assert_eq!(
343_557., Haversine.length(&line).round()
);
assert_eq!(
4., Euclidean.length(&line).round()
);
let projected_line = Line::new(
coord!(x: 3620451.74f64, y: 3203901.44),
coord!(x: 3760771.86, y: 2889484.80),
);
assert_eq!(344_307., Euclidean.length(&projected_line).round());
}
#[test]
fn line_strings() {
let line_string = LineString::new(vec![
coord!(x: -58.3816f64, y: -34.6037), coord!(x: -77.0428, y: -12.0464), coord!(x: -47.9292, y: -15.7801), ]);
assert_eq!(
6_302_220., Geodesic.length(&line_string).round()
);
assert_eq!(
6_308_683., Rhumb.length(&line_string).round()
);
assert_eq!(
6_304_387., Haversine.length(&line_string).round()
);
assert_eq!(
59., Euclidean.length(&line_string).round()
);
let projected_line_string = LineString::from(vec![
coord!(x: 143042.46f64, y: -1932485.45), coord!(x: -1797084.08, y: 583528.84), coord!(x: 1240052.27, y: 207169.12), ]);
assert_eq!(6_237_538., Euclidean.length(&projected_line_string).round());
}
}