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;
82 geod_init(&gd, spheroid->
a, spheroid->
f);
83 double lat1 = a->
lat * 180.0 / M_PI;
84 double lon1 = a->
lon * 180.0 / M_PI;
85 double lat2 = b->
lat * 180.0 / M_PI;
86 double lon2 = b->
lon * 180.0 / M_PI;
88 geod_inverse(&gd, lat1, lon1, lat2, lon2, &s12, 0, 0);
102 struct geod_geodesic gd;
103 geod_init(&gd, spheroid->
a, spheroid->
f);
104 double lat1 = a->
lat * 180.0 / M_PI;
105 double lon1 = a->
lon * 180.0 / M_PI;
106 double lat2 = b->
lat * 180.0 / M_PI;
107 double lon2 = b->
lon * 180.0 / M_PI;
109 geod_inverse(&gd, lat1, lon1, lat2, lon2, 0, &azi1, 0);
110 return azi1 * M_PI / 180.0;
125 struct geod_geodesic gd;
126 geod_init(&gd, spheroid->
a, spheroid->
f);
127 double lat1 = r->
lat * 180.0 / M_PI;
128 double lon1 = r->
lon * 180.0 / M_PI;
130 geod_direct(&gd, lat1, lon1, azimuth * 180.0 / M_PI,
distance, &lat2, &lon2, 0);
131 g->
lat = lat2 * M_PI / 180.0;
132 g->
lon = lon2 * M_PI / 180.0;
143 struct geod_geodesic gd;
144 geod_init(&gd, spheroid->
a, spheroid->
f);
145 struct geod_polygon poly;
146 geod_polygon_init(&poly, 0);
152 for ( i = 0; i < pa->
npoints - 1; i++ )
155 geod_polygon_addpoint(&gd, &poly, p.
y, p.
x);
156 LWDEBUGF(4,
"geod_polygon_addpoint %d: %.12g %.12g", i, p.
y, p.
x);
158 i = geod_polygon_compute(&gd, &poly, 0, 1, &area, 0);
161 lwerror(
"ptarray_area_spheroid: different number of points %d vs %d",
164 LWDEBUGF(4,
"geod_polygon_compute area: %.12g", area);
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);
285 double lambda = s->
lon - r->
lon;
286 double omf = 1 - spheroid->
f;
287 double u1 = atan(omf * tan(r->
lat));
288 double cos_u1 = cos(u1);
289 double sin_u1 = sin(u1);
290 double u2 = atan(omf * tan(s->
lat));
291 double cos_u2 = cos(u2);
292 double sin_u2 = sin(u2);
294 double omega = lambda;
295 double alpha, sigma, sin_sigma, cos_sigma, cos2_sigma_m, sqr_sin_sigma, last_lambda;
296 double sin_alpha, cos_alphasq, C, alphaFD;
299 sqr_sin_sigma =
POW2(cos_u2 * sin(lambda)) +
300 POW2((cos_u1 * sin_u2 - sin_u1 * cos_u2 * cos(lambda)));
301 sin_sigma = sqrt(sqr_sin_sigma);
302 cos_sigma = sin_u1 * sin_u2 + cos_u1 * cos_u2 * cos(lambda);
303 sigma = atan2(sin_sigma, cos_sigma);
304 sin_alpha = cos_u1 * cos_u2 * sin(lambda) / sin(sigma);
307 if ( sin_alpha > 1.0 )
309 else if ( sin_alpha < -1.0 )
310 alpha = -1.0 * M_PI_2;
312 alpha = asin(sin_alpha);
314 cos_alphasq =
POW2(cos(alpha));
315 cos2_sigma_m = cos(sigma) - (2.0 * sin_u1 * sin_u2 / cos_alphasq);
318 if ( cos2_sigma_m > 1.0 )
320 if ( cos2_sigma_m < -1.0 )
323 C = (spheroid->
f / 16.0) * cos_alphasq * (4.0 + spheroid->
f * (4.0 - 3.0 * cos_alphasq));
324 last_lambda = lambda;
325 lambda = omega + (1.0 - C) * spheroid->
f * sin(alpha) * (sigma + C * sin(sigma) *
326 (cos2_sigma_m + C * cos(sigma) * (-1.0 + 2.0 *
POW2(cos2_sigma_m))));
329 while ( (i < 999) && (lambda != 0) && (fabs((last_lambda - lambda) / lambda) > 1.0e-9) );
331 alphaFD = atan2((cos_u2 * sin(lambda)),
332 (cos_u1 * sin_u2 - sin_u1 * cos_u2 * cos(lambda)));
335 alphaFD = alphaFD + 2.0 * M_PI;
337 if (alphaFD > 2.0 * M_PI)
339 alphaFD = alphaFD - 2.0 * M_PI;
361 double omf = 1 - spheroid->
f;
362 double tan_u1 = omf * tan(r->
lat);
363 double u1 = atan(tan_u1);
364 double sigma, last_sigma, delta_sigma, two_sigma_m;
365 double sigma1, sin_alpha, alpha, cos_alphasq;
367 double lat2, lambda, lambda2, C, omega;
372 azimuth = azimuth + M_PI * 2.0;
374 if (azimuth > (M_PI * 2.0))
376 azimuth = azimuth - M_PI * 2.0;
379 sigma1 = atan2(tan_u1, cos(azimuth));
380 sin_alpha = cos(u1) * sin(azimuth);
381 alpha = asin(sin_alpha);
382 cos_alphasq = 1.0 -
POW2(sin_alpha);
388 sigma = (distance / (spheroid->
b * A));
391 two_sigma_m = 2.0 * sigma1 + sigma;
392 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))))));
394 sigma = (distance / (spheroid->
b * A)) + delta_sigma;
397 while (i < 999 && fabs((last_sigma - sigma) / sigma) > 1.0e-9);
399 lat2 = atan2((sin(u1) * cos(sigma) + cos(u1) * sin(sigma) *
400 cos(azimuth)), (omf * sqrt(
POW2(sin_alpha) +
401 POW2(sin(u1) * sin(sigma) - cos(u1) * cos(sigma) *
403 lambda = atan2((sin(sigma) * sin(azimuth)), (cos(u1) * cos(sigma) -
404 sin(u1) * sin(sigma) * cos(azimuth)));
405 C = (spheroid->
f / 16.0) * cos_alphasq * (4.0 + spheroid->
f * (4.0 - 3.0 * cos_alphasq));
406 omega = lambda - (1.0 - C) * spheroid->
f * sin_alpha * (sigma + C * sin(sigma) *
407 (cos(two_sigma_m) + C * cos(sigma) * (-1.0 + 2.0 *
POW2(cos(two_sigma_m)))));
408 lambda2 = r->
lon + omega;
417 return spheroid->
a / (sqrt(1.0 - spheroid->
e_sq *
POW2(sin(latitude))));
439 double z0 = (northEastCorner->
lon - southWestCorner->
lon) *
POW2(spheroid->
b) / 2.0;
440 double e = sqrt(spheroid->
e_sq);
441 double sinPhi1 = sin(southWestCorner->
lat);
442 double sinPhi2 = sin(northEastCorner->
lat);
443 double t1p1 = sinPhi1 / (1.0 - spheroid->
e_sq * sinPhi1 * sinPhi1);
444 double t1p2 = sinPhi2 / (1.0 - spheroid->
e_sq * sinPhi2 * sinPhi2);
445 double oneOver2e = 1.0 / (2.0 * e);
446 double t2p1 = oneOver2e * log((1.0 + e * sinPhi1) / (1.0 - e * sinPhi1));
447 double t2p2 = oneOver2e * log((1.0 + e * sinPhi2) / (1.0 - e * sinPhi2));
448 return z0 * (t1p2 + t2p2) - z0 * (t1p1 + t2p1);
458 double deltaLng, baseArea, topArea;
459 double bE, tE, ratio, sign;
464 mL.
lat = latitude_min;
471 LWDEBUGF(4,
"baseArea %.12g", baseArea);
480 LWDEBUGF(4,
"topArea %.12g", topArea);
483 LWDEBUGF(4,
"deltaLng %.12g", deltaLng);
489 ratio = (bE + tE)/tE;
491 return (baseArea + topArea / ratio) * sign;
502 double delta_lon_tolerance;
515 lwerror(
"ptarray_area_spheroid: cannot handle ptarray that crosses equator");
518 if ( gbox2d.
ymax < 0.0 )
526 delta_lon_tolerance = (90.0 / (fabs(gbox2d.
ymin) / 8.0) - 2.0) / 10000.0;
531 delta_lon_tolerance = (90.0 / (fabs(gbox2d.
ymax) / 8.0) - 2.0) / 10000.0;
539 for ( i = 1; i < pa->
npoints; i++ )
542 double strip_area = 0.0;
543 double delta_lon = 0.0;
559 LWDEBUGF(4,
"in_south %d", in_south);
568 shift = (M_PI - a1.
lon) + 0.088;
570 shift = (M_PI - b1.
lon) + 0.088;
581 delta_lon = fabs(b1.
lon - a1.
lon);
584 LWDEBUGF(4,
"delta_lon %.18g", delta_lon);
585 LWDEBUGF(4,
"delta_lon_tolerance %.18g", delta_lon_tolerance);
587 if ( delta_lon > 0.0 )
589 if ( delta_lon < delta_lon_tolerance )
592 LWDEBUGF(4,
"strip_area %.12g", strip_area);
598 double step = floor(delta_lon / delta_lon_tolerance);
600 double pDistance = 0.0;
603 LWDEBUGF(4,
"distance %.18g", distance);
604 step = distance / step;
607 while (pDistance < (distance - step * 1.01))
612 LWDEBUGF(4,
" azimuth %.12g", azimuth);
613 pDistance = pDistance + step;
614 LWDEBUGF(4,
" pDistance %.12g", pDistance);
617 LWDEBUGF(4,
" strip_area %.12g", strip_area);
674 for ( i = 1; i < poly->
nrings; i++ )
688 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.
static double spheroid_big_b(double u2)
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.
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)
int crosses_dateline(const GEOGRAPHIC_POINT *s, const GEOGRAPHIC_POINT *e)
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...
Datum area(PG_FUNCTION_ARGS)
static double spheroid_parallel_arc_length(double latitude, double deltaLongitude, 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_mu2(double alpha, const SPHEROID *s)
void point_shift(GEOGRAPHIC_POINT *p, double shift)
Shift a point around by a number of radians.
Point in spherical coordinates on the world.
void spheroid_init(SPHEROID *s, double a, double b)
Initialize spheroid object based on major and minor axis.
#define LW_TRUE
Return types for functions with status returns.
double lwgeom_area_spheroid(const LWGEOM *lwgeom, const SPHEROID *spheroid)
Calculate the area of an LWGEOM.
int getPoint2d_p(const POINTARRAY *pa, int n, POINT2D *point)
static double ptarray_area_spheroid(const POINTARRAY *pa, const SPHEROID *spheroid)
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.
Datum distance(PG_FUNCTION_ARGS)
uint8_t gflags(int hasz, int hasm, int geodetic)
Construct a new flags char.
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 geographic_point_equals(const GEOGRAPHIC_POINT *g1, const GEOGRAPHIC_POINT *g2)
void geographic_point_init(double lon, double lat, GEOGRAPHIC_POINT *g)
Initialize a geographic point.
double deltaLongitude(double azimuth, double sigma, double tsm, SPHEROID *sphere)
#define deg2rad(d)
Conversion functions.
int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members) ...
#define LWDEBUGF(level, msg,...)
static double spheroid_prime_vertical_radius_of_curvature(double latitude, const SPHEROID *spheroid)
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
#define SIGNUM(n)
Macro that returns: -1 if n < 0, 1 if n > 0, 0 if n == 0.