44 s->e_sq = (a*a - b*b)/(a*a);
45 s->radius = (2.0 * a + b ) / 3.0;
49 static double spheroid_mu2(
double alpha,
const SPHEROID *
s)
51 double b2 =
POW2(
s->b);
52 return POW2(cos(alpha)) * (
POW2(
s->a) - b2) / b2;
55 static double spheroid_big_a(
double u2)
57 return 1.0 + (u2 / 16384.0) * (4096.0 + u2 * (-768.0 + u2 * (320.0 - 175.0 * u2)));
60 static double spheroid_big_b(
double u2)
62 return (u2 / 1024.0) * (256.0 + u2 * (-128.0 + u2 * (74.0 - 47.0 * u2)));
81 struct geod_geodesic gd;
87 geod_init(&gd, spheroid->
a, spheroid->
f);
88 double lat1 = a->
lat * 180.0 / M_PI;
89 double lon1 = a->
lon * 180.0 / M_PI;
90 double lat2 = b->
lat * 180.0 / M_PI;
91 double lon2 = b->
lon * 180.0 / M_PI;
93 geod_inverse(&gd, lat1, lon1, lat2, lon2, &s12, 0, 0);
107 struct geod_geodesic gd;
108 geod_init(&gd, spheroid->
a, spheroid->
f);
109 double lat1 = a->
lat * 180.0 / M_PI;
110 double lon1 = a->
lon * 180.0 / M_PI;
111 double lat2 = b->
lat * 180.0 / M_PI;
112 double lon2 = b->
lon * 180.0 / M_PI;
114 geod_inverse(&gd, lat1, lon1, lat2, lon2, 0, &azi1, 0);
115 return azi1 * M_PI / 180.0;
130 struct geod_geodesic gd;
131 geod_init(&gd, spheroid->
a, spheroid->
f);
132 double lat1 =
r->lat * 180.0 / M_PI;
133 double lon1 =
r->lon * 180.0 / M_PI;
135 geod_direct(&gd, lat1, lon1, azimuth * 180.0 / M_PI,
distance, &lat2, &lon2, 0);
136 g->
lat = lat2 * M_PI / 180.0;
137 g->
lon = lon2 * M_PI / 180.0;
148 struct geod_geodesic gd;
149 geod_init(&gd, spheroid->
a, spheroid->
f);
150 struct geod_polygon poly;
151 geod_polygon_init(&poly, 0);
157 for ( i = 0; i < pa->
npoints - 1; i++ )
160 geod_polygon_addpoint(&gd, &poly, p.
y, p.
x);
161 LWDEBUGF(4,
"geod_polygon_addpoint %d: %.12g %.12g", i, p.
y, p.
x);
163 i = geod_polygon_compute(&gd, &poly, 0, 1, &area, 0);
166 lwerror(
"ptarray_area_spheroid: different number of points %d vs %d",
169 LWDEBUGF(4,
"geod_polygon_compute area: %.12g", area);
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) );
256 u2 = spheroid_mu2(alpha, spheroid);
257 big_a = spheroid_big_a(u2);
258 big_b = spheroid_big_b(u2);
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);
290 double lambda =
s->lon -
r->lon;
291 double omf = 1 - spheroid->
f;
292 double u1 = atan(omf * tan(
r->lat));
293 double cos_u1 = cos(u1);
294 double sin_u1 = sin(u1);
295 double u2 = atan(omf * tan(
s->lat));
296 double cos_u2 = cos(u2);
297 double sin_u2 = sin(u2);
299 double omega = lambda;
300 double alpha, sigma, sin_sigma, cos_sigma, cos2_sigma_m, sqr_sin_sigma, last_lambda;
301 double sin_alpha, cos_alphasq, C, alphaFD;
304 sqr_sin_sigma =
POW2(cos_u2 * sin(lambda)) +
305 POW2((cos_u1 * sin_u2 - sin_u1 * cos_u2 * cos(lambda)));
306 sin_sigma = sqrt(sqr_sin_sigma);
307 cos_sigma = sin_u1 * sin_u2 + cos_u1 * cos_u2 * cos(lambda);
308 sigma = atan2(sin_sigma, cos_sigma);
309 sin_alpha = cos_u1 * cos_u2 * sin(lambda) / sin(sigma);
312 if ( sin_alpha > 1.0 )
314 else if ( sin_alpha < -1.0 )
315 alpha = -1.0 * M_PI_2;
317 alpha = asin(sin_alpha);
319 cos_alphasq =
POW2(cos(alpha));
320 cos2_sigma_m = cos(sigma) - (2.0 * sin_u1 * sin_u2 / cos_alphasq);
323 if ( cos2_sigma_m > 1.0 )
325 if ( cos2_sigma_m < -1.0 )
328 C = (spheroid->
f / 16.0) * cos_alphasq * (4.0 + spheroid->
f * (4.0 - 3.0 * cos_alphasq));
329 last_lambda = lambda;
330 lambda = omega + (1.0 - C) * spheroid->
f * sin(alpha) * (sigma + C * sin(sigma) *
331 (cos2_sigma_m + C * cos(sigma) * (-1.0 + 2.0 *
POW2(cos2_sigma_m))));
334 while ( (i < 999) && (lambda != 0) && (fabs((last_lambda - lambda) / lambda) > 1.0e-9) );
336 alphaFD = atan2((cos_u2 * sin(lambda)),
337 (cos_u1 * sin_u2 - sin_u1 * cos_u2 * cos(lambda)));
340 alphaFD = alphaFD + 2.0 * M_PI;
342 if (alphaFD > 2.0 * M_PI)
344 alphaFD = alphaFD - 2.0 * M_PI;
366 double omf = 1 - spheroid->
f;
367 double tan_u1 = omf * tan(
r->lat);
368 double u1 = atan(tan_u1);
369 double sigma, last_sigma, delta_sigma, two_sigma_m;
370 double sigma1, sin_alpha, alpha, cos_alphasq;
372 double lat2, lambda, lambda2, C, omega;
377 azimuth = azimuth + M_PI * 2.0;
379 if (azimuth > (M_PI * 2.0))
381 azimuth = azimuth - M_PI * 2.0;
384 sigma1 = atan2(tan_u1, cos(azimuth));
385 sin_alpha = cos(u1) * sin(azimuth);
386 alpha = asin(sin_alpha);
387 cos_alphasq = 1.0 -
POW2(sin_alpha);
389 u2 = spheroid_mu2(alpha, spheroid);
390 A = spheroid_big_a(u2);
391 B = spheroid_big_b(u2);
396 two_sigma_m = 2.0 * sigma1 + sigma;
397 delta_sigma = B * sin(sigma) * (cos(two_sigma_m) + (B / 4.0) * (cos(sigma) * (-1.0 + 2.0 *
POW2(cos(two_sigma_m)) - (B / 6.0) * cos(two_sigma_m) * (-3.0 + 4.0 *
POW2(sin(sigma))) * (-3.0 + 4.0 *
POW2(cos(two_sigma_m))))));
399 sigma = (
distance / (spheroid->
b * A)) + delta_sigma;
402 while (i < 999 && fabs((last_sigma - sigma) / sigma) > 1.0e-9);
404 lat2 = atan2((sin(u1) * cos(sigma) + cos(u1) * sin(sigma) *
405 cos(azimuth)), (omf * sqrt(
POW2(sin_alpha) +
406 POW2(sin(u1) * sin(sigma) - cos(u1) * cos(sigma) *
408 lambda = atan2((sin(sigma) * sin(azimuth)), (cos(u1) * cos(sigma) -
409 sin(u1) * sin(sigma) * cos(azimuth)));
410 C = (spheroid->
f / 16.0) * cos_alphasq * (4.0 + spheroid->
f * (4.0 - 3.0 * cos_alphasq));
411 omega = lambda - (1.0 - C) * spheroid->
f * sin_alpha * (sigma + C * sin(sigma) *
412 (cos(two_sigma_m) + C * cos(sigma) * (-1.0 + 2.0 *
POW2(cos(two_sigma_m)))));
413 lambda2 =
r->lon + omega;
420 static inline double spheroid_prime_vertical_radius_of_curvature(
double latitude,
const SPHEROID *spheroid)
422 return spheroid->
a / (sqrt(1.0 - spheroid->
e_sq *
POW2(sin(latitude))));
425 static inline double spheroid_parallel_arc_length(
double latitude,
double deltaLongitude,
const SPHEROID *spheroid)
427 return spheroid_prime_vertical_radius_of_curvature(latitude, spheroid)
444 double z0 = (northEastCorner->
lon - southWestCorner->
lon) *
POW2(spheroid->
b) / 2.0;
445 double e = sqrt(spheroid->
e_sq);
446 double sinPhi1 = sin(southWestCorner->
lat);
447 double sinPhi2 = sin(northEastCorner->
lat);
448 double t1p1 = sinPhi1 / (1.0 - spheroid->
e_sq * sinPhi1 * sinPhi1);
449 double t1p2 = sinPhi2 / (1.0 - spheroid->
e_sq * sinPhi2 * sinPhi2);
450 double oneOver2e = 1.0 / (2.0 * e);
451 double t2p1 = oneOver2e * log((1.0 + e * sinPhi1) / (1.0 - e * sinPhi1));
452 double t2p2 = oneOver2e * log((1.0 + e * sinPhi2) / (1.0 - e * sinPhi2));
453 return z0 * (t1p2 + t2p2) - z0 * (t1p1 + t2p1);
463 double deltaLng, baseArea, topArea;
464 double bE, tE, ratio, sign;
469 mL.
lat = latitude_min;
475 baseArea = spheroid_boundingbox_area(&mL, &nR, spheroid);
476 LWDEBUGF(4,
"baseArea %.12g", baseArea);
484 topArea = spheroid_boundingbox_area(&mL, &nR, spheroid);
485 LWDEBUGF(4,
"topArea %.12g", topArea);
488 LWDEBUGF(4,
"deltaLng %.12g", deltaLng);
489 bE = spheroid_parallel_arc_length(A.
lat, deltaLng, spheroid);
490 tE = spheroid_parallel_arc_length(B.
lat, deltaLng, spheroid);
494 ratio = (bE + tE)/tE;
496 return (baseArea + topArea / ratio) * sign;
507 double delta_lon_tolerance;
520 lwerror(
"ptarray_area_spheroid: cannot handle ptarray that crosses equator");
523 if ( gbox2d.
ymax < 0.0 )
531 delta_lon_tolerance = (90.0 / (fabs(gbox2d.
ymin) / 8.0) - 2.0) / 10000.0;
536 delta_lon_tolerance = (90.0 / (fabs(gbox2d.
ymax) / 8.0) - 2.0) / 10000.0;
544 for ( i = 1; i < pa->
npoints; i++ )
547 double strip_area = 0.0;
548 double delta_lon = 0.0;
564 LWDEBUGF(4,
"in_south %d", in_south);
573 shift = (M_PI - a1.
lon) + 0.088;
575 shift = (M_PI - b1.
lon) + 0.088;
586 delta_lon = fabs(b1.
lon - a1.
lon);
589 LWDEBUGF(4,
"delta_lon %.18g", delta_lon);
590 LWDEBUGF(4,
"delta_lon_tolerance %.18g", delta_lon_tolerance);
592 if ( delta_lon > 0.0 )
594 if ( delta_lon < delta_lon_tolerance )
596 strip_area = spheroid_striparea(&a1, &b1, latitude_min, spheroid);
597 LWDEBUGF(4,
"strip_area %.12g", strip_area);
603 double step = floor(delta_lon / delta_lon_tolerance);
605 double pDistance = 0.0;
612 while (pDistance < (
distance - step * 1.01))
617 LWDEBUGF(4,
" azimuth %.12g", azimuth);
618 pDistance = pDistance + step;
619 LWDEBUGF(4,
" pDistance %.12g", pDistance);
621 strip_area = spheroid_striparea(&p, &q, latitude_min, spheroid);
622 LWDEBUGF(4,
" strip_area %.12g", strip_area);
628 strip_area = spheroid_striparea(&p, &b1, latitude_min, spheroid);
679 for ( i = 1; i < poly->
nrings; i++ )
693 for ( i = 0; i < col->
ngeoms; i++ )
int ptarray_calculate_gbox_cartesian(const POINTARRAY *pa, GBOX *gbox)
Calculate box (x/y) and add values to gbox.
int getPoint2d_p(const POINTARRAY *pa, uint32_t n, POINT2D *point)
lwflags_t lwflags(int hasz, int hasm, int geodetic)
Construct a new flags bitmask.
#define LW_TRUE
Return types for functions with status returns.
#define SIGNUM(n)
Macro that returns: -1 if n < 0, 1 if n > 0, 0 if n == 0.
void point_shift(GEOGRAPHIC_POINT *p, double shift)
Shift a point around by a number of radians.
void geographic_point_init(double lon, double lat, GEOGRAPHIC_POINT *g)
Initialize a geographic point.
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)
int crosses_dateline(const GEOGRAPHIC_POINT *s, const GEOGRAPHIC_POINT *e)
#define deg2rad(d)
Conversion functions.
#define LWDEBUGF(level, msg,...)
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
double deltaLongitude(double azimuth, double sigma, double tsm, SPHEROID *sphere)
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
static double ptarray_area_spheroid(const POINTARRAY *pa, const SPHEROID *spheroid)
double lwgeom_area_spheroid(const LWGEOM *lwgeom, const SPHEROID *spheroid)
Calculate the area of an LWGEOM.
double spheroid_distance(const GEOGRAPHIC_POINT *a, const GEOGRAPHIC_POINT *b, const SPHEROID *spheroid)
Computes the shortest distance along the surface of the spheroid between two points,...
void spheroid_init(SPHEROID *s, double a, double b)
Initialize spheroid object based on major and minor axis.
int spheroid_project(const GEOGRAPHIC_POINT *r, const SPHEROID *spheroid, double distance, double azimuth, GEOGRAPHIC_POINT *g)
Given a location, an azimuth and a distance, computes the location of the projected point.
double spheroid_direction(const GEOGRAPHIC_POINT *a, const GEOGRAPHIC_POINT *b, const SPHEROID *spheroid)
Computes the forward azimuth of the geodesic joining two points on the spheroid, using the inverse ge...
static double distance(double x1, double y1, double x2, double y2)
Point in spherical coordinates on the world.