52 if ( lon == -1.0 * M_PI )
54 if ( lon == -2.0 * M_PI )
57 if ( lon > 2.0 * M_PI )
58 lon = remainder(lon, 2.0 * M_PI);
60 if ( lon < -2.0 * M_PI )
61 lon = remainder(lon, -2.0 * M_PI);
64 lon = -2.0 * M_PI + lon;
66 if ( lon < -1.0 * M_PI )
67 lon = 2.0 * M_PI + lon;
69 if ( lon == -2.0 * M_PI )
81 if ( lat > 2.0 * M_PI )
82 lat = remainder(lat, 2.0 * M_PI);
84 if ( lat < -2.0 * M_PI )
85 lat = remainder(lat, -2.0 * M_PI);
90 if ( lat < -1.0 * M_PI )
91 lat = -1.0 * M_PI - lat;
96 if ( lat < -1.0 * M_PI_2 )
97 lat = -1.0 * M_PI - lat;
109 lon = remainder(lon, 360.0);
112 lon = remainder(lon, -360.0);
137 lat = remainder(lat, 360.0);
140 lat = remainder(lat, -360.0);
162 double lon = p->
lon + shift;
164 p->
lon = -1.0 * M_PI + (lon - M_PI);
192 double zmin = FLT_MAX;
193 double zmax = -1 * FLT_MAX;
198 memcpy(d, &(gbox->
xmin), 6*
sizeof(
double));
201 for ( i = 0; i < 8; i++ )
204 pt.
y = d[2 + (i % 4) / 2];
205 pt.
z = d[4 + (i % 2)];
207 if ( pt.
z < zmin ) zmin = pt.
z;
208 if ( pt.
z > zmax ) zmax = pt.
z;
210 return asin(zmax) - asin(zmin);
225 memcpy(d, &(gbox->
xmin), 6*
sizeof(
double));
228 pt[0].
x = gbox->
xmin;
229 pt[0].
y = gbox->
ymin;
230 magnitude = sqrt(pt[0].
x*pt[0].
x + pt[0].
y*pt[0].
y);
231 pt[0].
x /= magnitude;
232 pt[0].
y /= magnitude;
236 for ( j = 0; j < 2; j++ )
238 maxangle = -1 * FLT_MAX;
239 for ( i = 0; i < 4; i++ )
241 double angle, dotprod;
245 pt_n.
y = d[2 + (i % 2)];
246 magnitude = sqrt(pt_n.
x*pt_n.
x + pt_n.
y*pt_n.
y);
251 dotprod = pt_n.
x*pt[j].
x + pt_n.
y*pt[j].
y;
252 angle = acos(dotprod > 1.0 ? 1.0 : dotprod);
253 if ( angle > maxangle )
276 memcpy(d, &(gbox->
xmin), 6*
sizeof(
double));
279 pt.
x = pt.
y = pt.
z = 0.0;
281 for ( i = 0; i < 8; i++ )
286 pt_n.
y = d[2 + ((i % 4) / 2)];
287 pt_n.
z = d[4 + (i % 2)];
319 #if POSTGIS_DEBUG_LEVEL >= 4
326 if (gbox->
xmin < 0.0 && gbox->
xmax > 0.0 &&
327 gbox->
ymin < 0.0 && gbox->
ymax > 0.0)
330 if ((gbox->
zmin > 0.0) && (gbox->
zmax > 0.0))
332 LWDEBUG(4,
"enclosed positive z axis");
336 else if ((gbox->
zmin < 0.0) && (gbox->
zmax < 0.0))
338 LWDEBUG(4,
"enclosed negative z axis");
344 LWDEBUG(4,
"enclosed both z axes");
352 if (gbox->
xmin < 0.0 && gbox->
xmax > 0.0 &&
353 gbox->
zmin < 0.0 && gbox->
zmax > 0.0)
355 if ((gbox->
ymin > 0.0) && (gbox->
ymax > 0.0))
357 LWDEBUG(4,
"enclosed positive y axis");
360 else if ((gbox->
ymin < 0.0) && (gbox->
ymax < 0.0))
362 LWDEBUG(4,
"enclosed negative y axis");
367 LWDEBUG(4,
"enclosed both y axes");
375 if (gbox->
ymin < 0.0 && gbox->
ymax > 0.0 &&
376 gbox->
zmin < 0.0 && gbox->
zmax > 0.0)
378 if ((gbox->
xmin > 0.0) && (gbox->
xmax > 0.0))
380 LWDEBUG(4,
"enclosed positive x axis");
383 else if ((gbox->
xmin < 0.0) && (gbox->
xmax < 0.0))
385 LWDEBUG(4,
"enclosed negative x axis");
390 LWDEBUG(4,
"enclosed both x axes");
406 p->
x = cos(g->
lat) * cos(g->
lon);
407 p->
y = cos(g->
lat) * sin(g->
lon);
416 g->
lon = atan2(p->
y, p->
x);
425 double x_rad = M_PI * g->
x / 180.0;
426 double y_rad = M_PI * g->
y / 180.0;
427 double cos_y_rad = cos(y_rad);
428 p->
x = cos_y_rad * cos(x_rad);
429 p->
y = cos_y_rad * sin(x_rad);
448 return (p1->
x*p2->
x) + (p1->
y*p2->
y) + (p1->
z*p2->
z);
456 n->
x = a->
y * b->
z - a->
z * b->
y;
457 n->
y = a->
z * b->
x - a->
x * b->
z;
458 n->
z = a->
x * b->
y - a->
y * b->
x;
526 double d = sqrt(p->
x*p->
x + p->
y*p->
y);
553 else if ( p_dot > 0.95 )
576 double cos_a = cos(angle);
577 double sin_a = sin(angle);
578 double uxuy, uyuz, uxuz;
579 double ux2, uy2, uz2;
580 double rxx, rxy, rxz, ryx, ryy, ryz, rzx, rzy, rzz;
593 rxx = cos_a + ux2 * (1 - cos_a);
594 rxy = uxuy * (1 - cos_a) - u.
z * sin_a;
595 rxz = uxuz * (1 - cos_a) + u.
y * sin_a;
597 ryx = uxuy * (1 - cos_a) + u.
z * sin_a;
598 ryy = cos_a + uy2 * (1 - cos_a);
599 ryz = uyuz * (1 - cos_a) - u.
x * sin_a;
601 rzx = uxuz * (1 - cos_a) - u.
y * sin_a;
602 rzy = uyuz * (1 - cos_a) + u.
x * sin_a;
603 rzz = cos_a + uz2 * (1 - cos_a);
605 n->
x = rxx * v1->
x + rxy * v1->
y + rxz * v1->
z;
606 n->
y = ryx * v1->
x + ryy * v1->
y + ryz * v1->
z;
607 n->
z = rzx * v1->
x + rzy * v1->
y + rzz * v1->
z;
617 double d = sqrt(p->
x*p->
x + p->
y*p->
y + p->
z*p->
z);
620 p->
x = p->
y = p->
z = 0.0;
636 double lon_qpp = (q->
lon + p->
lon) / -2.0;
637 double lon_qmp = (q->
lon - p->
lon) / 2.0;
638 double sin_p_lat_minus_q_lat = sin(p->
lat-q->
lat);
639 double sin_p_lat_plus_q_lat = sin(p->
lat+q->
lat);
640 double sin_lon_qpp = sin(lon_qpp);
641 double sin_lon_qmp = sin(lon_qmp);
642 double cos_lon_qpp = cos(lon_qpp);
643 double cos_lon_qmp = cos(lon_qmp);
644 a->
x = sin_p_lat_minus_q_lat * sin_lon_qpp * cos_lon_qmp -
645 sin_p_lat_plus_q_lat * cos_lon_qpp * sin_lon_qmp;
646 a->
y = sin_p_lat_minus_q_lat * cos_lon_qpp * cos_lon_qmp +
647 sin_p_lat_plus_q_lat * sin_lon_qpp * sin_lon_qmp;
668 double sign_s =
SIGNUM(
s->lon);
670 double ss = fabs(
s->lon);
671 double ee = fabs(e->
lon);
672 if ( sign_s == sign_e )
707 LWDEBUG(4,
"point is on plane (dot product is zero)");
743 double angle_a, angle_b, angle_c;
744 double area_radians = 0.0;
752 area_radians = angle_a + angle_b + angle_c - M_PI;
764 return side * area_radians;
791 double vs_dot_vcp, vp_dot_vcp;
795 if ( vs.
x == -1.0 * ve.
x && vs.
y == -1.0 * ve.
y && vs.
z == -1.0 * ve.
z )
803 LWDEBUGF(4,
"vs_dot_vcp %.19g",vs_dot_vcp);
806 LWDEBUGF(4,
"vp_dot_vcp %.19g",vp_dot_vcp);
808 LWDEBUGF(4,
"fabs(vp_dot_vcp - vs_dot_vcp) %.39g",fabs(vp_dot_vcp - vs_dot_vcp));
823 if ( vp_dot_vcp > vs_dot_vcp || fabs(vp_dot_vcp - vs_dot_vcp) < 2e-16 )
825 LWDEBUG(4,
"point is in cone");
828 LWDEBUG(4,
"point is not in cone");
839 double slon = fabs((e->
start).lon) + fabs((e->
end).lon);
840 double dlon = fabs(fabs((e->
start).lon) - fabs((e->
end).lon));
841 double slat = (e->
start).lat + (e->
end).lat;
844 LWDEBUGF(4,
"e.end == GPOINT(%.6g %.6g) ", (e->
end).lat, (e->
end).lon);
854 LWDEBUG(4,
"vertical plane, we need to do this calculation in latitude");
873 LWDEBUG(4,
"over the pole...");
892 LWDEBUG(4,
"north or south?...");
897 LWDEBUG(4,
"over the north pole...");
906 LWDEBUG(4,
"over the south pole...");
917 LWDEBUG(4,
"crosses dateline, flip longitudes...");
936 LWDEBUG(4,
"true, this edge contains point");
940 LWDEBUG(4,
"false, this edge does not contain point");
950 double d_lon = e->
lon -
s->lon;
951 double cos_d_lon = cos(d_lon);
952 double cos_lat_e = cos(e->
lat);
953 double sin_lat_e = sin(e->
lat);
954 double cos_lat_s = cos(
s->lat);
955 double sin_lat_s = sin(
s->lat);
957 double a1 =
POW2(cos_lat_e * sin(d_lon));
958 double a2 =
POW2(cos_lat_s * sin_lat_e - sin_lat_s * cos_lat_e * cos_d_lon);
959 double a = sqrt(a1 + a2);
960 double b = sin_lat_s * sin_lat_e + cos_lat_s * cos_lat_e * cos_d_lon;
977 double heading = 0.0;
982 return (
s->lat > 0.0) ? M_PI : 0.0;
984 f = (sin(e->
lat) - sin(
s->lat) * cos(d)) / (sin(d) * cos(
s->lat));
989 else if ( fabs(f) > 1.0 )
997 if ( sin(e->
lon -
s->lon) < 0.0 )
998 heading = -1 * heading;
1022 double sign =
SIGNUM(hcb-hca);
1023 double ss = (a_dist + b_dist + c_dist) / 2.0;
1024 double E = tan(ss/2.0)*tan((ss-a_dist)/2.0)*tan((ss-b_dist)/2.0)*tan((ss-c_dist)/2.0);
1025 return 4.0 * atan(sqrt(fabs(E))) * sign;
1039 LWDEBUG(4,
"point is on edge");
1042 LWDEBUG(4,
"point is not on edge");
1052 double tlat = acos(z);
1053 LWDEBUGF(4,
"inputs: z(%.8g) sign(%.8g) tlat(%.8g)", z, sign, tlat);
1056 if (top)
return M_PI_2;
1057 else return -1.0 * M_PI_2;
1059 if (fabs(tlat) > M_PI_2 )
1061 tlat = sign * (M_PI - fabs(tlat));
1067 LWDEBUGF(4,
"output: tlat(%.8g)", tlat);
1080 LWDEBUG(4,
"entering function");
1083 LWDEBUGF(4,
"unit normal t1 == POINT(%.8g %.8g %.8g)", t1.
x, t1.
y, t1.
z);
1084 LWDEBUGF(4,
"unit normal t2 == POINT(%.8g %.8g %.8g)", t2.
x, t2.
y, t2.
z);
1091 LWDEBUGF(4,
"clairaut top == GPOINT(%.6g %.6g)", g_top->
lat, g_top->
lon);
1092 LWDEBUGF(4,
"clairaut bottom == GPOINT(%.6g %.6g)", g_bottom->
lat, g_bottom->
lon);
1105 LWDEBUG(4,
"entering function");
1110 LWDEBUGF(4,
"unit normal t1 == POINT(%.8g %.8g %.8g)", t1.
x, t1.
y, t1.
z);
1111 LWDEBUGF(4,
"unit normal t2 == POINT(%.8g %.8g %.8g)", t2.
x, t2.
y, t2.
z);
1118 LWDEBUGF(4,
"clairaut top == GPOINT(%.6g %.6g)", g_top->
lat, g_top->
lon);
1119 LWDEBUGF(4,
"clairaut bottom == GPOINT(%.6g %.6g)", g_bottom->
lat, g_bottom->
lon);
1161 LWDEBUGF(4,
"e1 cross product == POINT(%.12g %.12g %.12g)", ea.
x, ea.
y, ea.
z);
1162 LWDEBUGF(4,
"e2 cross product == POINT(%.12g %.12g %.12g)", eb.
x, eb.
y, eb.
z);
1192 LWDEBUGF(4,
"v == POINT(%.12g %.12g %.12g)", v.
x, v.
y, v.
z);
1193 g->
lat = atan2(v.
z, sqrt(v.
x * v.
x + v.
y * v.
y));
1194 g->
lon = atan2(v.
y, v.
x);
1203 LWDEBUG(4,
"flipping point to other side of sphere");
1206 if ( g->
lon > M_PI )
1208 g->
lon = -1.0 * (2.0 * M_PI - g->
lon);
1220 double d1 = 1000000000.0, d2, d3, d_nearest;
1227 *closest = e->
start;
1248 if ( d2 < d_nearest )
1251 g_nearest = e->
start;
1253 if ( d3 < d_nearest )
1259 *closest = g_nearest;
1303 if ( closest1 ) *closest1 = c1;
1304 if ( closest2 ) *closest2 = c2;
1317 double lat1 =
r->lat;
1318 double lon1 =
r->lon;
1321 lat2 = asin(sin(lat1)*cos(d) + cos(lat1)*sin(d)*cos(azimuth));
1331 lon2 = lon1 + atan2(sin(azimuth)*sin(d)*cos(lat1), cos(d)-sin(lat1)*sin(lat2));
1334 if ( isnan(lat2) || isnan(lon2) )
1346 int steps = 1000000;
1355 LWDEBUG(4,
"edge is zero length. returning");
1367 LWDEBUG(4,
"edge is antipodal. setting to maximum size box, and returning");
1377 dx = (end.
x - start.
x)/steps;
1378 dy = (end.
y - start.
y)/steps;
1379 dz = (end.
z - start.
z)/steps;
1384 for ( i = 0; i < steps; i++ )
1426 lwerror(
"Antipodal (180 degrees long) edge detected!");
1441 memset(X, 0,
sizeof(
POINT3D) * 6);
1442 X[0].
x = X[2].
y = X[4].
z = 1.0;
1443 X[1].
x = X[3].
y = X[5].
z = -1.0;
1451 for ( i = 0; i < 6; i++ )
1464 Xn.
x = RX.
x * A1->
x + RX.
y * A3.
x;
1465 Xn.
y = RX.
x * A1->
y + RX.
y * A3.
y;
1466 Xn.
z = RX.
x * A1->
z + RX.
y * A3.
z;
1491 POINT3D q1, q2, qMid, qCross, qSum;
1497 pa = poly->
rings[0];
1554 double grow = M_PI / 180.0 / 60.0;
1561 while ( grow < M_PI )
1565 if ( ge.
xmin > -1 ) ge.
xmin -= grow;
1566 if ( ge.
ymin > -1 ) ge.
ymin -= grow;
1567 if ( ge.
zmin > -1 ) ge.
zmin -= grow;
1568 if ( ge.
xmax < 1 ) ge.
xmax += grow;
1569 if ( ge.
ymax < 1 ) ge.
ymax += grow;
1570 if ( ge.
zmax < 1 ) ge.
zmax += grow;
1573 corners[0].
x = ge.
xmin;
1574 corners[0].
y = ge.
ymin;
1575 corners[0].
z = ge.
zmin;
1577 corners[1].
x = ge.
xmin;
1578 corners[1].
y = ge.
ymax;
1579 corners[1].
z = ge.
zmin;
1581 corners[2].
x = ge.
xmin;
1582 corners[2].
y = ge.
ymin;
1583 corners[2].
z = ge.
zmax;
1585 corners[3].
x = ge.
xmax;
1586 corners[3].
y = ge.
ymin;
1587 corners[3].
z = ge.
zmin;
1589 corners[4].
x = ge.
xmax;
1590 corners[4].
y = ge.
ymax;
1591 corners[4].
z = ge.
zmin;
1593 corners[5].
x = ge.
xmax;
1594 corners[5].
y = ge.
ymin;
1595 corners[5].
z = ge.
zmax;
1597 corners[6].
x = ge.
xmin;
1598 corners[6].
y = ge.
ymax;
1599 corners[6].
z = ge.
zmax;
1601 corners[7].
x = ge.
xmax;
1602 corners[7].
y = ge.
ymax;
1603 corners[7].
z = ge.
zmax;
1605 LWDEBUG(4,
"trying to use a box corner point...");
1606 for ( i = 0; i < 8; i++ )
1609 LWDEBUGF(4,
"testing corner %d: POINT(%.8g %.8g %.8g)", i, corners[i].
x, corners[i].
y, corners[i].z);
1612 LWDEBUGF(4,
"corner %d is outside our gbox", i);
1618 LWDEBUGF(4,
"returning POINT(%.8g %.8g) as outside point", pt_outside->
x, pt_outside->
y);
1636 double d,
double max_seg_length,
1644 if (d <= max_seg_length)
1659 mid.
x = (p1->
x + p2->
x) / 2.0;
1660 mid.
y = (p1->
y + p2->
y) / 2.0;
1661 mid.
z = (p1->
z + p2->
z) / 2.0;
1669 midv.
z = (v1->
z + v2->
z) / 2.0;
1670 midv.
m = (v1->
m + v2->
m) / 2.0;
1696 lwerror(
"%s: null input pointarray", __func__);
1697 if ( max_seg_length <= 0.0 )
1698 lwerror(
"%s: maximum segment length must be positive", __func__);
1704 for (i = 1; i < pa_in->
npoints; i++)
1718 if (d > max_seg_length)
1747 LWPOLY *lwpoly_in, *lwpoly_out;
1759 switch (lwg_in->
type)
1773 for ( i = 0; i < lwpoly_in->
nrings; i++ )
1785 for ( i = 0; i < lwcol_in->
ngeoms; i++ )
1792 lwerror(
"lwgeom_segmentize_sphere: unsupported input geometry type: %d - %s",
1797 lwerror(
"lwgeom_segmentize_sphere got to the end of the function, should not happen");
1815 if ( ! pa || pa->
npoints < 4 )
1823 for ( i = 2; i < pa->
npoints-1; i++ )
1844 int use_sphere = (
s->a ==
s->b ? 1 : 0);
1865 else if (
distance < 0.95 * tolerance )
1900 for ( i = 1; i < pa_many->
npoints; i++ )
1914 if ( d < tolerance )
1922 else if ( d < tolerance * 0.95 )
1931 if ( d < tolerance )
1954 for ( i = 1; i < pa1->
npoints; i++ )
1965 for ( j = 1; j < pa2->
npoints; j++ )
1980 LWDEBUG(4,
"edge intersection! returning 0.0");
1984 LWDEBUGF(4,
"got edge_distance_to_edge %.8g", d);
1992 if ( d < tolerance )
2001 if ( d < tolerance )
2064 for ( i = 1; i < poly->
nrings; i++ )
2078 for ( i = 0; i < col->
ngeoms; i++ )
2114 azimuth -= 2.0 * M_PI * floor(azimuth / (2.0 * M_PI));
2119 lwerror(
"Distance must not be greater than %g", M_PI * spheroid->
radius);
2131 LWDEBUGF(3,
"Unable to project from (%g %g) with azimuth %g and distance %g",
x,
y, azimuth,
distance);
2132 lwerror(
"Unable to project from (%g %g) with azimuth %g and distance %g",
x,
y, azimuth,
distance);
2140 pt_dest.
z = pt_dest.
m = 0.0;
2159 double x1, y1, x2, y2;
2199 LWDEBUGF(4,
"entered function, tolerance %.8g", tolerance);
2208 type1 = lwgeom1->
type;
2209 type2 = lwgeom2->
type;
2212 if ( lwgeom1->
bbox )
2213 gbox1 = *(lwgeom1->
bbox);
2218 if ( lwgeom2->
bbox )
2219 gbox2 = *(lwgeom2->
bbox);
2234 pa1 = ((
LWPOINT*)lwgeom1)->point;
2236 pa1 = ((
LWLINE*)lwgeom1)->points;
2239 pa2 = ((
LWPOINT*)lwgeom2)->point;
2241 pa2 = ((
LWLINE*)lwgeom2)->points;
2259 lwpoly = (
LWPOLY*)lwgeom2;
2264 lwpoly = (
LWPOLY*)lwgeom1;
2275 for ( i = 0; i < lwpoly->
nrings; i++ )
2298 lwline = (
LWLINE*)lwgeom1;
2299 lwpoly = (
LWPOLY*)lwgeom2;
2303 lwline = (
LWLINE*)lwgeom2;
2304 lwpoly = (
LWPOLY*)lwgeom1;
2308 LWDEBUG(4,
"checking if a point of line is in polygon");
2314 LWDEBUG(4,
"checking ring distances");
2317 for ( i = 0; i < lwpoly->
nrings; i++ )
2320 LWDEBUGF(4,
"ring[%d] ring_distance = %.8g", i, ring_distance);
2350 for (i = 0; i < lwpoly1->
nrings; i++)
2352 for (j = 0; j < lwpoly2->
nrings; j++)
2354 double ring_distance =
2360 check_intersection);
2376 for ( i = 0; i < col->
ngeoms; i++ )
2379 col->
geoms[i], lwgeom2, spheroid, tolerance);
2395 for ( i = 0; i < col->
ngeoms; i++ )
2422 type1 = lwgeom1->
type;
2423 type2 = lwgeom2->
type;
2430 LWDEBUG(4,
"dimension of geom2 is bigger than geom1");
2435 if ( lwgeom1->
bbox )
2436 gbox1 = *(lwgeom1->
bbox);
2441 if ( lwgeom2->
bbox )
2442 gbox2 = *(lwgeom2->
bbox);
2481 for ( i = 0; i < col->
ngeoms; i++ )
2497 for ( i = 0; i < col->
ngeoms; i++ )
2508 lwerror(
"lwgeom_covers_lwgeom_sphere: reached end of function without resolution");
2521 int in_hole_count = 0;
2526 #if POSTGIS_DEBUG_LEVEL >= 4
2534 LWDEBUG(4,
"returning false, geometry is empty or null");
2540 gbox = *(poly->
bbox);
2549 LWDEBUG(4,
"the point is not in the box!");
2556 LWDEBUGF(4,
"pt_outside POINT(%.18g %.18g)", pt_outside.
x, pt_outside.
y);
2557 LWDEBUGF(4,
"pt_to_test POINT(%.18g %.18g)", pt_to_test->
x, pt_to_test->
y);
2558 #if POSTGIS_DEBUG_LEVEL >= 4
2560 LWDEBUGF(4,
"polygon %s", geom_ewkt);
2570 LWDEBUG(4,
"returning false, point is outside ring");
2577 for ( i = 1; i < poly->
nrings; i++ )
2579 LWDEBUGF(4,
"ring test loop %d", i);
2585 LWDEBUGF(4,
"in_hole_count == %d", in_hole_count);
2587 if ( in_hole_count % 2 )
2589 LWDEBUG(4,
"returning false, inner ring containment count is odd");
2593 LWDEBUG(4,
"returning true, inner ring containment count is even");
2609 LWDEBUG(4,
"returning false, geometry1 is empty or null");
2616 LWDEBUG(4,
"returning false, geometry2 is empty or null");
2621 for (i = 0; i < poly2->
nrings; i++)
2629 LWDEBUG(4,
"returning false, geometry2 has point outside of geometry1");
2637 LWDEBUG(4,
"returning false, geometry2 has point inside a hole of geometry1");
2644 for (i = 0; i < poly2->
nrings; i++)
2648 LWDEBUG(4,
"returning false, geometry2 is partially outside of geometry1");
2665 LWDEBUG(4,
"returning false, geometry1 is empty or null");
2672 LWDEBUG(4,
"returning false, geometry2 is empty or null");
2678 LWDEBUG(4,
"returning false, geometry2 has point outside of geometry1");
2685 LWDEBUG(4,
"returning false, geometry2 is partially outside of geometry1");
2699 for (i = 0; i < pta->
npoints; i++) {
2703 LWDEBUG(4,
"returning false, geometry2 has point outside of geometry1");
2719 for (i = 0; i < lwpoly->
nrings; i++)
2730 for (k = 0; k < line->
npoints - 1; k++)
2797 LWDEBUG(4,
"returning false, first point of line2 is not covered by line1");
2804 LWDEBUG(4,
"returning false, last point of line2 is not covered by line1");
2810 while (i < lwline1->points->npoints - 1 && j < lwline2->points->npoints - 1)
2848 LWDEBUG(4,
"returning false, found point not covered by both lines");
2879 assert(n < pa->npoints);
2918 for ( i = 1; i < pa->
npoints; i++ )
2965 for ( i = 0; i < poly->
nrings; i++ )
3005 for ( i = 0; i < coll->
ngeoms; i++ )
3059 lwerror(
"lwgeom_calculate_gbox_geodetic: unsupported input geometry type: %d - %s",
3079 if ( pt.
x < -180.0 || pt.
y < -90.0 || pt.
x > 180.0 || pt.
y > 90.0 )
3103 for ( i = 0; i < poly->
nrings; i++ )
3123 for ( i = 0; i < col->
ngeoms; i++ )
3154 lwerror(
"lwgeom_check_geodetic: unsupported input geometry type: %d - %s",
3168 for ( t=0; t < pa->
npoints; t++ )
3171 if ( pt.
x < -180.0 || pt.
x > 180.0 || pt.
y < -90.0 || pt.
y > 90.0 )
3200 for ( i = 0; i < poly->
nrings; i++ )
3214 for ( i = 0; i < col->
ngeoms; i++ )
3247 double za = 0.0, zb = 0.0;
3251 double length = 0.0;
3252 double seglength = 0.0;
3255 if ( ! pa || pa->
npoints < 2 )
3268 for ( i = 1; i < pa->
npoints; i++ )
3285 seglength = sqrt( (zb-za)*(zb-za) + seglength*seglength );
3288 length += seglength;
3301 double length = 0.0;
3320 for ( i = 0; i < poly->
nrings; i++ )
3334 for ( i = 0; i < col->
ngeoms; i++ )
3341 lwerror(
"unsupported type passed to lwgeom_length_sphere");
3359 static double tolerance = 1e-10;
3362 lwerror(
"ptarray_nudge_geodetic called with null input");
3364 for(i = 0; i < pa->
npoints; i++ )
3367 if ( p.
x < -180.0 && (-180.0 - p.
x < tolerance) )
3372 if ( p.
x > 180.0 && (p.
x - 180.0 < tolerance) )
3377 if ( p.
y < -90.0 && (-90.0 - p.
y < tolerance) )
3382 if ( p.
y > 90.0 && (p.
y - 90.0 < tolerance) )
3427 for ( i = 0; i < poly->
nrings; i++ )
3430 rv = (rv ==
LW_TRUE ? rv : n);
3442 for ( i = 0; i < col->
ngeoms; i++ )
3445 rv = (rv ==
LW_TRUE ? rv : n);
3462 double min_similarity, similarity;
3476 if (fabs(1.0 - min_similarity) > 1e-10)
3485 if (similarity > min_similarity)
3532 return dp < 0.0 ? -1 : 1;
3544 int a1_side, a2_side, b1_side, b2_side;
3573 if ( a1_side == a2_side && a1_side != 0 )
3580 if ( b1_side == b2_side && b1_side != 0 )
3587 if ( a1_side != a2_side && (a1_side + a2_side) == 0 &&
3588 b1_side != b2_side && (b1_side + b2_side) == 0 )
3616 else if ( a2_side == 0 )
3628 else if ( b2_side == 0 )
3653 if ( ! pa || pa->
npoints < 4 )
3665 for ( i = 1; i < pa->
npoints; i++ )
3667 LWDEBUGF(4,
"testing edge (%d)", i);
3668 LWDEBUGF(4,
" start point == POINT(%.12g %.12g)", p.
x, p.
y);
3704 LWDEBUGF(4,
" edge (%d) crossed, disregarding to avoid double count", i,
count);
3715 LWDEBUGF(4,
" edge (%d) did not cross", i);
int gbox_merge(const GBOX *new_box, GBOX *merge_box)
Update the merged GBOX to be large enough to include itself and the new box.
void gbox_duplicate(const GBOX *original, GBOX *duplicate)
Copy the values of original GBOX into duplicate.
int gbox_contains_point3d(const GBOX *gbox, const POINT3D *pt)
Return true if the point is inside the gbox.
int gbox_merge_point3d(const POINT3D *p, GBOX *gbox)
Update the GBOX to be large enough to include itself and the new point.
int gbox_overlaps(const GBOX *g1, const GBOX *g2)
Return LW_TRUE if the GBOX overlaps, LW_FALSE otherwise.
void gbox_init(GBOX *gbox)
Zero out all the entries in the GBOX.
GBOX * gbox_copy(const GBOX *box)
Return a copy of the GBOX, based on dimensionality of flags.
int gbox_init_point3d(const POINT3D *p, GBOX *gbox)
Initialize a GBOX using the values of the point.
char * gbox_to_string(const GBOX *gbox)
Allocate a string representation of the GBOX, based on dimensionality of flags.
uint8_t gflags(int hasz, int hasm, int geodetic)
Construct a new flags char.
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
void lwgeom_set_geodetic(LWGEOM *geom, int value)
Set the FLAGS geodetic bit on geometry an all sub-geometries and pointlists.
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int srid, char hasz, char hasm)
uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
double lwpoint_get_x(const LWPOINT *point)
uint32_t lwgeom_get_type(const LWGEOM *geom)
Return LWTYPE number.
LWGEOM * lwgeom_clone_deep(const LWGEOM *lwgeom)
Deep clone an LWGEOM, everything is copied.
int lwpoly_add_ring(LWPOLY *poly, POINTARRAY *pa)
Add a ring, allocating extra space if necessary.
int getPoint2d_p(const POINTARRAY *pa, uint32_t n, POINT2D *point)
POINTARRAY * ptarray_construct(char hasz, char hasm, uint32_t npoints)
Construct an empty pointarray, allocating storage and setting the npoints, but not filling in any inf...
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
int lwtype_is_collection(uint8_t type)
Determine whether a type number is a collection or not.
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
char * lwgeom_to_ewkt(const LWGEOM *lwgeom)
Return an alloced string.
#define FLAGS_GET_Z(flags)
Macros for manipulating the 'flags' byte.
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
LWPOINT * lwpoint_construct(int srid, GBOX *bbox, POINTARRAY *point)
#define POLYHEDRALSURFACETYPE
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
#define FLAGS_GET_M(flags)
int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
LWGEOM * lwgeom_clone(const LWGEOM *lwgeom)
Clone LWGEOM object.
int ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int allow_duplicates)
Append a point to the end of an existing POINTARRAY If allow_duplicate is LW_FALSE,...
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
#define LW_TRUE
Return types for functions with status returns.
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
LWLINE * lwline_construct(int srid, GBOX *bbox, POINTARRAY *points)
void ptarray_set_point4d(POINTARRAY *pa, uint32_t n, const POINT4D *p4d)
LWPOLY * lwpoly_construct_empty(int srid, char hasz, char hasm)
double lwpoint_get_y(const LWPOINT *point)
const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
LWPOINT * lwline_get_lwpoint(const LWLINE *line, uint32_t where)
Returns freshly allocated LWPOINT that corresponds to the index where.
int p4d_same(const POINT4D *p1, const POINT4D *p2)
int p3d_same(const POINT3D *p1, const POINT3D *p2)
#define LW_ON_INTERRUPT(x)
#define SIGNUM(n)
Macro that returns: -1 if n < 0, 1 if n > 0, 0 if n == 0.
int ptarray_has_z(const POINTARRAY *pa)
int lw_segment_side(const POINT2D *p1, const POINT2D *p2, const POINT2D *q)
lw_segment_side()
int ptarray_has_m(const POINTARRAY *pa)
char lwpoint_same(const LWPOINT *p1, const LWPOINT *p2)
int clairaut_geographic(const GEOGRAPHIC_POINT *start, const GEOGRAPHIC_POINT *end, GEOGRAPHIC_POINT *g_top, GEOGRAPHIC_POINT *g_bottom)
Computes the pole of the great circle disk which is the intersection of the great circle with the lin...
static int lwline_check_geodetic(const LWLINE *line)
static int lwcollection_check_geodetic(const LWCOLLECTION *col)
int lwpoly_covers_point2d(const LWPOLY *poly, const POINT2D *pt_to_test)
Given a polygon (lon/lat decimal degrees) and point (lon/lat decimal degrees) and a guaranteed outsid...
void normalize(POINT3D *p)
Normalize to a unit vector.
static int lwpoly_check_geodetic(const LWPOLY *poly)
int lwline_covers_lwpoint(const LWLINE *lwline, const LWPOINT *lwpoint)
return LW_TRUE if any of the line segments covers the point
int lwpoly_intersects_line(const LWPOLY *lwpoly, const POINTARRAY *line)
Checks if any edges of lwpoly intersect with the line formed by the pointarray return LW_TRUE if any ...
double longitude_radians_normalize(double lon)
Convert a longitude to the range of -PI,PI.
int clairaut_cartesian(const POINT3D *start, const POINT3D *end, GEOGRAPHIC_POINT *g_top, GEOGRAPHIC_POINT *g_bottom)
Computes the pole of the great circle disk which is the intersection of the great circle with the lin...
LWPOINT * lwgeom_project_spheroid(const LWPOINT *r, const SPHEROID *spheroid, double distance, double azimuth)
Calculate a projected point given a source point, a distance and a bearing.
void point_shift(GEOGRAPHIC_POINT *p, double shift)
Shift a point around by a number of radians.
static int lwpoly_force_geodetic(LWPOLY *poly)
LWGEOM * lwgeom_segmentize_sphere(const LWGEOM *lwg_in, double max_seg_length)
Create a new, densified geometry where no segment is longer than max_seg_length.
double lwgeom_distance_spheroid(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2, const SPHEROID *spheroid, double tolerance)
Calculate the distance between two LWGEOMs, using the coordinates are longitude and latitude.
static int lwcollection_force_geodetic(LWCOLLECTION *col)
static int lwtriangle_check_geodetic(const LWTRIANGLE *triangle)
int gbox_pt_outside(const GBOX *gbox, POINT2D *pt_outside)
Given a unit geocentric gbox, return a lon/lat (degrees) coordinate point point that is guaranteed to...
double sphere_distance_cartesian(const POINT3D *s, const POINT3D *e)
Given two unit vectors, calculate their distance apart in radians.
static int ptarray_force_geodetic(POINTARRAY *pa)
void vector_rotate(const POINT3D *v1, const POINT3D *v2, double angle, POINT3D *n)
Rotates v1 through an angle (in radians) within the plane defined by v1/v2, returns the rotated vecto...
static int lwline_force_geodetic(LWLINE *line)
static int lwcollection_calculate_gbox_geodetic(const LWCOLLECTION *coll, GBOX *gbox)
double ptarray_area_sphere(const POINTARRAY *pa)
Returns the area of the ring (ring must be closed) in square radians (surface of the sphere is 4*PI).
static int point_in_cone(const POINT3D *A1, const POINT3D *A2, const POINT3D *P)
Utility function for checking if P is within the cone defined by A1/A2.
int lwpoly_covers_lwpoly(const LWPOLY *poly1, const LWPOLY *poly2)
Given a polygon1 check if all points of polygon2 are inside polygon1 and no intersections of the poly...
static int gbox_check_poles(GBOX *gbox)
Check to see if this geocentric gbox is wrapped around a pole.
int lwpoly_covers_pointarray(const LWPOLY *lwpoly, const POINTARRAY *pta)
return LW_TRUE if all points are inside the polygon
int ptarray_contains_point_sphere(const POINTARRAY *pa, const POINT2D *pt_outside, const POINT2D *pt_to_test)
This routine returns LW_TRUE if the stabline joining the pt_outside and pt_to_test crosses the ring a...
int lwgeom_calculate_gbox_geodetic(const LWGEOM *geom, GBOX *gbox)
Calculate the geodetic bounding box for an LWGEOM.
static int ptarray_check_geodetic(const POINTARRAY *pa)
static POINTARRAY * ptarray_segmentize_sphere(const POINTARRAY *pa_in, double max_seg_length)
Create a new point array with no segment longer than the input segment length (expressed in radians!...
static int lwpoint_check_geodetic(const LWPOINT *point)
int edge_point_on_plane(const GEOGRAPHIC_EDGE *e, const GEOGRAPHIC_POINT *p)
Returns true if the point p is on the great circle plane.
static double ptarray_distance_spheroid(const POINTARRAY *pa1, const POINTARRAY *pa2, const SPHEROID *s, double tolerance, int check_intersection)
double latitude_radians_normalize(double lat)
Convert a latitude to the range of -PI/2,PI/2.
void vector_scale(POINT3D *n, double scale)
Scale a vector out by a factor.
int lwgeom_check_geodetic(const LWGEOM *geom)
Check that coordinates of LWGEOM are all within the geodetic range (-180, -90, 180,...
void cart2geog(const POINT3D *p, GEOGRAPHIC_POINT *g)
Convert cartesian coordinates on unit sphere to spherical coordinates.
double gbox_angular_height(const GBOX *gbox)
Returns the angular height (latitudinal span) of the box in radians.
int lwpoly_covers_lwline(const LWPOLY *poly, const LWLINE *line)
int lwgeom_covers_lwgeom_sphere(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2)
Calculate covers predicate for two lwgeoms on the sphere.
double gbox_angular_width(const GBOX *gbox)
Returns the angular width (longitudinal span) of the box in radians.
static int lwpoint_force_geodetic(LWPOINT *point)
int lwpoly_pt_outside(const LWPOLY *poly, POINT2D *pt_outside)
int sphere_project(const GEOGRAPHIC_POINT *r, double distance, double azimuth, GEOGRAPHIC_POINT *n)
Given a starting location r, a distance and an azimuth to the new point, compute the location of the ...
void ll2cart(const POINT2D *g, POINT3D *p)
Convert lon/lat coordinates to cartesian coordinates on unit sphere.
static int lwline_calculate_gbox_geodetic(const LWLINE *line, GBOX *gbox)
static void normalize2d(POINT2D *p)
Normalize to a unit vector.
int gbox_geocentric_slow
For testing geodetic bounding box, we have a magic global variable.
int edge_point_in_cone(const GEOGRAPHIC_EDGE *e, const GEOGRAPHIC_POINT *p)
Returns true if the point p is inside the cone defined by the two ends of the edge e.
double longitude_degrees_normalize(double lon)
Convert a longitude to the range of -180,180.
double z_to_latitude(double z, int top)
Used in great circle to compute the pole of the great circle.
void robust_cross_product(const GEOGRAPHIC_POINT *p, const GEOGRAPHIC_POINT *q, POINT3D *a)
Computes the cross product of two vectors using their lat, lng representations.
static int lwpoly_pt_outside_hack(const LWPOLY *poly, POINT2D *pt_outside)
int ptarray_calculate_gbox_geodetic(const POINTARRAY *pa, GBOX *gbox)
Calculate geodetic (x/y/z) box and add values to gbox.
void geographic_point_init(double lon, double lat, GEOGRAPHIC_POINT *g)
Initialize a geographic point.
static int dot_product_side(const POINT3D *p, const POINT3D *q)
Utility function for edge_intersects(), signum with a tolerance in determining if the value is zero.
double ptarray_length_spheroid(const POINTARRAY *pa, const SPHEROID *s)
void unit_normal(const POINT3D *P1, const POINT3D *P2, POINT3D *normal)
Calculates the unit normal to two vectors, trying to avoid problems with over-narrow or over-wide cas...
int lwgeom_force_geodetic(LWGEOM *geom)
Force coordinates of LWGEOM into geodetic range (-180, -90, 180, 90)
static int ptarray_segmentize_sphere_edge_recursive(const POINT3D *p1, const POINT3D *p2, const POINT4D *v1, const POINT4D *v2, double d, double max_seg_length, POINTARRAY *pa)
static void vector_difference(const POINT3D *a, const POINT3D *b, POINT3D *n)
Calculate the difference of two vectors.
int lwgeom_nudge_geodetic(LWGEOM *geom)
When features are snapped or sometimes they are just this way, they are very close to the geodetic bo...
static void cross_product(const POINT3D *a, const POINT3D *b, POINT3D *n)
Calculate the cross product of two vectors.
static int edge_point_side(const GEOGRAPHIC_EDGE *e, const GEOGRAPHIC_POINT *p)
Returns -1 if the point is to the left of the plane formed by the edge, 1 if the point is to the righ...
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 dot_product(const POINT3D *p1, const POINT3D *p2)
Convert cartesian coordinates on unit sphere to lon/lat coordinates static void cart2ll(const POINT3D...
double sphere_direction(const GEOGRAPHIC_POINT *s, const GEOGRAPHIC_POINT *e, double d)
Given two points on a unit sphere, calculate the direction from s to e.
int edge_calculate_gbox_slow(const GEOGRAPHIC_EDGE *e, GBOX *gbox)
int edge_intersection(const GEOGRAPHIC_EDGE *e1, const GEOGRAPHIC_EDGE *e2, GEOGRAPHIC_POINT *g)
Returns true if an intersection can be calculated, and places it in *g.
void vector_sum(const POINT3D *a, const POINT3D *b, POINT3D *n)
Calculate the sum of two vectors.
static int lwtriangle_calculate_gbox_geodetic(const LWTRIANGLE *triangle, GBOX *gbox)
uint32_t edge_intersects(const POINT3D *A1, const POINT3D *A2, const POINT3D *B1, const POINT3D *B2)
Returns non-zero if edges A and B interact.
double lwgeom_length_spheroid(const LWGEOM *geom, const SPHEROID *s)
Calculate the geodetic length of a lwgeom on the unit sphere.
int edge_calculate_gbox(const POINT3D *A1, const POINT3D *A2, GBOX *gbox)
The magic function, given an edge in spherical coordinates, calculate a 3D bounding box that fully co...
double edge_distance_to_point(const GEOGRAPHIC_EDGE *e, const GEOGRAPHIC_POINT *gp, GEOGRAPHIC_POINT *closest)
void geog2cart(const GEOGRAPHIC_POINT *g, POINT3D *p)
Convert spherical coordinates to cartesian coordinates on unit sphere.
int gbox_centroid(const GBOX *gbox, POINT2D *out)
Computes the average(ish) center of the box and returns success.
static double sphere_signed_area(const GEOGRAPHIC_POINT *a, const GEOGRAPHIC_POINT *b, const GEOGRAPHIC_POINT *c)
Computes the spherical area of a triangle.
static int point3d_equals(const POINT3D *p1, const POINT3D *p2)
Utility function for ptarray_contains_point_sphere()
int lwline_covers_lwline(const LWLINE *lwline1, const LWLINE *lwline2)
Check if first and last point of line2 are covered by line1 and then each point in between has to be ...
int edge_contains_point(const GEOGRAPHIC_EDGE *e, const GEOGRAPHIC_POINT *p)
Returns true if the point p is on the minor edge defined by the end points of e.
static double sphere_angle(const GEOGRAPHIC_POINT *a, const GEOGRAPHIC_POINT *b, const GEOGRAPHIC_POINT *c)
Returns the angle in radians at point B of the triangle formed by A-B-C.
double edge_distance_to_edge(const GEOGRAPHIC_EDGE *e1, const GEOGRAPHIC_EDGE *e2, GEOGRAPHIC_POINT *closest1, GEOGRAPHIC_POINT *closest2)
Calculate the distance between two edges.
static int ptarray_nudge_geodetic(POINTARRAY *pa)
When features are snapped or sometimes they are just this way, they are very close to the geodetic bo...
int geographic_point_equals(const GEOGRAPHIC_POINT *g1, const GEOGRAPHIC_POINT *g2)
double lwgeom_azumith_spheroid(const LWPOINT *r, const LWPOINT *s, const SPHEROID *spheroid)
Calculate a bearing (azimuth) given a source and destination point.
int crosses_dateline(const GEOGRAPHIC_POINT *s, const GEOGRAPHIC_POINT *e)
static int lwpoint_calculate_gbox_geodetic(const LWPOINT *point, GBOX *gbox)
double latitude_degrees_normalize(double lat)
Convert a latitude to the range of -90,90.
double vector_angle(const POINT3D *v1, const POINT3D *v2)
Angle between two unit vectors.
int edge_contains_coplanar_point(const GEOGRAPHIC_EDGE *e, const GEOGRAPHIC_POINT *p)
True if the longitude of p is within the range of the longitude of the ends of e.
double lwgeom_area_sphere(const LWGEOM *lwgeom, const SPHEROID *spheroid)
Calculate the area of an LWGEOM.
static int lwpolygon_calculate_gbox_geodetic(const LWPOLY *poly, GBOX *gbox)
int getPoint2d_p_ro(const POINTARRAY *pa, uint32_t n, POINT2D **point)
This function can only be used on LWGEOM that is built on top of GSERIALIZED, otherwise alignment err...
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.
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.
#define deg2rad(d)
Conversion functions.
#define PIR_A_TOUCH_RIGHT
#define PIR_B_TOUCH_RIGHT
#define PIR_NO_INTERACT
Bitmask elements for edge_intersects() return value.
Datum distance(PG_FUNCTION_ARGS)
Datum area(PG_FUNCTION_ARGS)
#define LWDEBUG(level, msg)
#define LWDEBUGF(level, msg,...)
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Two-point great circle segment from a to b.
Point in spherical coordinates on the world.