Skip to content

Commit d115f16

Browse files
authored
Merge branch 'master' into finstuff
2 parents 8f93f28 + 83ad4d9 commit d115f16

File tree

3 files changed

+114
-1
lines changed

3 files changed

+114
-1
lines changed

DIRECTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@
265265
* Navigation
266266
* [Bearing](https://github.com/TheAlgorithms/Rust/blob/master/src/navigation/bearing.rs)
267267
* [Haversine](https://github.com/TheAlgorithms/Rust/blob/master/src/navigation/haversine.rs)
268+
* [Rhumbline](https://github.com/TheAlgorithms/Rust/blob/master/src/navigation/rhumbline.rs)
268269
* Number Theory
269270
* [Compute Totient](https://github.com/TheAlgorithms/Rust/blob/master/src/number_theory/compute_totient.rs)
270271
* [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: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
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 = if del_psi.abs() > 1e-12 {
19+
del_phi / del_psi
20+
} else {
21+
phi1.cos()
22+
};
23+
24+
(del_phi.powf(2.00) + (q * del_lambda).powf(2.00)).sqrt() * EARTH_RADIUS
25+
}
26+
27+
pub fn rhumb_bearing(lat1: f64, long1: f64, lat2: f64, long2: f64) -> f64 {
28+
let phi1 = lat1 * PI / 180.00;
29+
let phi2 = lat2 * PI / 180.00;
30+
let mut del_lambda = (long2 - long1) * PI / 180.00;
31+
32+
if del_lambda > PI {
33+
del_lambda -= 2.0 * PI;
34+
} else if del_lambda < -PI {
35+
del_lambda += 2.0 * PI;
36+
}
37+
38+
let del_psi = ((phi2 / 2.00 + PI / 4.00).tan() / (phi1 / 2.00 + PI / 4.00).tan()).ln();
39+
let bearing = del_lambda.atan2(del_psi) * 180.0 / PI;
40+
(bearing + 360.00) % 360.00
41+
}
42+
pub fn rhumb_destination(lat: f64, long: f64, distance: f64, bearing: f64) -> (f64, f64) {
43+
let del = distance / EARTH_RADIUS;
44+
let phi1 = lat * PI / 180.00;
45+
let lambda1 = long * PI / 180.00;
46+
let theta = bearing * PI / 180.00;
47+
48+
let del_phi = del * theta.cos();
49+
let phi2 = (phi1 + del_phi).clamp(-PI / 2.0, PI / 2.0);
50+
51+
let del_psi = ((phi2 / 2.00 + PI / 4.00).tan() / (phi1 / 2.0 + PI / 4.0).tan()).ln();
52+
let q = if del_psi.abs() > 1e-12 {
53+
del_phi / del_psi
54+
} else {
55+
phi1.cos()
56+
};
57+
58+
let del_lambda = del * theta.sin() / q;
59+
let lambda2 = lambda1 + del_lambda;
60+
61+
(phi2 * 180.00 / PI, lambda2 * 180.00 / PI)
62+
}
63+
64+
// TESTS
65+
#[cfg(test)]
66+
mod tests {
67+
use super::*;
68+
69+
#[test]
70+
fn test_rhumb_distance() {
71+
let distance = rhumb_dist(28.5416, 77.2006, 28.5457, 77.1928);
72+
assert!(distance > 700.00 && distance < 1000.0);
73+
}
74+
75+
#[test]
76+
fn test_rhumb_bearing() {
77+
let bearing = rhumb_bearing(28.5416, 77.2006, 28.5457, 77.1928);
78+
assert!((bearing - 300.0).abs() < 5.0);
79+
}
80+
81+
#[test]
82+
fn test_rhumb_destination_point() {
83+
let (lat, lng) = rhumb_destination(28.5457, 77.1928, 1000.00, 305.0);
84+
assert!((lat - 28.550).abs() < 0.010);
85+
assert!((lng - 77.1851).abs() < 0.010);
86+
}
87+
// edge cases
88+
89+
#[test]
90+
fn test_rhumb_distance_cross_antimeridian() {
91+
// Test when del_lambda > PI (line 12)
92+
let distance = rhumb_dist(0.0, 170.0, 0.0, -170.0);
93+
assert!(distance > 0.0);
94+
}
95+
96+
#[test]
97+
fn test_rhumb_distance_cross_antimeridian_negative() {
98+
// Test when del_lambda < -PI (line 14)
99+
let distance = rhumb_dist(0.0, -170.0, 0.0, 170.0);
100+
assert!(distance > 0.0);
101+
}
102+
103+
#[test]
104+
fn test_rhumb_distance_to_equator() {
105+
// Test when del_psi is near zero (line 21 - the else branch)
106+
let distance = rhumb_dist(0.0, 0.0, 0.0, 1.0);
107+
assert!(distance > 0.0);
108+
}
109+
}

0 commit comments

Comments
 (0)