Skip to main content

geometry_strategy/spherical/
distance_cross_track.rs

1//! Spherical point-to-segment cross-track distance.
2//!
3//! Ports the strategy from
4//! `boost/geometry/strategies/spherical/distance_cross_track.hpp`.
5
6use geometry_cs::{CoordinateSystem, SphericalFamily};
7use geometry_model::Segment;
8use geometry_tag::SameAs;
9use geometry_trait::{Point, PointMut};
10
11use crate::distance::DistanceStrategy;
12use crate::normalise::HasAngularUnits;
13
14use super::great_circle;
15
16/// Great-circle distance from a point to the nearest location on a segment.
17#[derive(Debug, Clone, Copy)]
18pub struct CrossTrack {
19    /// Sphere radius in output distance units.
20    pub radius: f64,
21}
22
23impl CrossTrack {
24    /// Mean Earth radius used by the spherical Haversine strategy.
25    pub const EARTH: Self = Self {
26        radius: 6_372_795.0,
27    };
28    /// Unit sphere, returning angular distance in radians.
29    pub const UNIT: Self = Self { radius: 1.0 };
30}
31
32impl Default for CrossTrack {
33    fn default() -> Self {
34        Self::EARTH
35    }
36}
37
38impl<P> DistanceStrategy<P, Segment<P>> for CrossTrack
39where
40    P: Point<Scalar = f64> + PointMut + Default + Copy,
41    P::Cs: HasAngularUnits,
42    <P::Cs as CoordinateSystem>::Family: SameAs<SphericalFamily>,
43{
44    type Out = f64;
45    type Comparable = Self;
46
47    fn distance(&self, point: &P, segment: &Segment<P>) -> Self::Out {
48        great_circle::project(point, segment.start(), segment.end()).angular_distance * self.radius
49    }
50
51    fn comparable(&self) -> Self::Comparable {
52        *self
53    }
54}
55
56impl<P> DistanceStrategy<Segment<P>, P> for CrossTrack
57where
58    P: Point<Scalar = f64> + PointMut + Default + Copy,
59    P::Cs: HasAngularUnits,
60    <P::Cs as CoordinateSystem>::Family: SameAs<SphericalFamily>,
61{
62    type Out = f64;
63    type Comparable = Self;
64
65    fn distance(&self, segment: &Segment<P>, point: &P) -> Self::Out {
66        <Self as DistanceStrategy<P, Segment<P>>>::distance(self, point, segment)
67    }
68
69    fn comparable(&self) -> Self::Comparable {
70        *self
71    }
72}