Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 83ad4d9

Browse files
feat: Added Rhumb Line Distance algorithm to navigation module (TheAlgorithms#934)
1 parent 379b934 commit 83ad4d9

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
@@ -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: 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)

AltStyle によって変換されたページ (->オリジナル) /