28 #include "../postgis_config.h"
35 #include "utils/array.h"
36 #include "utils/builtins.h"
37 #include "utils/lsyscache.h"
38 #include "utils/numeric.h"
39 #include "access/htup_details.h"
55 #define HANDLE_GEOS_ERROR(label) \
57 if (strstr(lwgeom_geos_errmsg, "InterruptedException")) \
59 (errcode(ERRCODE_QUERY_CANCELED), errmsg("canceling statement due to user request"))); \
61 lwpgerror("%s: %s", (label), lwgeom_geos_errmsg); \
71 Datum
touches(PG_FUNCTION_ARGS);
73 Datum
crosses(PG_FUNCTION_ARGS);
75 Datum
within(PG_FUNCTION_ARGS);
77 Datum
covers(PG_FUNCTION_ARGS);
79 Datum
isvalid(PG_FUNCTION_ARGS);
82 Datum
buffer(PG_FUNCTION_ARGS);
91 Datum
isring(PG_FUNCTION_ARGS);
121 text *result = cstring_to_text(ver);
122 PG_RETURN_POINTER(result);
185 geom1 = PG_GETARG_GSERIALIZED_P(0);
186 geom2 = PG_GETARG_GSERIALIZED_P(1);
200 GEOSGeom_destroy(g1);
204 retcode = GEOSHausdorffDistance(g1, g2, &result);
205 GEOSGeom_destroy(g1);
206 GEOSGeom_destroy(g2);
210 PG_FREE_IF_COPY(geom1, 0);
211 PG_FREE_IF_COPY(geom2, 1);
213 PG_RETURN_FLOAT8(result);
235 geom1 = PG_GETARG_GSERIALIZED_P(0);
236 geom2 = PG_GETARG_GSERIALIZED_P(1);
237 densifyFrac = PG_GETARG_FLOAT8(2);
251 GEOSGeom_destroy(g1);
255 retcode = GEOSHausdorffDistanceDensify(g1, g2, densifyFrac, &result);
256 GEOSGeom_destroy(g1);
257 GEOSGeom_destroy(g2);
261 PG_FREE_IF_COPY(geom1, 0);
262 PG_FREE_IF_COPY(geom2, 1);
264 PG_RETURN_FLOAT8(result);
277 #if POSTGIS_GEOS_VERSION < 37
279 lwpgerror(
"The GEOS version this PostGIS binary "
280 "was compiled against (%d) doesn't support "
281 "'GEOSFechetDistance' function (3.7.0+ required)",
294 geom1 = PG_GETARG_GSERIALIZED_P(0);
295 geom2 = PG_GETARG_GSERIALIZED_P(1);
296 densifyFrac = PG_GETARG_FLOAT8(2);
310 GEOSGeom_destroy(g1);
314 if (densifyFrac <= 0.0)
316 retcode = GEOSFrechetDistance(g1, g2, &result);
320 retcode = GEOSFrechetDistanceDensify(g1, g2, densifyFrac, &result);
323 GEOSGeom_destroy(g1);
324 GEOSGeom_destroy(g2);
328 PG_FREE_IF_COPY(geom1, 0);
329 PG_FREE_IF_COPY(geom2, 1);
331 PG_RETURN_FLOAT8(result);
348 ArrayIterator iterator;
353 int nelems = 0, geoms_size = 0, curgeom = 0,
count = 0;
357 GEOSGeometry *g = NULL;
358 GEOSGeometry *g_union = NULL;
359 GEOSGeometry **geoms = NULL;
366 if ( PG_ARGISNULL(0) )
369 array = PG_GETARG_ARRAYTYPE_P(0);
370 nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
373 if ( nelems == 0 ) PG_RETURN_NULL();
376 iterator = array_create_iterator(array, 0, NULL);
377 while (array_iterate(iterator, &
value, &isnull))
380 if (isnull)
continue;
383 array_free_iterator(iterator);
391 if (
count == 1 && nelems == 1 )
393 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
394 #pragma GCC diagnostic push
395 #pragma GCC diagnostic ignored "-Wsign-compare"
397 PG_RETURN_POINTER((
GSERIALIZED *)(ARR_DATA_PTR(array)));
398 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
399 #pragma GCC diagnostic pop
410 geoms = palloc(
sizeof(GEOSGeometry*) * geoms_size);
416 iterator = array_create_iterator(array, 0, NULL);
417 while (array_iterate(iterator, &
value, &isnull))
422 if (isnull)
continue;
440 if (gser_type > empty_type)
442 empty_type = gser_type;
443 POSTGIS_DEBUGF(4,
"empty_type = %d gser_type = %d", empty_type, gser_type);
454 "One of the geometries in the set "
455 "could not be converted to GEOS");
459 if ( curgeom == geoms_size )
462 geoms = repalloc( geoms,
sizeof(GEOSGeometry*) * geoms_size );
470 array_free_iterator(iterator);
478 g = GEOSGeom_createCollection(GEOS_GEOMETRYCOLLECTION, geoms, curgeom);
479 if (!g)
HANDLE_GEOS_ERROR(
"Could not create GEOS COLLECTION from geometry array");
481 g_union = GEOSUnaryUnion(g);
485 GEOSSetSRID(g_union, srid);
487 GEOSGeom_destroy(g_union);
493 if ( empty_type > 0 )
510 PG_RETURN_POINTER(gser_out);
531 geoms = palloc(list_length(state->
geoms) *
sizeof(
LWGEOM*));
534 foreach (l, state->
geoms)
541 geoms[ngeoms++] = geom;
552 empty_type =
type > empty_type ?
type : empty_type;
564 GEOSGeometry *g = NULL;
565 GEOSGeometry *g_union = NULL;
573 g_union = GEOSUnaryUnion(g);
578 GEOSSetSRID(g_union, srid);
580 GEOSGeom_destroy(g_union);
601 PG_RETURN_POINTER(gser_out);
617 LWGEOM *lwgeom1, *lwresult ;
619 geom1 = PG_GETARG_GSERIALIZED_P(0);
629 PG_FREE_IF_COPY(geom1, 0);
631 PG_RETURN_POINTER(result);
640 LWGEOM *lwgeom1, *lwgeom2, *lwresult;
642 geom1 = PG_GETARG_GSERIALIZED_P(0);
643 geom2 = PG_GETARG_GSERIALIZED_P(1);
655 PG_FREE_IF_COPY(geom1, 0);
656 PG_FREE_IF_COPY(geom2, 1);
658 PG_RETURN_POINTER(result);
672 LWGEOM *lwgeom1, *lwgeom2, *lwresult ;
674 geom1 = PG_GETARG_GSERIALIZED_P(0);
675 geom2 = PG_GETARG_GSERIALIZED_P(1);
687 PG_FREE_IF_COPY(geom1, 0);
688 PG_FREE_IF_COPY(geom2, 1);
690 PG_RETURN_POINTER(result);
698 GEOSGeometry *g1, *g3;
703 geom1 = PG_GETARG_GSERIALIZED_P(0);
707 PG_RETURN_POINTER(geom1);
713 lwpgerror(
"POSTGIS2GEOS: unable to deserialize input");
723 PG_RETURN_POINTER(result);
734 g3 = GEOSBoundary(g1);
738 GEOSGeom_destroy(g1);
742 POSTGIS_DEBUGF(3,
"result: %s", GEOSGeomToWKT(g3));
744 GEOSSetSRID(g3, srid);
750 GEOSGeom_destroy(g1);
751 GEOSGeom_destroy(g3);
753 "GEOS2POSTGIS threw an error (result postgis geometry "
758 GEOSGeom_destroy(g1);
759 GEOSGeom_destroy(g3);
761 PG_FREE_IF_COPY(geom1, 0);
763 PG_RETURN_POINTER(result);
770 GEOSGeometry *g1, *g3;
776 geom1 = PG_GETARG_GSERIALIZED_P(0);
780 PG_RETURN_POINTER(geom1);
791 g3 = GEOSConvexHull(g1);
792 GEOSGeom_destroy(g1);
796 POSTGIS_DEBUGF(3,
"result: %s", GEOSGeomToWKT(g3));
798 GEOSSetSRID(g3, srid);
801 GEOSGeom_destroy(g3);
806 "convexhull() failed to convert GEOS geometry to LWGEOM");
823 elog(ERROR,
"GEOS convexhull() threw an error (result postgis geometry formation)!");
827 PG_FREE_IF_COPY(geom1, 0);
828 PG_RETURN_POINTER(result);
837 GEOSGeometry *g1, *g3;
841 gs1 = PG_GETARG_GSERIALIZED_P(0);
842 tolerance = PG_GETARG_FLOAT8(1);
848 PG_RETURN_POINTER(gs1);
852 lwpgerror(
"Geometry contains invalid coordinates");
863 g3 = GEOSTopologyPreserveSimplify(g1,tolerance);
864 GEOSGeom_destroy(g1);
868 POSTGIS_DEBUGF(3,
"result: %s", GEOSGeomToWKT(g3));
873 GEOSGeom_destroy(g3);
877 elog(ERROR,
"GEOS topologypreservesimplify() threw an error (result postgis geometry formation)!");
881 PG_FREE_IF_COPY(gs1, 0);
882 PG_RETURN_POINTER(result);
888 GEOSBufferParams *bufferparams;
889 GEOSGeometry *g1, *g3 = NULL;
906 const double DEFAULT_MITRE_LIMIT = 5.0;
907 const int DEFAULT_ENDCAP_STYLE = ENDCAP_ROUND;
908 const int DEFAULT_JOIN_STYLE = JOIN_ROUND;
909 double mitreLimit = DEFAULT_MITRE_LIMIT;
910 int endCapStyle = DEFAULT_ENDCAP_STYLE;
911 int joinStyle = DEFAULT_JOIN_STYLE;
914 double size = PG_GETARG_FLOAT8(1);
919 params_text = PG_GETARG_TEXT_P(2);
923 params_text = palloc(VARHDRSZ);
924 SET_VARSIZE(params_text, 0);
940 lwpgerror(
"Geometry contains invalid coordinates");
952 if (VARSIZE_ANY_EXHDR(params_text) > 0)
957 for (param=params; ; param=NULL)
960 param = strtok(param,
" ");
962 POSTGIS_DEBUGF(3,
"Param: %s", param);
965 val = strchr(key,
'=');
966 if (!val || *(val + 1) ==
'\0')
968 lwpgerror(
"Missing value for buffer parameter %s", key);
974 POSTGIS_DEBUGF(3,
"Param: %s : %s", key, val);
976 if ( !strcmp(key,
"endcap") )
981 if ( !strcmp(val,
"round") )
983 endCapStyle = ENDCAP_ROUND;
985 else if ( !strcmp(val,
"flat") ||
986 !strcmp(val,
"butt") )
988 endCapStyle = ENDCAP_FLAT;
990 else if ( !strcmp(val,
"square") )
992 endCapStyle = ENDCAP_SQUARE;
996 lwpgerror(
"Invalid buffer end cap "
997 "style: %s (accept: "
998 "'round', 'flat', 'butt' "
1005 else if ( !strcmp(key,
"join") )
1007 if ( !strcmp(val,
"round") )
1009 joinStyle = JOIN_ROUND;
1011 else if ( !strcmp(val,
"mitre") ||
1012 !strcmp(val,
"miter") )
1014 joinStyle = JOIN_MITRE;
1016 else if ( !strcmp(val,
"bevel") )
1018 joinStyle = JOIN_BEVEL;
1022 lwpgerror(
"Invalid buffer end cap "
1023 "style: %s (accept: "
1024 "'round', 'mitre', 'miter' "
1030 else if ( !strcmp(key,
"mitre_limit") ||
1031 !strcmp(key,
"miter_limit") )
1034 mitreLimit = atof(val);
1036 else if ( !strcmp(key,
"quad_segs") )
1039 quadsegs = atoi(val);
1041 else if ( !strcmp(key,
"side") )
1043 if ( !strcmp(val,
"both") )
1047 else if ( !strcmp(val,
"left") )
1051 else if ( !strcmp(val,
"right") )
1058 lwpgerror(
"Invalid side parameter: %s (accept: 'right', 'left', 'both')", val);
1065 "Invalid buffer parameter: %s (accept: 'endcap', 'join', 'mitre_limit', 'miter_limit', 'quad_segs' and 'side')",
1074 POSTGIS_DEBUGF(3,
"endCap:%d joinStyle:%d mitreLimit:%g",
1075 endCapStyle, joinStyle, mitreLimit);
1077 bufferparams = GEOSBufferParams_create();
1080 if (GEOSBufferParams_setEndCapStyle(bufferparams, endCapStyle) &&
1081 GEOSBufferParams_setJoinStyle(bufferparams, joinStyle) &&
1082 GEOSBufferParams_setMitreLimit(bufferparams, mitreLimit) &&
1083 GEOSBufferParams_setQuadrantSegments(bufferparams, quadsegs) &&
1084 GEOSBufferParams_setSingleSided(bufferparams, singleside))
1086 g3 = GEOSBufferWithParams(g1, bufferparams, size);
1090 lwpgerror(
"Error setting buffer parameters.");
1092 GEOSBufferParams_destroy(bufferparams);
1096 lwpgerror(
"Error setting buffer parameters.");
1099 GEOSGeom_destroy(g1);
1103 POSTGIS_DEBUGF(3,
"result: %s", GEOSGeomToWKT(g3));
1108 GEOSGeom_destroy(g3);
1112 elog(ERROR,
"GEOS buffer() threw an error (result postgis geometry formation)!");
1116 PG_FREE_IF_COPY(geom1, 0);
1117 PG_RETURN_POINTER(result);
1136 gser_input = PG_GETARG_GSERIALIZED_P(0);
1137 npoints = PG_GETARG_INT32(1);
1142 if (PG_NARGS() > 2 && ! PG_ARGISNULL(2))
1144 seed = PG_GETARG_INT32(2);
1147 lwpgerror(
"ST_GeneratePoints: seed must be greater than zero");
1156 PG_FREE_IF_COPY(gser_input, 0);
1165 PG_RETURN_POINTER(gser_result);
1191 static const double DEFAULT_MITRE_LIMIT = 5.0;
1192 static const int DEFAULT_JOIN_STYLE = JOIN_ROUND;
1193 double mitreLimit = DEFAULT_MITRE_LIMIT;
1194 int joinStyle = DEFAULT_JOIN_STYLE;
1196 char *paramstr = NULL;
1200 gser_input = PG_GETARG_GSERIALIZED_P(0);
1201 size = PG_GETARG_FLOAT8(1);
1204 if (size == 0) PG_RETURN_POINTER(gser_input);
1208 if ( ! lwgeom_input )
1209 lwpgerror(
"ST_OffsetCurve: lwgeom_from_gserialized returned NULL");
1213 PG_RETURN_POINTER(gser_input);
1218 text *wkttext = PG_GETARG_TEXT_P(2);
1221 POSTGIS_DEBUGF(3,
"paramstr: %s", paramstr);
1223 for ( param=paramstr; ; param=NULL )
1226 param = strtok(param,
" ");
1228 POSTGIS_DEBUGF(3,
"Param: %s", param);
1231 val = strchr(key,
'=');
1232 if (!val || *(val + 1) ==
'\0')
1234 lwpgerror(
"ST_OffsetCurve: Missing value for buffer parameter %s", key);
1240 POSTGIS_DEBUGF(3,
"Param: %s : %s", key, val);
1242 if ( !strcmp(key,
"join") )
1244 if ( !strcmp(val,
"round") )
1246 joinStyle = JOIN_ROUND;
1248 else if ( !(strcmp(val,
"mitre") && strcmp(val,
"miter")) )
1250 joinStyle = JOIN_MITRE;
1252 else if ( ! strcmp(val,
"bevel") )
1254 joinStyle = JOIN_BEVEL;
1259 "Invalid buffer end cap style: %s (accept: 'round', 'mitre', 'miter' or 'bevel')",
1264 else if ( !strcmp(key,
"mitre_limit") ||
1265 !strcmp(key,
"miter_limit") )
1268 mitreLimit = atof(val);
1270 else if ( !strcmp(key,
"quad_segs") )
1273 quadsegs = atoi(val);
1278 "Invalid buffer parameter: %s (accept: 'join', 'mitre_limit', 'miter_limit and 'quad_segs')",
1283 POSTGIS_DEBUGF(3,
"joinStyle:%d mitreLimit:%g", joinStyle, mitreLimit);
1287 lwgeom_result =
lwgeom_offsetcurve(lwgeom_input, size, quadsegs, joinStyle, mitreLimit);
1290 lwpgerror(
"ST_OffsetCurve: lwgeom_offsetcurve returned NULL");
1295 PG_RETURN_POINTER(gser_result);
1304 LWGEOM *lwgeom1, *lwgeom2, *lwresult;
1306 geom1 = PG_GETARG_GSERIALIZED_P(0);
1307 geom2 = PG_GETARG_GSERIALIZED_P(1);
1319 PG_FREE_IF_COPY(geom1, 0);
1320 PG_FREE_IF_COPY(geom2, 1);
1322 PG_RETURN_POINTER(result);
1331 LWGEOM *lwgeom1, *lwgeom2, *lwresult;
1333 geom1 = PG_GETARG_GSERIALIZED_P(0);
1334 geom2 = PG_GETARG_GSERIALIZED_P(1);
1346 PG_FREE_IF_COPY(geom1, 0);
1347 PG_FREE_IF_COPY(geom2, 1);
1349 PG_RETURN_POINTER(result);
1360 LWGEOM *lwgeom, *lwresult;
1362 geom = PG_GETARG_GSERIALIZED_P(0);
1367 PG_FREE_IF_COPY(geom, 0);
1369 if (!lwresult) PG_RETURN_NULL();
1373 PG_RETURN_POINTER(result);
1380 LWGEOM *lwgeom, *lwresult;
1382 geom = PG_GETARG_GSERIALIZED_P(0);
1387 PG_FREE_IF_COPY(geom, 0);
1389 if (!lwresult) PG_RETURN_NULL();
1393 PG_RETURN_POINTER(result);
1402 LWGEOM *lwgeom1, *lwresult ;
1406 geom1 = PG_GETARG_GSERIALIZED_P(0);
1414 PG_RETURN_POINTER(geom1);
1418 bbox2 = (
GBOX *)PG_GETARG_POINTER(1);
1426 PG_FREE_IF_COPY(geom1, 0);
1429 PG_RETURN_POINTER(result);
1436 PG_RETURN_POINTER(geom1);
1443 PG_FREE_IF_COPY(geom1, 0);
1445 if (!lwresult) PG_RETURN_NULL();
1449 PG_RETURN_POINTER(result);
1463 geom1 = PG_GETARG_GSERIALIZED_P(0);
1467 PG_RETURN_BOOL(
true);
1474 lwpgerror(
"unable to deserialize input");
1485 PG_RETURN_BOOL(
false);
1488 result = GEOSisValid(g1);
1489 GEOSGeom_destroy(g1);
1493 elog(ERROR,
"GEOS isvalid() threw an error!");
1497 PG_FREE_IF_COPY(geom1, 0);
1498 PG_RETURN_BOOL(result);
1505 char *reason_str = NULL;
1506 text *result = NULL;
1507 const GEOSGeometry *g1 = NULL;
1509 geom = PG_GETARG_GSERIALIZED_P(0);
1516 reason_str = GEOSisValidReason(g1);
1517 GEOSGeom_destroy((GEOSGeometry *)g1);
1519 result = cstring_to_text(reason_str);
1520 GEOSFree(reason_str);
1527 PG_FREE_IF_COPY(geom, 0);
1528 PG_RETURN_POINTER(result);
1535 const GEOSGeometry *g1 = NULL;
1537 char *geos_reason = NULL;
1538 char *reason = NULL;
1539 GEOSGeometry *geos_location = NULL;
1542 HeapTupleHeader result;
1545 AttInMetadata *attinmeta;
1552 get_call_result_type(fcinfo, 0, &tupdesc);
1553 BlessTupleDesc(tupdesc);
1559 attinmeta = TupleDescGetAttInMetadata(tupdesc);
1561 geom = PG_GETARG_GSERIALIZED_P(0);
1562 flags = PG_GETARG_INT32(1);
1570 valid = GEOSisValidDetail(g1, flags, &geos_reason, &geos_location);
1571 GEOSGeom_destroy((GEOSGeometry *)g1);
1574 reason = pstrdup(geos_reason);
1575 GEOSFree(geos_reason);
1577 if ( geos_location )
1579 location =
GEOS2LWGEOM(geos_location, GEOSHasZ(geos_location));
1580 GEOSGeom_destroy(geos_location);
1586 lwpgerror(
"GEOS isvaliddetail() threw an exception!");
1597 values[0] = valid ?
"t" :
"f";
1605 tuple = BuildTupleFromCStrings(attinmeta, values);
1606 result = (HeapTupleHeader) palloc(tuple->t_len);
1607 memcpy(result, tuple->t_data, tuple->t_len);
1608 heap_freetuple(tuple);
1610 PG_RETURN_HEAPTUPLEHEADER(result);
1625 GEOSGeometry *g1, *g2;
1629 geom1 = PG_GETARG_GSERIALIZED_P(0);
1630 geom2 = PG_GETARG_GSERIALIZED_P(1);
1635 PG_RETURN_BOOL(
false);
1646 PG_RETURN_BOOL(
false);
1660 GEOSGeom_destroy(g1);
1664 result = GEOSOverlaps(g1,g2);
1666 GEOSGeom_destroy(g1);
1667 GEOSGeom_destroy(g2);
1670 PG_FREE_IF_COPY(geom1, 0);
1671 PG_FREE_IF_COPY(geom2, 1);
1673 PG_RETURN_BOOL(result);
1683 GEOSGeometry *g1, *g2;
1690 PG_RETURN_BOOL(
false);
1692 POSTGIS_DEBUG(3,
"contains called.");
1702 PG_RETURN_BOOL(
false);
1716 POSTGIS_DEBUG(3,
"Point in Polygon test requested...short-circuiting.");
1723 retval = (pip_result == 1);
1729 int found_completely_inside =
LW_FALSE;
1732 for (i = 0; i < mpoint->
ngeoms; i++)
1740 if (pip_result == 1)
1741 found_completely_inside =
LW_TRUE;
1743 if (pip_result == -1)
1750 retval = retval && found_completely_inside;
1756 elog(ERROR,
"Type isn't point or multipoint!");
1757 PG_RETURN_BOOL(
false);
1777 POSTGIS_DEBUG(4,
"containsPrepared: cache is live, running preparedcontains");
1778 result = GEOSPreparedContains( prep_cache->
prepared_geom, g1);
1779 GEOSGeom_destroy(g1);
1784 if (!g1)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
1789 GEOSGeom_destroy(g1);
1791 POSTGIS_DEBUG(4,
"containsPrepared: cache is not ready, running standard contains");
1792 result = GEOSContains( g1, g2);
1793 GEOSGeom_destroy(g1);
1794 GEOSGeom_destroy(g2);
1799 PG_FREE_IF_COPY(geom1, 0);
1800 PG_FREE_IF_COPY(geom2, 1);
1801 PG_RETURN_BOOL(result > 0);
1808 PG_RETURN_DATUM(CallerFInfoFunctionCall2(
contains, fcinfo->flinfo, InvalidOid,
1809 PG_GETARG_DATUM(1), PG_GETARG_DATUM(0)));
1823 geom1 = PG_GETARG_GSERIALIZED_P(0);
1824 geom2 = PG_GETARG_GSERIALIZED_P(1);
1829 PG_RETURN_BOOL(
false);
1839 PG_RETURN_BOOL(
false);
1849 if (!g)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
1850 result = GEOSPreparedContainsProperly( prep_cache->
prepared_geom, g);
1851 GEOSGeom_destroy(g);
1859 if (!g1)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
1863 GEOSGeom_destroy(g1);
1866 result = GEOSRelatePattern( g1, g2,
"T**FF*FF*" );
1867 GEOSGeom_destroy(g1);
1868 GEOSGeom_destroy(g2);
1873 PG_FREE_IF_COPY(geom1, 0);
1874 PG_FREE_IF_COPY(geom2, 1);
1876 PG_RETURN_BOOL(result);
1892 geom1 = PG_GETARG_GSERIALIZED_P(0);
1893 geom2 = PG_GETARG_GSERIALIZED_P(1);
1897 PG_RETURN_BOOL(
false);
1910 PG_RETURN_BOOL(
false);
1924 POSTGIS_DEBUG(3,
"Point in Polygon test requested...short-circuiting.");
1931 retval = (pip_result != -1);
1939 for (i = 0; i < mpoint->
ngeoms; i++)
1942 if (pip_result == -1)
1954 elog(ERROR,
"Type isn't point or multipoint!");
1958 PG_FREE_IF_COPY(geom1, 0);
1959 PG_FREE_IF_COPY(geom2, 1);
1960 PG_RETURN_BOOL(retval);
1974 if (!g1)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
1975 result = GEOSPreparedCovers( prep_cache->
prepared_geom, g1);
1976 GEOSGeom_destroy(g1);
1984 if (!g1)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
1988 GEOSGeom_destroy(g1);
1991 result = GEOSRelatePattern( g1, g2,
"******FF*" );
1992 GEOSGeom_destroy(g1);
1993 GEOSGeom_destroy(g2);
1998 PG_FREE_IF_COPY(geom1, 0);
1999 PG_FREE_IF_COPY(geom2, 1);
2001 PG_RETURN_BOOL(result);
2022 GEOSGeometry *g1, *g2;
2025 char *patt =
"**F**F***";
2027 geom1 = PG_GETARG_GSERIALIZED_P(0);
2028 geom2 = PG_GETARG_GSERIALIZED_P(1);
2033 PG_RETURN_BOOL(
false);
2044 PG_RETURN_BOOL(
false);
2047 POSTGIS_DEBUG(3,
"bounding box short-circuit missed.");
2060 POSTGIS_DEBUG(3,
"Point in Polygon test requested...short-circuiting.");
2067 retval = (pip_result != -1);
2075 for (i = 0; i < mpoint->
ngeoms; i++)
2078 if (pip_result == -1)
2090 elog(ERROR,
"Type isn't point or multipoint!");
2094 PG_FREE_IF_COPY(geom1, 0);
2095 PG_FREE_IF_COPY(geom2, 1);
2096 PG_RETURN_BOOL(retval);
2114 GEOSGeom_destroy(g1);
2118 result = GEOSRelatePattern(g1,g2,patt);
2120 GEOSGeom_destroy(g1);
2121 GEOSGeom_destroy(g2);
2125 PG_FREE_IF_COPY(geom1, 0);
2126 PG_FREE_IF_COPY(geom2, 1);
2128 PG_RETURN_BOOL(result);
2136 GEOSGeometry *g1, *g2;
2140 geom1 = PG_GETARG_GSERIALIZED_P(0);
2141 geom2 = PG_GETARG_GSERIALIZED_P(1);
2146 PG_RETURN_BOOL(
false);
2157 PG_RETURN_BOOL(
false);
2170 GEOSGeom_destroy(g1);
2174 result = GEOSCrosses(g1,g2);
2176 GEOSGeom_destroy(g1);
2177 GEOSGeom_destroy(g2);
2181 PG_FREE_IF_COPY(geom1, 0);
2182 PG_FREE_IF_COPY(geom2, 1);
2184 PG_RETURN_BOOL(result);
2196 geom1 = PG_GETARG_GSERIALIZED_P(0);
2197 geom2 = PG_GETARG_GSERIALIZED_P(1);
2202 PG_RETURN_BOOL(
false);
2212 PG_RETURN_BOOL(
false);
2226 POSTGIS_DEBUG(3,
"Point in Polygon test requested...short-circuiting.");
2233 retval = (pip_result != -1);
2241 for (i = 0; i < mpoint->
ngeoms; i++)
2244 if (pip_result != -1)
2256 elog(ERROR,
"Type isn't point or multipoint!");
2260 PG_FREE_IF_COPY(geom1, 0);
2261 PG_FREE_IF_COPY(geom2, 1);
2262 PG_RETURN_BOOL(retval);
2270 if ( prep_cache->
gcache.argnum == 1 )
2274 result = GEOSPreparedIntersects( prep_cache->
prepared_geom, g);
2275 GEOSGeom_destroy(g);
2282 result = GEOSPreparedIntersects( prep_cache->
prepared_geom, g);
2283 GEOSGeom_destroy(g);
2291 if (!g1)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
2295 GEOSGeom_destroy(g1);
2298 result = GEOSIntersects( g1, g2);
2299 GEOSGeom_destroy(g1);
2300 GEOSGeom_destroy(g2);
2305 PG_FREE_IF_COPY(geom1, 0);
2306 PG_FREE_IF_COPY(geom2, 1);
2308 PG_RETURN_BOOL(result);
2317 GEOSGeometry *g1, *g2;
2321 geom1 = PG_GETARG_GSERIALIZED_P(0);
2322 geom2 = PG_GETARG_GSERIALIZED_P(1);
2327 PG_RETURN_BOOL(
false);
2338 PG_RETURN_BOOL(
false);
2351 GEOSGeom_destroy(g1);
2355 result = GEOSTouches(g1,g2);
2357 GEOSGeom_destroy(g1);
2358 GEOSGeom_destroy(g2);
2362 PG_FREE_IF_COPY(geom1, 0);
2363 PG_FREE_IF_COPY(geom2, 1);
2365 PG_RETURN_BOOL(result);
2374 GEOSGeometry *g1, *g2;
2378 geom1 = PG_GETARG_GSERIALIZED_P(0);
2379 geom2 = PG_GETARG_GSERIALIZED_P(1);
2384 PG_RETURN_BOOL(
true);
2395 PG_RETURN_BOOL(
true);
2408 GEOSGeom_destroy(g1);
2412 result = GEOSDisjoint(g1,g2);
2414 GEOSGeom_destroy(g1);
2415 GEOSGeom_destroy(g2);
2419 PG_FREE_IF_COPY(geom1, 0);
2420 PG_FREE_IF_COPY(geom2, 1);
2422 PG_RETURN_BOOL(result);
2433 GEOSGeometry *g1, *g2;
2436 geom1 = PG_GETARG_GSERIALIZED_P(0);
2437 geom2 = PG_GETARG_GSERIALIZED_P(1);
2450 GEOSGeom_destroy(g1);
2454 patt = DatumGetCString(DirectFunctionCall1(textout,
2455 PointerGetDatum(PG_GETARG_DATUM(2))));
2460 for ( i = 0; i < strlen(patt); i++ )
2462 if ( patt[i] ==
't' ) patt[i] =
'T';
2463 if ( patt[i] ==
'f' ) patt[i] =
'F';
2466 result = GEOSRelatePattern(g1,g2,patt);
2467 GEOSGeom_destroy(g1);
2468 GEOSGeom_destroy(g2);
2473 PG_FREE_IF_COPY(geom1, 0);
2474 PG_FREE_IF_COPY(geom2, 1);
2476 PG_RETURN_BOOL(result);
2486 GEOSGeometry *g1, *g2;
2489 int bnr = GEOSRELATE_BNR_OGC;
2492 geom1 = PG_GETARG_GSERIALIZED_P(0);
2493 geom2 = PG_GETARG_GSERIALIZED_P(1);
2496 if ( PG_NARGS() > 2 )
2497 bnr = PG_GETARG_INT32(2);
2507 GEOSGeom_destroy(g1);
2511 POSTGIS_DEBUG(3,
"constructed geometries ");
2513 POSTGIS_DEBUGF(3,
"%s", GEOSGeomToWKT(g1));
2514 POSTGIS_DEBUGF(3,
"%s", GEOSGeomToWKT(g2));
2516 relate_str = GEOSRelateBoundaryNodeRule(g1, g2, bnr);
2518 GEOSGeom_destroy(g1);
2519 GEOSGeom_destroy(g2);
2523 result = cstring_to_text(relate_str);
2524 GEOSFree(relate_str);
2526 PG_FREE_IF_COPY(geom1, 0);
2527 PG_FREE_IF_COPY(geom2, 1);
2529 PG_RETURN_TEXT_P(result);
2538 GEOSGeometry *g1, *g2;
2542 geom1 = PG_GETARG_GSERIALIZED_P(0);
2543 geom2 = PG_GETARG_GSERIALIZED_P(1);
2548 PG_RETURN_BOOL(
true);
2559 PG_RETURN_BOOL(
false);
2567 if (VARSIZE(geom1) == VARSIZE(geom2) && !memcmp(geom1, geom2, VARSIZE(geom1))) {
2568 PG_RETURN_BOOL(
true);
2582 GEOSGeom_destroy(g1);
2586 result = GEOSEquals(g1,g2);
2588 GEOSGeom_destroy(g1);
2589 GEOSGeom_destroy(g2);
2593 PG_FREE_IF_COPY(geom1, 0);
2594 PG_FREE_IF_COPY(geom2, 1);
2596 PG_RETURN_BOOL(result);
2606 POSTGIS_DEBUG(2,
"issimple called");
2608 geom = PG_GETARG_GSERIALIZED_P(0);
2611 PG_RETURN_BOOL(
true);
2616 PG_FREE_IF_COPY(geom, 0);
2622 PG_RETURN_BOOL(result);
2632 geom = PG_GETARG_GSERIALIZED_P(0);
2636 PG_RETURN_BOOL(
false);
2644 if ( GEOSGeomTypeId(g1) != GEOS_LINESTRING )
2646 GEOSGeom_destroy(g1);
2647 elog(ERROR,
"ST_IsRing() should only be called on a linear feature");
2650 result = GEOSisRing(g1);
2651 GEOSGeom_destroy(g1);
2655 PG_FREE_IF_COPY(geom, 0);
2656 PG_RETURN_BOOL(result);
2668 lwpgerror(
"%s: GEOS2LWGEOM returned NULL", __func__);
2672 POSTGIS_DEBUGF(4,
"%s: GEOS2LWGEOM returned a %s", __func__,
lwgeom_summary(lwgeom, 0));
2692 lwpgerror(
"POSTGIS2GEOS: unable to deserialize input");
2702 ArrayIterator iterator;
2705 uint32_t nelems_not_null = 0;
2706 iterator = array_create_iterator(array, 0, NULL);
2707 while(array_iterate(iterator, &
value, &isnull) )
2711 array_free_iterator(iterator);
2713 return nelems_not_null;
2719 ArrayIterator iterator;
2722 bool gotsrid =
false;
2727 iterator = array_create_iterator(array, 0, NULL);
2729 while (array_iterate(iterator, &
value, &isnull))
2741 lwpgerror(
"Geometry deserializing geometry");
2759 GEOSGeometry**
ARRAY2GEOS(ArrayType* array, uint32_t nelems,
int* is3d,
int* srid)
2761 ArrayIterator iterator;
2764 bool gotsrid =
false;
2767 GEOSGeometry** geos_geoms = palloc(nelems *
sizeof(GEOSGeometry*));
2769 iterator = array_create_iterator(array, 0, NULL);
2771 while(array_iterate(iterator, &
value, &isnull))
2784 lwpgerror(
"Geometry could not be converted to GEOS");
2786 for (j = 0; j < i; j++) {
2787 GEOSGeom_destroy(geos_geoms[j]);
2800 for (j = 0; j <= i; j++) {
2801 GEOSGeom_destroy(geos_geoms[j]);
2810 array_free_iterator(iterator);
2818 GEOSGeometry *geosgeom;
2823 geom = PG_GETARG_GSERIALIZED_P(0);
2825 if ( ! geosgeom ) PG_RETURN_NULL();
2828 GEOSGeom_destroy(geosgeom);
2830 PG_FREE_IF_COPY(geom, 0);
2832 PG_RETURN_POINTER(lwgeom_result);
2842 GEOSGeometry *geos_result;
2843 const GEOSGeometry **vgeoms;
2845 #if POSTGIS_DEBUG_LEVEL >= 3
2849 #if POSTGIS_DEBUG_LEVEL >= 3
2853 if (PG_ARGISNULL(0))
2856 array = PG_GETARG_ARRAYTYPE_P(0);
2862 POSTGIS_DEBUGF(3,
"polygonize_garray: number of non-null elements: %d", nelems);
2867 vgeoms = (
const GEOSGeometry**)
ARRAY2GEOS(array, nelems, &is3d, &srid);
2869 POSTGIS_DEBUG(3,
"polygonize_garray: invoking GEOSpolygonize");
2871 geos_result = GEOSPolygonize(vgeoms, nelems);
2873 POSTGIS_DEBUG(3,
"polygonize_garray: GEOSpolygonize returned");
2875 for (i=0; i<nelems; ++i) GEOSGeom_destroy((GEOSGeometry *)vgeoms[i]);
2878 if ( ! geos_result ) PG_RETURN_NULL();
2880 GEOSSetSRID(geos_result, srid);
2882 GEOSGeom_destroy(geos_result);
2885 elog(ERROR,
"%s returned an error", __func__);
2889 PG_RETURN_POINTER(result);
2896 Datum* result_array_data;
2897 ArrayType *array, *result;
2899 uint32 nelems, nclusters, i;
2900 GEOSGeometry **geos_inputs, **geos_results;
2909 if (PG_ARGISNULL(0))
2912 array = PG_GETARG_ARRAYTYPE_P(0);
2915 POSTGIS_DEBUGF(3,
"clusterintersecting_garray: number of non-null elements: %d", nelems);
2917 if ( nelems == 0 ) PG_RETURN_NULL();
2924 geos_inputs =
ARRAY2GEOS(array, nelems, &is3d, &srid);
2932 elog(ERROR,
"clusterintersecting: Error performing clustering");
2937 if (!geos_results) PG_RETURN_NULL();
2939 result_array_data = palloc(nclusters *
sizeof(Datum));
2940 for (i=0; i<nclusters; ++i)
2942 result_array_data[i] = PointerGetDatum(
GEOS2POSTGIS(geos_results[i], is3d));
2943 GEOSGeom_destroy(geos_results[i]);
2947 get_typlenbyvalalign(array->elemtype, &elmlen, &elmbyval, &elmalign);
2948 result = construct_array(result_array_data, nclusters, array->elemtype, elmlen, elmbyval, elmalign);
2952 elog(ERROR,
"clusterintersecting: Error constructing return-array");
2956 PG_RETURN_POINTER(result);
2962 Datum* result_array_data;
2963 ArrayType *array, *result;
2965 uint32 nelems, nclusters, i;
2977 if (PG_ARGISNULL(0))
2980 array = PG_GETARG_ARRAYTYPE_P(0);
2982 tolerance = PG_GETARG_FLOAT8(1);
2985 lwpgerror(
"Tolerance must be a positive number.");
2991 POSTGIS_DEBUGF(3,
"cluster_within_distance_garray: number of non-null elements: %d", nelems);
2993 if ( nelems == 0 ) PG_RETURN_NULL();
3008 elog(ERROR,
"cluster_within: Error performing clustering");
3013 if (!lw_results) PG_RETURN_NULL();
3015 result_array_data = palloc(nclusters *
sizeof(Datum));
3016 for (i=0; i<nclusters; ++i)
3023 get_typlenbyvalalign(array->elemtype, &elmlen, &elmbyval, &elmalign);
3024 result = construct_array(result_array_data, nclusters, array->elemtype, elmlen, elmbyval, elmalign);
3028 elog(ERROR,
"clusterwithin: Error constructing return-array");
3032 PG_RETURN_POINTER(result);
3040 LWGEOM *lwgeom1, *lwresult ;
3042 geom1 = PG_GETARG_GSERIALIZED_P(0);
3053 PG_FREE_IF_COPY(geom1, 0);
3055 PG_RETURN_POINTER(result);
3070 LWGEOM *lwgeom_in, *lwgeom_out;
3072 geom = PG_GETARG_GSERIALIZED_P(0);
3080 PG_FREE_IF_COPY(geom, 0);
3087 PG_FREE_IF_COPY(geom, 0);
3088 PG_RETURN_POINTER(result);
3100 LWGEOM *lwgeom_in, *lwgeom_out;
3101 double tolerance = 0.0;
3104 geom = PG_GETARG_GSERIALIZED_P(0);
3105 tolerance = PG_GETARG_FLOAT8(1);
3106 flags = PG_GETARG_INT32(2);
3114 PG_FREE_IF_COPY(geom, 0);
3121 PG_FREE_IF_COPY(geom, 0);
3122 PG_RETURN_POINTER(result);
3130 Datum
ST_Snap(PG_FUNCTION_ARGS);
3135 LWGEOM *lwgeom1, *lwgeom2, *lwresult;
3138 geom1 = PG_GETARG_GSERIALIZED_P(0);
3139 geom2 = PG_GETARG_GSERIALIZED_P(1);
3140 tolerance = PG_GETARG_FLOAT8(2);
3145 lwresult =
lwgeom_snap(lwgeom1, lwgeom2, tolerance);
3148 PG_FREE_IF_COPY(geom1, 0);
3149 PG_FREE_IF_COPY(geom2, 1);
3154 PG_RETURN_POINTER(result);
3186 LWGEOM *lwgeom_in, *lwblade_in, *lwgeom_out;
3188 in = PG_GETARG_GSERIALIZED_P(0);
3189 blade_in = PG_GETARG_GSERIALIZED_P(1);
3197 lwpgerror(
"Input Geometry contains invalid coordinates");
3203 lwpgerror(
"Blade Geometry contains invalid coordinates");
3214 PG_FREE_IF_COPY(in, 0);
3215 PG_FREE_IF_COPY(blade_in, 1);
3221 PG_FREE_IF_COPY(in, 0);
3222 PG_FREE_IF_COPY(blade_in, 1);
3224 PG_RETURN_POINTER(out);
3247 LWGEOM *g1, *g2, *lwgeom_out;
3249 geom1 = PG_GETARG_GSERIALIZED_P(0);
3250 geom2 = PG_GETARG_GSERIALIZED_P(1);
3261 PG_FREE_IF_COPY(geom1, 0);
3262 PG_FREE_IF_COPY(geom2, 1);
3269 PG_FREE_IF_COPY(geom1, 0);
3270 PG_FREE_IF_COPY(geom2, 1);
3271 PG_RETURN_POINTER(out);
3283 Datum
ST_Node(PG_FUNCTION_ARGS);
3290 geom1 = PG_GETARG_GSERIALIZED_P(0);
3299 PG_FREE_IF_COPY(geom1, 0);
3306 PG_FREE_IF_COPY(geom1, 0);
3307 PG_RETURN_POINTER(out);
3329 int custom_clip_envelope;
3330 int return_polygons;
3333 if (PG_ARGISNULL(0))
3337 if (PG_ARGISNULL(2))
3339 lwpgerror(
"Tolerance must be a positive number.");
3343 tolerance = PG_GETARG_FLOAT8(2);
3347 lwpgerror(
"Tolerance must be a positive number.");
3352 if (PG_ARGISNULL(3))
3354 lwpgerror(
"return_polygons must be true or false.");
3357 return_polygons = PG_GETARG_BOOL(3);
3360 custom_clip_envelope = !PG_ARGISNULL(1);
3361 if (custom_clip_envelope) {
3362 clip = PG_GETARG_GSERIALIZED_P(1);
3365 lwpgerror(
"Could not determine envelope of clipping geometry.");
3366 PG_FREE_IF_COPY(clip, 1);
3369 PG_FREE_IF_COPY(clip, 1);
3373 input = PG_GETARG_GSERIALIZED_P(0);
3379 lwpgerror(
"Could not read input geometry.");
3380 PG_FREE_IF_COPY(input, 0);
3384 lwgeom_result =
lwgeom_voronoi_diagram(lwgeom_input, custom_clip_envelope ? &clip_envelope : NULL, tolerance, !return_polygons);
3389 lwpgerror(
"Error computing Voronoi diagram.");
3390 PG_FREE_IF_COPY(input, 0);
3397 PG_FREE_IF_COPY(input, 0);
3398 PG_RETURN_POINTER(result);
3413 GEOSGeometry* input_geos;
3419 input = PG_GETARG_GSERIALIZED_P(0);
3424 error = GEOSMinimumClearance(input_geos, &result);
3425 GEOSGeom_destroy(input_geos);
3428 PG_FREE_IF_COPY(input, 0);
3429 PG_RETURN_FLOAT8(result);
3445 GEOSGeometry* input_geos;
3446 GEOSGeometry* result_geos;
3451 input = PG_GETARG_GSERIALIZED_P(0);
3457 result_geos = GEOSMinimumClearanceLine(input_geos);
3458 GEOSGeom_destroy(input_geos);
3462 GEOSSetSRID(result_geos, srid);
3464 GEOSGeom_destroy(result_geos);
3466 PG_FREE_IF_COPY(input, 0);
3467 PG_RETURN_POINTER(result);
3481 GEOSGeometry* input_geos;
3482 GEOSGeometry* result_geos;
3487 input = PG_GETARG_GSERIALIZED_P(0);
3493 result_geos = GEOSMinimumRotatedRectangle(input_geos);
3494 GEOSGeom_destroy(input_geos);
3498 GEOSSetSRID(result_geos, srid);
3500 GEOSGeom_destroy(result_geos);
3502 PG_FREE_IF_COPY(input, 0);
3503 PG_RETURN_POINTER(result);
int gbox_overlaps_2d(const GBOX *g1, const GBOX *g2)
Return LW_TRUE if the GBOX overlaps on the 2d plane, LW_FALSE otherwise.
GBOX * gbox_copy(const GBOX *box)
Return a copy of the GBOX, based on dimensionality of flags.
int gbox_same_2d_float(const GBOX *g1, const GBOX *g2)
Check if two given GBOX are the same in x and y, or would round to the same GBOX in x and if serializ...
int gbox_contains_2d(const GBOX *g1, const GBOX *g2)
Return LW_TRUE if the first GBOX contains the second on the 2d plane, LW_FALSE otherwise.
void gserialized_error_if_srid_mismatch(const GSERIALIZED *g1, const GSERIALIZED *g2, const char *funcname)
void gserialized_error_if_srid_mismatch_reference(const GSERIALIZED *g1, const int32_t srid2, const char *funcname)
int32_t gserialized_get_srid(const GSERIALIZED *g)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
int gserialized_get_gbox_p(const GSERIALIZED *g, GBOX *gbox)
Read the box from the GSERIALIZED or calculate it if necessary.
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
int gserialized_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
int gserialized_has_z(const GSERIALIZED *g)
Check if a GSERIALIZED has a Z ordinate.
uint32_t gserialized_get_type(const GSERIALIZED *g)
Extract the geometry type from the serialized form (it hides in the anonymous data area,...
char lwgeom_geos_errmsg[LWGEOM_GEOS_ERRMSG_MAXSIZE]
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, uint8_t autofix)
LWGEOM * GEOS2LWGEOM(const GEOSGeometry *geom, uint8_t want3d)
void lwgeom_geos_error(const char *fmt,...)
int cluster_within_distance(LWGEOM **geoms, uint32_t num_geoms, double tolerance, LWGEOM ***clusterGeoms, uint32_t *num_clusters)
Takes an array of LWGEOM* and constructs an array of LWGEOM*, where each element in the constructed a...
int cluster_intersecting(GEOSGeometry **geoms, uint32_t num_geoms, GEOSGeometry ***clusterGeoms, uint32_t *num_clusters)
Takes an array of GEOSGeometry* and constructs an array of GEOSGeometry*, where each element in the c...
LWGEOM * lwgeom_centroid(const LWGEOM *geom)
int32_t lwgeom_get_srid(const LWGEOM *geom)
Return SRID number.
LWGEOM * lwgeom_delaunay_triangulation(const LWGEOM *geom, double tolerance, int32_t edgeOnly)
Take vertices of a geometry and build a delaunay triangulation on them.
LWGEOM * lwgeom_node(const LWGEOM *lwgeom_in)
void lwmpoint_free(LWMPOINT *mpt)
LWGEOM * lwgeom_symdifference(const LWGEOM *geom1, const LWGEOM *geom2)
LWMPOINT * lwgeom_as_lwmpoint(const LWGEOM *lwgeom)
void lwgeom_free(LWGEOM *geom)
LWGEOM * lwgeom_split(const LWGEOM *lwgeom_in, const LWGEOM *blade_in)
LWGEOM * lwgeom_intersection(const LWGEOM *geom1, const LWGEOM *geom2)
LWGEOM * lwgeom_offsetcurve(const LWGEOM *geom, double size, int quadsegs, int joinStyle, double mitreLimit)
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
int lwgeom_is_simple(const LWGEOM *lwgeom)
LWGEOM * lwgeom_snap(const LWGEOM *geom1, const LWGEOM *geom2, double tolerance)
Snap vertices and segments of a geometry to another using a given tolerance.
LWGEOM * lwgeom_difference(const LWGEOM *geom1, const LWGEOM *geom2)
const char * lwgeom_geos_version(void)
Return GEOS version string (not to be freed)
LWMPOLY * lwgeom_as_lwmpoly(const LWGEOM *lwgeom)
int lwgeom_needs_bbox(const LWGEOM *geom)
Check whether or not a lwgeom is big enough to warrant a bounding box.
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
int lwgeom_isfinite(const LWGEOM *lwgeom)
Check if a LWGEOM has any non-finite (NaN or Inf) coordinates.
char * lwgeom_summary(const LWGEOM *lwgeom, int offset)
LWGEOM * lwgeom_pointonsurface(const LWGEOM *geom)
LWGEOM * lwgeom_sharedpaths(const LWGEOM *geom1, const LWGEOM *geom2)
LWGEOM * lwgeom_voronoi_diagram(const LWGEOM *g, const GBOX *env, double tolerance, int output_edges)
Take vertices of a geometry and build the Voronoi diagram.
LWGEOM * lwgeom_unaryunion(const LWGEOM *geom1)
LWGEOM * lwgeom_buildarea(const LWGEOM *geom)
Take a geometry and return an areal geometry (Polygon or MultiPolygon).
char * lwgeom_to_hexwkb(const LWGEOM *geom, uint8_t variant, size_t *size_out)
const GBOX * lwgeom_get_bbox(const LWGEOM *lwgeom)
Get a non-empty geometry bounding box, computing and caching it if not already there.
LWGEOM * lwgeom_linemerge(const LWGEOM *geom1)
LWCOLLECTION * lwcollection_construct(uint8_t type, int32_t srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
LWGEOM * lwgeom_clip_by_rect(const LWGEOM *geom1, double x0, double y0, double x1, double y1)
LWMPOINT * lwgeom_to_points(const LWGEOM *lwgeom, uint32_t npoints, int32_t seed)
#define LW_TRUE
Return types for functions with status returns.
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
#define SRID_UNKNOWN
Unknown SRID value.
LWPOLY * lwpoly_construct_empty(int32_t srid, char hasz, char hasm)
LWGEOM * lwgeom_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
LWGEOM * lwgeom_union(const LWGEOM *geom1, const LWGEOM *geom2)
This library is the generic geometry handling section of PostGIS.
int point_in_multipolygon(LWMPOLY *mpolygon, LWPOINT *point)
int point_in_multipolygon_rtree(RTREE_NODE **root, int polyCount, int *ringCounts, LWPOINT *point)
int point_in_polygon(LWPOLY *polygon, LWPOINT *point)
PrepGeomCache * GetPrepGeomCache(FunctionCallInfo fcinfo, GSERIALIZED *g1, GSERIALIZED *g2)
Given a couple potential geometries and a function call context, return a prepared structure for one ...
RTREE_POLY_CACHE * GetRtreeCache(FunctionCallInfo fcinfo, GSERIALIZED *g1)
Checks for a cache hit against the provided geometry and returns a pre-built index structure (RTREE_P...
static uint32_t lwgeom_get_type(const LWGEOM *geom)
Return LWTYPE number.
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 LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
uint32_t array_nelems_not_null(ArrayType *array)
Datum polygonize_garray(PG_FUNCTION_ARGS)
static int pip_short_circuit(RTREE_POLY_CACHE *poly_cache, LWPOINT *point, GSERIALIZED *gpoly)
Datum contains(PG_FUNCTION_ARGS)
Datum coveredby(PG_FUNCTION_ARGS)
Datum ST_Intersection(PG_FUNCTION_ARGS)
Datum isvaliddetail(PG_FUNCTION_ARGS)
#define HANDLE_GEOS_ERROR(label)
Datum isvalid(PG_FUNCTION_ARGS)
static char is_point(const GSERIALIZED *g)
Datum ST_Snap(PG_FUNCTION_ARGS)
Datum ST_Union(PG_FUNCTION_ARGS)
Datum ST_BuildArea(PG_FUNCTION_ARGS)
Datum ST_Split(PG_FUNCTION_ARGS)
Datum covers(PG_FUNCTION_ARGS)
Datum ST_Node(PG_FUNCTION_ARGS)
Datum ST_GeneratePoints(PG_FUNCTION_ARGS)
Datum hausdorffdistancedensify(PG_FUNCTION_ARGS)
Datum ST_OffsetCurve(PG_FUNCTION_ARGS)
Datum cluster_within_distance_garray(PG_FUNCTION_ARGS)
Datum centroid(PG_FUNCTION_ARGS)
Datum touches(PG_FUNCTION_ARGS)
Datum disjoint(PG_FUNCTION_ARGS)
Datum ST_MinimumClearance(PG_FUNCTION_ARGS)
Datum ST_Intersects(PG_FUNCTION_ARGS)
Datum GEOSnoop(PG_FUNCTION_ARGS)
Datum ST_FrechetDistance(PG_FUNCTION_ARGS)
Datum buffer(PG_FUNCTION_ARGS)
Datum convexhull(PG_FUNCTION_ARGS)
GEOSGeometry * POSTGIS2GEOS(GSERIALIZED *pglwgeom)
Datum ST_ClipByBox2d(PG_FUNCTION_ARGS)
Datum crosses(PG_FUNCTION_ARGS)
Datum relate_full(PG_FUNCTION_ARGS)
Datum relate_pattern(PG_FUNCTION_ARGS)
Datum issimple(PG_FUNCTION_ARGS)
Datum symdifference(PG_FUNCTION_ARGS)
LWGEOM ** ARRAY2LWGEOM(ArrayType *array, uint32_t nelems, int *is3d, int *srid)
Datum topologypreservesimplify(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(postgis_geos_version)
GSERIALIZED * GEOS2POSTGIS(GEOSGeom geom, char want3d)
Datum ST_DelaunayTriangles(PG_FUNCTION_ARGS)
static char is_poly(const GSERIALIZED *g)
Datum boundary(PG_FUNCTION_ARGS)
Datum postgis_geos_version(PG_FUNCTION_ARGS)
Datum ST_UnaryUnion(PG_FUNCTION_ARGS)
Datum overlaps(PG_FUNCTION_ARGS)
Datum ST_Equals(PG_FUNCTION_ARGS)
Datum within(PG_FUNCTION_ARGS)
Datum ST_OrientedEnvelope(PG_FUNCTION_ARGS)
Datum ST_SharedPaths(PG_FUNCTION_ARGS)
Datum ST_MinimumClearanceLine(PG_FUNCTION_ARGS)
Datum ST_Voronoi(PG_FUNCTION_ARGS)
Datum clusterintersecting_garray(PG_FUNCTION_ARGS)
Datum pgis_geometry_union_finalfn(PG_FUNCTION_ARGS)
GEOSGeometry ** ARRAY2GEOS(ArrayType *array, uint32_t nelems, int *is3d, int *srid)
Datum ST_Difference(PG_FUNCTION_ARGS)
Datum pgis_union_geometry_array(PG_FUNCTION_ARGS)
Datum hausdorffdistance(PG_FUNCTION_ARGS)
Datum isvalidreason(PG_FUNCTION_ARGS)
Datum isring(PG_FUNCTION_ARGS)
Datum linemerge(PG_FUNCTION_ARGS)
Datum pointonsurface(PG_FUNCTION_ARGS)
Datum containsproperly(PG_FUNCTION_ARGS)
char * text_to_cstring(const text *textptr)
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)
#define POSTGIS_GEOS_VERSION
const GEOSPreparedGeometry * prepared_geom
RTREE_NODE ** ringIndices
The tree structure used for fast P-i-P tests by point_in_multipolygon_rtree()