Skip to content

Commit 0e9e30f

Browse files
Create vincenty.rs
In your mod.rs file, make sure to declare the additional modules: code // mod.rs pub mod bearing; pub mod haversine; pub mod vincenty; // Add the new module for Vincenty formula
1 parent 0dbaff5 commit 0e9e30f

File tree

1 file changed

+73
-0
lines changed

1 file changed

+73
-0
lines changed

src/navigation/vincenty.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// vincenty.rs
2+
const WGS84_A: f64 = 6378137.0; // Semi-major axis in meters
3+
const WGS84_B: f64 = 6356752.314245; // Semi-minor axis in meters
4+
const WGS84_F: f64 = 1.0 / 298.257223563; // Flattening
5+
6+
pub fn vincenty(lat1: f64, lon1: f64, lat2: f64, lon2: f64) -> f64 {
7+
let u1 = (1.0 - WGS84_F) * lat1.to_radians().tan();
8+
let u2 = (1.0 - WGS84_F) * lat2.to_radians().tan();
9+
let l = (lon2 - lon1).to_radians();
10+
11+
let sin_u1 = u1.sin();
12+
let cos_u1 = u1.cos();
13+
let sin_u2 = u2.sin();
14+
let cos_u2 = u2.cos();
15+
16+
let lambda = l;
17+
let (sin_lambda, cos_lambda) = (lambda.sin(), lambda.cos());
18+
19+
let mut sin_sigma;
20+
let mut cos_sigma;
21+
let mut cos_sq_alpha;
22+
let mut cos2_sigma_m;
23+
let mut sigma = 0.0;
24+
25+
let mut iteration_limit = 100;
26+
let mut lambda_prev = 0.0;
27+
28+
while (lambda - lambda_prev).abs() > 1e-12 && iteration_limit > 0 {
29+
let sin_lambda = lambda.sin();
30+
let cos_lambda = lambda.cos();
31+
32+
sin_sigma = ((cos_u2 * sin_lambda).powi(2) +
33+
(cos_u1 * sin_u2 - sin_u1 * cos_u2 * cos_lambda).powi(2)).sqrt();
34+
35+
if sin_sigma == 0.0 {
36+
return 0.0; // coincident points
37+
}
38+
39+
cos_sigma = sin_u1 * sin_u2 + cos_u1 * cos_u2 * cos_lambda;
40+
sigma = sin_sigma.atan2(cos_sigma);
41+
42+
let sin_alpha = cos_u1 * cos_u2 * sin_lambda;
43+
cos_sq_alpha = 1.0 - sin_alpha.powi(2);
44+
45+
cos2_sigma_m = if cos_sq_alpha == 0.0 {
46+
0.0
47+
} else {
48+
cos_u2 * cos_u1 * cos_lambda / cos_sq_alpha
49+
};
50+
51+
let c = WGS84_F / 16.0 * cos_sq_alpha * (4.0 + WGS84_F * (4.0 - 3.0 * cos_sq_alpha));
52+
53+
lambda_prev = lambda;
54+
lambda = l + (1.0 - c) * WGS84_F * sin_alpha * (sigma + c * sin_sigma * (cos2_sigma_m + c * cos_sigma * (-1.0 + 2.0 * cos2_sigma_m.powi(2))));
55+
56+
iteration_limit -= 1;
57+
}
58+
59+
if iteration_limit == 0 {
60+
return f64::NAN; // formula failed to converge
61+
}
62+
63+
let u_sq = cos_sq_alpha * (WGS84_A.powi(2) - WGS84_B.powi(2)) / WGS84_B.powi(2);
64+
let a = 1.0 + u_sq / 16384.0 * (4096.0 + u_sq * (-768.0 + u_sq * (320.0 - 175.0 * u_sq)));
65+
let b = u_sq / 1024.0 * (256.0 + u_sq * (-128.0 + u_sq * (74.0 - 47.0 * u_sq)));
66+
67+
let delta_sigma = b * sin_sigma * (cos2_sigma_m + b / 4.0 * (cos_sigma * (-1.0 + 2.0 * cos2_sigma_m.powi(2)) -
68+
b / 6.0 * cos2_sigma_m * (-3.0 + 4.0 * sin_sigma.powi(2)) * (-3.0 + 4.0 * cos2_sigma_m.powi(2))));
69+
70+
let s = WGS84_B * a * (sigma - delta_sigma);
71+
72+
s // distance in meters
73+
}

0 commit comments

Comments
 (0)