Due to the lapse in federal government funding, NASA is not updating this website. We sincerely regret this inconvenience.
NASA Logo
Ocean Color Science Software

ocssw V2022
vincenty.c
Go to the documentation of this file.
1 #include <math.h>
2 #include <stdbool.h>
3 #include <stdio.h>
4 
5 #ifndef VINCENTY_TOLERANCE
6 
7 #define VINCENTY_TOLERANCE 1e-12
8 #endif
9 
10 #ifndef VINCENTY_MAX_LOOP
11 
12 #define VINCENTY_MAX_LOOP 1e3
13 #endif
14 
15 #ifndef USE_HELMERTS
16 
20 #define USE_HELMERTS 1
21 #endif
22 
23 #define pi 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899L
24 #define flattening (1 / 298.257223563) // flattening of the ellipsoid
25 #define semimajor 6378137.0 // abbreviated a, radius at the equator
26 #define semiminor ((1 - flattening) * semimajor) // abbreviated b, radius at the poles
27 
28 inline static double deg2rad(const double deg) {
29  return (pi * deg / 180.0);
30 }
31 //inline static double rad2deg(const double rad) {
32 // return (rad * 180.0 / pi);
33 //}
34 
35 inline static void vincenty_AB_equations(const double u2, double *A, double *B) {
36 #ifdef USE_HELMERTS
37  const double k1 = (sqrt(1 + u2) - 1) / (sqrt(1 + u2) + 1);
38  *A = (1 + 1 / 4 * pow(k1, 2));
39  *B = k1 * (1 - 3 / 8 * pow(k1, 2));
40 # else
41  *A = 1 + (u2 / 16384) * (4096 + u2 * (-768 + u2 * (320 - 175 * u2)));
42  *B = (u2 / 1024) * (256 + u2 * (-128 + u2 * (74 - 47 * u2)));
43 #endif
44 }
45 
46 // https://en.wikipedia.org/wiki/Vincenty's_formulae#Inverse_problem
47 double vincenty_distance(double lat1, double lon1, double lat2, double lon2) {
48  if (lat1 == lat2 && lon1 == lon2) { // returns -nan in this case
49  return 0;
50  }
51  lat1 = deg2rad(lat1);
52  lon1 = deg2rad(lon1);
53  lat2 = deg2rad(lat2);
54  lon2 = deg2rad(lon2);
55 
56  // reduced latitudes (latitudes on the auxiliary sphere)
57  const double U1 = atan((1 - flattening) * tan(lat1));
58  const double U2 = atan((1 - flattening) * tan(lat2));
59  const double sin_U1 = sin(U1), cos_U1 = cos(U1);
60  const double sin_U2 = sin(U2), cos_U2 = cos(U2);
61  const double L = lon2 - lon1;
62 
63  double lambda = L;
64 
65  double old_lambda, sin_sigma, cos_sigma, sigma, sin_alpha, cos2_alpha, cos_2sigmam = 0, C;
66  int loop_count = 0;
67  do {
68  old_lambda = lambda;
69  const double cos_lambda = cos(lambda), sin_lambda = sin(lambda);
70  sin_sigma = sqrt(pow(cos_U2 * sin_lambda, 2) + pow(cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda, 2));
71  cos_sigma = sin_U1 * sin_U2 + cos_U1 * cos_U2 * cos_lambda;
72  sigma = atan2(sin_sigma, cos_sigma);
73  sin_alpha = (cos_U1 * cos_U2 * sin_lambda) / sin_sigma;
74  cos2_alpha = 1 - pow(sin_alpha, 2);
75  if (cos2_alpha == 0) {
76  lambda = L + flattening * sin_alpha * sigma;
77  } else {
78  cos_2sigmam = cos_sigma - (2 * sin_U1 * sin_U2) / cos2_alpha;
79  C = (flattening / 16) * cos2_alpha * (4 + flattening * (4 - 3 * cos2_alpha));
80  lambda = L + (1 - C) * flattening * sin_alpha * (sigma + C * sin_sigma * (cos_2sigmam + C * cos_sigma * (-1 + 2 * cos_2sigmam)));
81  }
82  } while (fabs(lambda - old_lambda) > VINCENTY_TOLERANCE && ++loop_count < VINCENTY_MAX_LOOP);
83 
84  const double u2 = cos2_alpha * (pow(semimajor, 2) - pow(semiminor, 2)) / pow(semiminor, 2);
85  double A, B;
86  vincenty_AB_equations(u2, &A, &B);
87  const double cos2_2sigmam = pow(cos_2sigmam, 2);
88  const double delta_sigma = B * sin_sigma * (cos_2sigmam + 1 / 4 * B * (-1 + 2 * cos2_2sigmam) - 1 / 6 * B * cos_2sigmam * (-3 + 4 * pow(sin_sigma, 2)) * (-3 + 4 * cos2_2sigmam));
89  const double s = semiminor * A * (sigma - delta_sigma);
90 
91  // I think this stuff calculates the bearings, not required for this function but useful for a geolib.
92 // const double cos_lambda = cos(lambda);
93 // const double sin_lambda = sin(lambda);
94 // const double cosU1_sin_U2 = cos_U1 * sin_U2;
95 // const double alpha1 = atan((cos_U2 * sin_lambda) / (cosU1_sin_U2 - (sin_U1 * cos_U2 * cos_lambda)));
96 // const double alpha2 = atan((cos_U1 * sin_lambda) / ((-sin_U1 * cos_U2) - (cosU1_sin_U2 * cos_lambda)));
97 
98 // printf("%f, %f, %f, %f = %.64f\n", rad2deg(lat1), rad2deg(lon1), rad2deg(lat2), rad2deg(lon2), s);
99  return s;
100 }
#define VINCENTY_MAX_LOOP
Used to prevent infinite loops caused by non-convergence.
Definition: vincenty.c:12
#define L(lambda, T)
Definition: PreprocessP.h:185
const double C
Definition: calc_par.c:102
const double deg2rad
#define flattening
Definition: vincenty.c:24
#define VINCENTY_TOLERANCE
Used to control the accuracy requirement. 1e−12 corresponds to approximately 0.06mm.
Definition: vincenty.c:7
double vincenty_distance(double lat1, double lon1, double lat2, double lon2)
Calculate geographical distances using Vincenty's algorithm.
Definition: vincenty.c:47
data_t lambda[NROOTS+1]
Definition: decode_rs.h:75
const float A
Definition: calc_par.c:100
#define pi
Definition: vincenty.c:23
const float B
Definition: calc_par.c:101
#define fabs(a)
Definition: misc.h:93
#define semimajor
Definition: vincenty.c:25
data_t s[NROOTS]
Definition: decode_rs.h:75
#define semiminor
Definition: vincenty.c:26