44 s->e_sq = (a*a - b*b)/(a*a);
45 s->radius = (2.0 * a + b ) / 3.0;
51 double b2 =
POW2(
s->b);
52 return POW2(cos(alpha)) * (
POW2(
s->a) - b2) / b2;
57 return 1.0 + (u2 / 16384.0) * (4096.0 + u2 * (-768.0 + u2 * (320.0 - 175.0 * 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",
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);
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);
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;
422 return spheroid->
a / (sqrt(1.0 - spheroid->
e_sq *
POW2(sin(latitude))));
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;
476 LWDEBUGF(4,
"baseArea %.12g", baseArea);
485 LWDEBUGF(4,
"topArea %.12g", topArea);
488 LWDEBUGF(4,
"deltaLng %.12g", deltaLng);
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 )
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);
622 LWDEBUGF(4,
" strip_area %.12g", strip_area);
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.
uint8_t gflags(int hasz, int hasm, int geodetic)
Construct a new flags char.
int getPoint2d_p(const POINTARRAY *pa, uint32_t n, POINT2D *point)
int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
#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.
Datum distance(PG_FUNCTION_ARGS)
Datum area(PG_FUNCTION_ARGS)
#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 double spheroid_big_b(double u2)
static double spheroid_big_a(double u2)
static double ptarray_area_spheroid(const POINTARRAY *pa, const SPHEROID *spheroid)
static double spheroid_mu2(double alpha, const SPHEROID *s)
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.
static double spheroid_parallel_arc_length(double latitude, double deltaLongitude, const SPHEROID *spheroid)
void spheroid_init(SPHEROID *s, double a, double b)
Initialize spheroid object based on major and minor axis.
static double spheroid_prime_vertical_radius_of_curvature(double latitude, const SPHEROID *spheroid)
static double spheroid_striparea(const GEOGRAPHIC_POINT *a, const GEOGRAPHIC_POINT *b, double latitude_min, const SPHEROID *spheroid)
This function doesn't work for edges crossing the dateline or in the southern hemisphere.
static double spheroid_boundingbox_area(const GEOGRAPHIC_POINT *southWestCorner, const GEOGRAPHIC_POINT *northEastCorner, const SPHEROID *spheroid)
Computes the area on the spheroid of a box bounded by meridians and parallels.
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 *r, const GEOGRAPHIC_POINT *s, const SPHEROID *spheroid)
Computes the direction of the geodesic joining two points on the spheroid.
Point in spherical coordinates on the world.