Computes the shortest distance along the surface of the spheroid between two points.
188 double lambda = (b->
lon - a->
lon);
189 double f = spheroid->
f;
190 double omf = 1 - spheroid->
f;
192 double cos_u1, cos_u2;
193 double sin_u1, sin_u2;
194 double big_a, big_b, delta_sigma;
195 double alpha, sin_alpha, cos_alphasq, c;
196 double sigma, sin_sigma, cos_sigma, cos2_sigma_m, sqrsin_sigma, last_lambda, omega;
197 double cos_lambda, sin_lambda;
207 u1 = atan(omf * tan(a->
lat));
210 u2 = atan(omf * tan(b->
lat));
217 cos_lambda = cos(lambda);
218 sin_lambda = sin(lambda);
219 sqrsin_sigma =
POW2(cos_u2 * sin_lambda) +
220 POW2((cos_u1 * sin_u2 - sin_u1 * cos_u2 * cos_lambda));
221 sin_sigma = sqrt(sqrsin_sigma);
222 cos_sigma = sin_u1 * sin_u2 + cos_u1 * cos_u2 * cos_lambda;
223 sigma = atan2(sin_sigma, cos_sigma);
224 sin_alpha = cos_u1 * cos_u2 * sin_lambda / sin(sigma);
227 if ( sin_alpha > 1.0 )
229 else if ( sin_alpha < -1.0 )
230 alpha = -1.0 * M_PI_2;
232 alpha = asin(sin_alpha);
234 cos_alphasq =
POW2(cos(alpha));
235 cos2_sigma_m = cos(sigma) - (2.0 * sin_u1 * sin_u2 / cos_alphasq);
238 if ( cos2_sigma_m > 1.0 )
240 if ( cos2_sigma_m < -1.0 )
243 c = (f / 16.0) * cos_alphasq * (4.0 + f * (4.0 - 3.0 * cos_alphasq));
244 last_lambda = lambda;
245 lambda = omega + (1.0 - c) * f * sin(alpha) * (sigma + c * sin(sigma) *
246 (cos2_sigma_m + c * cos(sigma) * (-1.0 + 2.0 *
POW2(cos2_sigma_m))));
249 while ( (i < 999) && (lambda != 0.0) && (fabs((last_lambda - lambda)/lambda) > 1.0e-9) );
254 delta_sigma = big_b * sin_sigma * (cos2_sigma_m + (big_b / 4.0) * (cos_sigma * (-1.0 + 2.0 *
POW2(cos2_sigma_m)) -
255 (big_b / 6.0) * cos2_sigma_m * (-3.0 + 4.0 * sqrsin_sigma) * (-3.0 + 4.0 *
POW2(cos2_sigma_m))));
257 distance = spheroid->
b * big_a * (sigma - delta_sigma);
260 if ( distance != distance )
262 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);
static double spheroid_big_b(double u2)
double sphere_distance(const GEOGRAPHIC_POINT *s, const GEOGRAPHIC_POINT *e)
Given two points on a unit sphere, calculate their distance apart in radians.
static double spheroid_big_a(double u2)
static double spheroid_mu2(double alpha, const SPHEROID *s)
Datum distance(PG_FUNCTION_ARGS)
int geographic_point_equals(const GEOGRAPHIC_POINT *g1, const GEOGRAPHIC_POINT *g2)
void lwerror(const char *fmt,...)
Write a notice out to the error handler.