Skip to content

Commit 0f00ed2

Browse files
committed
added rhumb line distance algorithm to navigation module
1 parent 379b934 commit 0f00ed2

File tree

3 files changed

+90
-1
lines changed

3 files changed

+90
-1
lines changed

DIRECTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@
262262
* Navigation
263263
* [Bearing](https://github.com/TheAlgorithms/Rust/blob/master/src/navigation/bearing.rs)
264264
* [Haversine](https://github.com/TheAlgorithms/Rust/blob/master/src/navigation/haversine.rs)
265+
* [Rhumbline](https://github.com/TheAlgorithms/Rust/blob/master/src/navigation/rhumbline.rs)
265266
* Number Theory
266267
* [Compute Totient](https://github.com/TheAlgorithms/Rust/blob/master/src/number_theory/compute_totient.rs)
267268
* [Euler Totient](https://github.com/TheAlgorithms/Rust/blob/master/src/number_theory/euler_totient.rs)

src/navigation/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
mod bearing;
22
mod haversine;
3-
3+
mod rhumbline;
44
pub use self::bearing::bearing;
55
pub use self::haversine::haversine;
6+
pub use self::rhumbline::rhumb_bearing;
7+
pub use self::rhumbline::rhumb_destination;
8+
pub use self::rhumbline::rhumb_dist;

src/navigation/rhumbline.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
use std::f64::consts::PI;
2+
3+
const EARTH_RADIUS: f64 = 6371000.0;
4+
5+
pub fn rhumb_dist(lat1: f64, long1: f64, lat2: f64, long2: f64) -> f64 {
6+
let phi1 = lat1 * PI / 180.00;
7+
let phi2 = lat2 * PI / 180.00;
8+
let del_phi = phi2 - phi1;
9+
let mut del_lambda = (long2 - long1) * PI / 180.00;
10+
11+
if del_lambda > PI {
12+
del_lambda -= 2.00 * PI;
13+
} else if del_lambda < -PI {
14+
del_lambda += 2.00 * PI;
15+
}
16+
17+
let del_psi = ((phi2 / 2.00 + PI / 4.00).tan() / (phi1 / 2.00 + PI / 4.00).tan()).ln();
18+
let q = match del_psi.abs() > 1e-12 {
19+
true => del_phi / del_psi,
20+
false => phi1.cos(),
21+
};
22+
23+
(del_phi.powf(2.00) + (q * del_lambda).powf(2.00)).sqrt() * EARTH_RADIUS
24+
}
25+
26+
pub fn rhumb_bearing(lat1: f64, long1: f64, lat2: f64, long2: f64) -> f64 {
27+
let phi1 = lat1 * PI / 180.00;
28+
let phi2 = lat2 * PI / 180.00;
29+
let mut del_lambda = (long2 - long1) * PI / 180.00;
30+
31+
if del_lambda > PI {
32+
del_lambda -= 2.00 * PI;
33+
} else if del_lambda < -PI {
34+
del_lambda += 2.00 * PI;
35+
}
36+
37+
let del_psi = ((phi2 / 2.00 + PI / 4.00).tan() / (phi1 / 2.00 + PI / 4.00).tan()).ln();
38+
let bearing = del_lambda.atan2(del_psi) * 180.0 / PI;
39+
(bearing + 360.00) % 360.00
40+
}
41+
pub fn rhumb_destination(lat: f64, long: f64, distance: f64, bearing: f64) -> (f64, f64) {
42+
let del = distance / EARTH_RADIUS;
43+
let phi1 = lat * PI / 180.00;
44+
let lambda1 = long * PI / 180.00;
45+
let theta = bearing * PI / 180.00;
46+
47+
let del_phi = del * theta.cos();
48+
let phi2 = (phi1 + del_phi).clamp(-PI / 2.0, PI / 2.0);
49+
50+
let del_psi = ((phi2 / 2.00 + PI / 4.00).tan() / (phi1 / 2.0 + PI / 4.0).tan()).ln();
51+
let q = match del_psi.abs() > 1e-12 {
52+
true => del_phi / del_psi,
53+
false => phi1.cos(),
54+
};
55+
56+
let del_lambda = del * theta.sin() / q;
57+
let lambda2 = lambda1 + del_lambda;
58+
59+
(phi2 * 180.00 / PI, lambda2 * 180.00 / PI)
60+
}
61+
62+
//TESTS
63+
#[cfg(test)]
64+
mod tests {
65+
use super::*;
66+
67+
#[test]
68+
fn test_rhumb_distance() {
69+
let distance = rhumb_dist(28.5416, 77.2006, 28.5457, 77.1928);
70+
assert!(distance > 700.00 && distance < 1000.0);
71+
}
72+
73+
#[test]
74+
fn test_rhumb_bearing() {
75+
let bearing = rhumb_bearing(28.5416, 77.2006, 28.5457, 77.1928);
76+
assert!((bearing - 300.0).abs() < 5.0);
77+
}
78+
79+
#[test]
80+
fn test_rhumb_destination_point() {
81+
let (lat, lng) = rhumb_destination(28.5457, 77.1928, 1000.00, 305.0);
82+
assert!((lat - 28.550).abs() < 0.010);
83+
assert!((lng - 77.1851).abs() < 0.010);
84+
}
85+
}

0 commit comments

Comments
 (0)