geometry_algorithm/
rhumb.rs1use geometry_strategy::{
8 AzimuthStrategy, DestinationStrategy, DistanceStrategy, LengthStrategy, Rhumb,
9};
10use geometry_trait::{Geometry, Linestring, Point};
11
12#[inline]
14#[must_use]
15pub fn rhumb_distance<A, B>(first: &A, second: &B) -> f64
16where
17 A: Geometry,
18 B: Geometry,
19 Rhumb: DistanceStrategy<A, B, Out = f64>,
20{
21 rhumb_distance_with(first, second, Rhumb::default())
22}
23
24#[inline]
26#[must_use]
27#[allow(
28 clippy::needless_pass_by_value,
29 reason = "rhumb strategies are small Copy radius configurations"
30)]
31pub fn rhumb_distance_with<A, B, S>(first: &A, second: &B, strategy: S) -> S::Out
32where
33 A: Geometry,
34 B: Geometry,
35 S: DistanceStrategy<A, B>,
36{
37 strategy.distance(first, second)
38}
39
40#[inline]
42#[must_use]
43pub fn rhumb_azimuth<P1, P2>(first: &P1, second: &P2) -> f64
44where
45 P1: Point,
46 P2: Point,
47 Rhumb: AzimuthStrategy<P1, P2, Out = f64>,
48{
49 rhumb_azimuth_with(first, second, Rhumb::default())
50}
51
52#[inline]
54#[must_use]
55#[allow(
56 clippy::needless_pass_by_value,
57 reason = "rhumb strategies are small Copy radius configurations"
58)]
59pub fn rhumb_azimuth_with<P1, P2, S>(first: &P1, second: &P2, strategy: S) -> S::Out
60where
61 P1: Point,
62 P2: Point,
63 S: AzimuthStrategy<P1, P2>,
64{
65 strategy.azimuth(first, second)
66}
67
68#[inline]
70#[must_use]
71pub fn rhumb_destination<P>(origin: &P, bearing: f64, distance: f64) -> PointOutput<P>
72where
73 P: Point,
74 Rhumb: DestinationStrategy<P>,
75{
76 rhumb_destination_with(origin, bearing, distance, Rhumb::default())
77}
78
79#[inline]
81#[must_use]
82#[allow(
83 clippy::needless_pass_by_value,
84 reason = "rhumb strategies are small Copy radius configurations"
85)]
86pub fn rhumb_destination_with<P, S>(
87 origin: &P,
88 bearing: f64,
89 distance: f64,
90 strategy: S,
91) -> S::Output
92where
93 P: Point,
94 S: DestinationStrategy<P>,
95{
96 strategy.destination(origin, bearing, distance)
97}
98
99#[inline]
101#[must_use]
102pub fn rhumb_length<L>(line: &L) -> f64
103where
104 L: Linestring,
105 Rhumb: LengthStrategy<L, Out = f64>,
106{
107 rhumb_length_with(line, Rhumb::default())
108}
109
110#[inline]
112#[must_use]
113#[allow(
114 clippy::needless_pass_by_value,
115 reason = "rhumb strategies are small Copy radius configurations"
116)]
117pub fn rhumb_length_with<L, S>(line: &L, strategy: S) -> S::Out
118where
119 L: Geometry,
120 S: LengthStrategy<L>,
121{
122 strategy.length(line)
123}
124
125type PointOutput<P> = <Rhumb as DestinationStrategy<P>>::Output;
126
127#[cfg(test)]
128mod tests {
129 use geometry_cs::{Degree, Spherical};
130 use geometry_model::{Linestring, Point2D};
131 use geometry_trait::Point as _;
132
133 use super::*;
134
135 #[test]
136 fn named_entries_share_one_metric() {
137 type P = Point2D<f64, Spherical<Degree>>;
138 let start = P::new(0.0, 0.0);
139 let east = P::new(1.0, 0.0);
140 let distance = rhumb_distance(&start, &east);
141 assert!((rhumb_azimuth(&start, &east) - core::f64::consts::FRAC_PI_2).abs() < 1e-12);
142 let endpoint = rhumb_destination(&start, core::f64::consts::FRAC_PI_2, distance);
143 assert!((endpoint.get::<0>() - 1.0).abs() < 1e-10);
144 let line = Linestring::from_vec(alloc::vec![start, east]);
145 assert!((rhumb_length(&line) - distance).abs() < 1e-9);
146 }
147}