Computes the shortest distance along the surface of the spheroid between two points.
193 double lambda = (b->
lon - a->
lon);
194 double f = spheroid->
f;
195 double omf = 1 - spheroid->
f;
197 double cos_u1, cos_u2;
198 double sin_u1, sin_u2;
199 double big_a, big_b, delta_sigma;
200 double alpha, sin_alpha, cos_alphasq, c;
201 double sigma, sin_sigma, cos_sigma, cos2_sigma_m, sqrsin_sigma, last_lambda, omega;
202 double cos_lambda, sin_lambda;
212 u1 = atan(omf * tan(a->
lat));
215 u2 = atan(omf * tan(b->
lat));
222 cos_lambda = cos(lambda);
223 sin_lambda = sin(lambda);
224 sqrsin_sigma =
POW2(cos_u2 * sin_lambda) +
225 POW2((cos_u1 * sin_u2 - sin_u1 * cos_u2 * cos_lambda));
226 sin_sigma = sqrt(sqrsin_sigma);
227 cos_sigma = sin_u1 * sin_u2 + cos_u1 * cos_u2 * cos_lambda;
228 sigma = atan2(sin_sigma, cos_sigma);
229 sin_alpha = cos_u1 * cos_u2 * sin_lambda / sin(sigma);
232 if ( sin_alpha > 1.0 )
234 else if ( sin_alpha < -1.0 )
235 alpha = -1.0 * M_PI_2;
237 alpha = asin(sin_alpha);
239 cos_alphasq =
POW2(cos(alpha));
240 cos2_sigma_m = cos(sigma) - (2.0 * sin_u1 * sin_u2 / cos_alphasq);
243 if ( cos2_sigma_m > 1.0 )
245 if ( cos2_sigma_m < -1.0 )
248 c = (f / 16.0) * cos_alphasq * (4.0 + f * (4.0 - 3.0 * cos_alphasq));
249 last_lambda = lambda;
250 lambda = omega + (1.0 - c) * f * sin(alpha) * (sigma + c * sin(sigma) *
251 (cos2_sigma_m + c * cos(sigma) * (-1.0 + 2.0 *
POW2(cos2_sigma_m))));
254 while ( (i < 999) && (lambda != 0.0) && (fabs((last_lambda - lambda)/lambda) > 1.0e-9) );
259 delta_sigma = big_b * sin_sigma * (cos2_sigma_m + (big_b / 4.0) * (cos_sigma * (-1.0 + 2.0 *
POW2(cos2_sigma_m)) -
260 (big_b / 6.0) * cos2_sigma_m * (-3.0 + 4.0 * sqrsin_sigma) * (-3.0 + 4.0 *
POW2(cos2_sigma_m))));
262 distance = spheroid->
b * big_a * (sigma - delta_sigma);
267 lwerror(
"spheroid_distance returned NaN: (%.20g %.20g) (%.20g %.20g) a = %.20g b = %.20g",a->
lat, a->
lon, b->
lat, b->
lon, spheroid->
a, spheroid->
b);
double sphere_distance(const GEOGRAPHIC_POINT *s, const GEOGRAPHIC_POINT *e)
Given two points on a unit sphere, calculate their distance apart in radians.
int geographic_point_equals(const GEOGRAPHIC_POINT *g1, const GEOGRAPHIC_POINT *g2)
Datum distance(PG_FUNCTION_ARGS)
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
static double spheroid_big_b(double u2)
static double spheroid_big_a(double u2)
static double spheroid_mu2(double alpha, const SPHEROID *s)