use geometry_cs::{CoordinateSystem, SphericalFamily};
use geometry_model::Segment;
use geometry_tag::SameAs;
use geometry_trait::{Point, PointMut};
use crate::closest_points::ClosestPointsStrategy;
use crate::normalise::HasAngularUnits;
use super::great_circle;
#[derive(Debug, Clone, Copy)]
pub struct HaversineClosestPoints {
pub radius: f64,
}
impl HaversineClosestPoints {
pub const EARTH: Self = Self {
radius: 6_372_795.0,
};
pub const UNIT: Self = Self { radius: 1.0 };
}
impl Default for HaversineClosestPoints {
fn default() -> Self {
Self::EARTH
}
}
impl<P> ClosestPointsStrategy<P, Segment<P>> for HaversineClosestPoints
where
P: Point<Scalar = f64> + PointMut + Default + Copy,
P::Cs: HasAngularUnits,
<P::Cs as CoordinateSystem>::Family: SameAs<SphericalFamily>,
{
type Out = P;
fn closest_points(&self, point: &P, segment: &Segment<P>) -> (Self::Out, Self::Out) {
let projected = great_circle::project(point, segment.start(), segment.end()).point;
(*point, projected)
}
}
impl<P> ClosestPointsStrategy<Segment<P>, P> for HaversineClosestPoints
where
P: Point<Scalar = f64> + PointMut + Default + Copy,
P::Cs: HasAngularUnits,
<P::Cs as CoordinateSystem>::Family: SameAs<SphericalFamily>,
{
type Out = P;
fn closest_points(&self, segment: &Segment<P>, point: &P) -> (Self::Out, Self::Out) {
let projected = great_circle::project(point, segment.start(), segment.end()).point;
(projected, *point)
}
}