28 #include "../postgis_config.h"
33 #include "utils/array.h"
34 #include "utils/builtins.h"
35 #include "utils/lsyscache.h"
36 #include "utils/numeric.h"
37 #include "access/htup_details.h"
54 #define HANDLE_GEOS_ERROR(label) \
56 if (!strstr(lwgeom_geos_errmsg, "InterruptedException")) \
57 lwpgerror("%s: %s", (label), lwgeom_geos_errmsg); \
67 Datum
touches(PG_FUNCTION_ARGS);
69 Datum
crosses(PG_FUNCTION_ARGS);
71 Datum
within(PG_FUNCTION_ARGS);
73 Datum
covers(PG_FUNCTION_ARGS);
75 Datum
isvalid(PG_FUNCTION_ARGS);
78 Datum
buffer(PG_FUNCTION_ARGS);
87 Datum
isring(PG_FUNCTION_ARGS);
118 text *
result = cstring_to_text(ver);
119 PG_RETURN_POINTER(
result);
181 geom1 = PG_GETARG_GSERIALIZED_P(0);
182 geom2 = PG_GETARG_GSERIALIZED_P(1);
196 GEOSGeom_destroy(g1);
200 retcode = GEOSHausdorffDistance(g1, g2, &
result);
201 GEOSGeom_destroy(g1);
202 GEOSGeom_destroy(g2);
206 PG_FREE_IF_COPY(geom1, 0);
207 PG_FREE_IF_COPY(geom2, 1);
231 geom1 = PG_GETARG_GSERIALIZED_P(0);
232 geom2 = PG_GETARG_GSERIALIZED_P(1);
233 densifyFrac = PG_GETARG_FLOAT8(2);
247 GEOSGeom_destroy(g1);
251 retcode = GEOSHausdorffDistanceDensify(g1, g2, densifyFrac, &
result);
252 GEOSGeom_destroy(g1);
253 GEOSGeom_destroy(g2);
257 PG_FREE_IF_COPY(geom1, 0);
258 PG_FREE_IF_COPY(geom2, 1);
273 #if POSTGIS_GEOS_VERSION < 30700
275 lwpgerror(
"The GEOS version this PostGIS binary "
276 "was compiled against (%d) doesn't support "
277 "'GEOSFechetDistance' function (3.7.0+ required)",
290 geom1 = PG_GETARG_GSERIALIZED_P(0);
291 geom2 = PG_GETARG_GSERIALIZED_P(1);
292 densifyFrac = PG_GETARG_FLOAT8(2);
306 GEOSGeom_destroy(g1);
310 if (densifyFrac <= 0.0)
312 retcode = GEOSFrechetDistance(g1, g2, &
result);
316 retcode = GEOSFrechetDistanceDensify(g1, g2, densifyFrac, &
result);
319 GEOSGeom_destroy(g1);
320 GEOSGeom_destroy(g2);
324 PG_FREE_IF_COPY(geom1, 0);
325 PG_FREE_IF_COPY(geom2, 1);
343 #if POSTGIS_GEOS_VERSION < 30900
345 lwpgerror(
"The GEOS version this PostGIS binary "
346 "was compiled against (%d) doesn't support "
347 "'GEOSMaximumInscribedCircle' function (3.9.0+ required)",
355 TupleDesc resultTupleDesc;
356 HeapTuple resultTuple;
358 Datum result_values[3];
359 bool result_is_null[3];
367 geom = PG_GETARG_GSERIALIZED_P(0);
376 center = geometry_serialize(lwcenter);
377 nearest = geometry_serialize(lwnearest);
382 GEOSGeometry *ginput, *gcircle, *gcenter, *gnearest;
383 double width, height, size, tolerance;
390 lwpgerror(
"Geometry contains invalid coordinates");
400 size = width > height ? width : height;
401 tolerance = size / 1000.0;
412 gcircle = GEOSMaximumInscribedCircle(ginput, tolerance);
415 lwpgerror(
"Error calculating GEOSMaximumInscribedCircle.");
416 GEOSGeom_destroy(ginput);
422 gcircle = GEOSLargestEmptyCircle(ginput, NULL, tolerance);
425 lwpgerror(
"Error calculating GEOSLargestEmptyCircle.");
426 GEOSGeom_destroy(ginput);
431 gcenter = GEOSGeomGetStartPoint(gcircle);
432 gnearest = GEOSGeomGetEndPoint(gcircle);
433 GEOSDistance(gcenter, gnearest, &radius);
434 GEOSSetSRID(gcenter, srid);
435 GEOSSetSRID(gnearest, srid);
439 GEOSGeom_destroy(gcenter);
440 GEOSGeom_destroy(gnearest);
441 GEOSGeom_destroy(gcircle);
442 GEOSGeom_destroy(ginput);
445 get_call_result_type(fcinfo, NULL, &resultTupleDesc);
446 BlessTupleDesc(resultTupleDesc);
448 result_values[0] = PointerGetDatum(center);
449 result_is_null[0] =
false;
450 result_values[1] = PointerGetDatum(nearest);
451 result_is_null[1] =
false;
452 result_values[2] = Float8GetDatum(radius);
453 result_is_null[2] =
false;
454 resultTuple = heap_form_tuple(resultTupleDesc, result_values, result_is_null);
456 result = HeapTupleGetDatum(resultTuple);
476 ArrayIterator iterator;
481 int nelems = 0, geoms_size = 0, curgeom = 0,
count = 0;
485 GEOSGeometry *g = NULL;
486 GEOSGeometry *g_union = NULL;
487 GEOSGeometry **geoms = NULL;
494 if ( PG_ARGISNULL(0) )
497 array = PG_GETARG_ARRAYTYPE_P(0);
498 nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
501 if ( nelems == 0 ) PG_RETURN_NULL();
504 iterator = array_create_iterator(array, 0, NULL);
505 while (array_iterate(iterator, &
value, &isnull))
508 if (isnull)
continue;
511 array_free_iterator(iterator);
522 if (
count == 1 && nelems == 1 )
524 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
525 #pragma GCC diagnostic push
526 #pragma GCC diagnostic ignored "-Wsign-compare"
529 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
530 #pragma GCC diagnostic pop
532 srid = GEOSGetSRID(g);
533 g_union = GEOSUnaryUnion(g);
536 GEOSSetSRID(g_union, srid);
538 GEOSGeom_destroy(g_union);
539 PG_RETURN_POINTER(gser_out);
546 geoms = palloc(
sizeof(GEOSGeometry*) * geoms_size);
552 iterator = array_create_iterator(array, 0, NULL);
553 while (array_iterate(iterator, &
value, &isnull))
558 if (isnull)
continue;
576 if (gser_type > empty_type)
578 empty_type = gser_type;
579 POSTGIS_DEBUGF(4,
"empty_type = %d gser_type = %d", empty_type, gser_type);
590 "One of the geometries in the set "
591 "could not be converted to GEOS");
595 if ( curgeom == geoms_size )
598 geoms = repalloc( geoms,
sizeof(GEOSGeometry*) * geoms_size );
606 array_free_iterator(iterator);
614 g = GEOSGeom_createCollection(GEOS_GEOMETRYCOLLECTION, geoms, curgeom);
615 if (!g)
HANDLE_GEOS_ERROR(
"Could not create GEOS COLLECTION from geometry array");
617 g_union = GEOSUnaryUnion(g);
621 GEOSSetSRID(g_union, srid);
623 GEOSGeom_destroy(g_union);
629 if ( empty_type > 0 )
646 PG_RETURN_POINTER(gser_out);
661 LWGEOM *lwgeom1, *lwresult ;
664 geom1 = PG_GETARG_GSERIALIZED_P(0);
665 if (PG_NARGS() > 1 && ! PG_ARGISNULL(1))
666 prec = PG_GETARG_FLOAT8(1);
671 result = geometry_serialize(lwresult) ;
676 PG_FREE_IF_COPY(geom1, 0);
678 PG_RETURN_POINTER(
result);
687 LWGEOM *lwgeom1, *lwgeom2, *lwresult;
688 double gridSize = -1;
690 geom1 = PG_GETARG_GSERIALIZED_P(0);
691 geom2 = PG_GETARG_GSERIALIZED_P(1);
692 if (PG_NARGS() > 2 && ! PG_ARGISNULL(2))
693 gridSize = PG_GETARG_FLOAT8(2);
699 result = geometry_serialize(lwresult);
705 PG_FREE_IF_COPY(geom1, 0);
706 PG_FREE_IF_COPY(geom2, 1);
708 PG_RETURN_POINTER(
result);
716 PG_RETURN_DATUM(DirectFunctionCall2(
718 PG_GETARG_DATUM(0), PG_GETARG_DATUM(1)
733 LWGEOM *lwgeom1, *lwgeom2, *lwresult ;
736 geom1 = PG_GETARG_GSERIALIZED_P(0);
737 geom2 = PG_GETARG_GSERIALIZED_P(1);
738 if (PG_NARGS() > 2 && ! PG_ARGISNULL(2))
739 prec = PG_GETARG_FLOAT8(2);
745 result = geometry_serialize(lwresult) ;
751 PG_FREE_IF_COPY(geom1, 0);
752 PG_FREE_IF_COPY(geom2, 1);
754 PG_RETURN_POINTER(
result);
761 GEOSGeometry *g1, *g3;
767 geom1 = PG_GETARG_GSERIALIZED_P(0);
771 PG_RETURN_POINTER(geom1);
782 g3 = GEOSConvexHull(g1);
783 GEOSGeom_destroy(g1);
787 POSTGIS_DEBUGF(3,
"result: %s", GEOSGeomToWKT(g3));
789 GEOSSetSRID(g3, srid);
792 GEOSGeom_destroy(g3);
797 "convexhull() failed to convert GEOS geometry to LWGEOM");
809 result = geometry_serialize(lwout);
814 elog(ERROR,
"GEOS convexhull() threw an error (result postgis geometry formation)!");
818 PG_FREE_IF_COPY(geom1, 0);
819 PG_RETURN_POINTER(
result);
826 #if POSTGIS_GEOS_VERSION < 31100
828 lwpgerror(
"The GEOS version this PostGIS binary "
829 "was compiled against (%d) doesn't support "
830 "'GEOSConcaveHull' function (3.11.0+ required)",
836 double ratio = PG_GETARG_FLOAT8(1);
837 bool allow_holes = PG_GETARG_BOOL(2);
840 LWGEOM* lwresult = lwgeom_concavehull(lwgeom, ratio, allow_holes);
845 PG_FREE_IF_COPY(geom, 0);
846 PG_RETURN_POINTER(
result);
854 #if POSTGIS_GEOS_VERSION < 31100
856 lwpgerror(
"The GEOS version this PostGIS binary "
857 "was compiled against (%d) doesn't support "
858 "'ST_SimplifyPolygonHull' function (3.11.0+ required)",
864 double vertex_fraction = PG_GETARG_FLOAT8(1);
865 uint32_t is_outer = PG_GETARG_BOOL(2);
868 LWGEOM* lwresult = lwgeom_simplify_polygonal(lwgeom, vertex_fraction, is_outer);
873 PG_FREE_IF_COPY(geom, 0);
874 PG_RETURN_POINTER(
result);
885 GEOSGeometry *g1, *g3;
889 gs1 = PG_GETARG_GSERIALIZED_P(0);
890 tolerance = PG_GETARG_FLOAT8(1);
896 PG_RETURN_POINTER(gs1);
900 lwpgerror(
"Geometry contains invalid coordinates");
911 g3 = GEOSTopologyPreserveSimplify(g1,tolerance);
912 GEOSGeom_destroy(g1);
916 POSTGIS_DEBUGF(3,
"result: %s", GEOSGeomToWKT(g3));
921 GEOSGeom_destroy(g3);
925 elog(ERROR,
"GEOS topologypreservesimplify() threw an error (result postgis geometry formation)!");
929 PG_FREE_IF_COPY(gs1, 0);
930 PG_RETURN_POINTER(
result);
936 GEOSBufferParams *bufferparams;
937 GEOSGeometry *g1, *g3 = NULL;
954 const double DEFAULT_MITRE_LIMIT = 5.0;
955 const int DEFAULT_ENDCAP_STYLE = ENDCAP_ROUND;
956 const int DEFAULT_JOIN_STYLE = JOIN_ROUND;
957 double mitreLimit = DEFAULT_MITRE_LIMIT;
958 int endCapStyle = DEFAULT_ENDCAP_STYLE;
959 int joinStyle = DEFAULT_JOIN_STYLE;
962 double size = PG_GETARG_FLOAT8(1);
967 params_text = PG_GETARG_TEXT_P(2);
971 params_text = cstring_to_text(
"");
980 PG_RETURN_POINTER(geometry_serialize(lwg));
987 lwpgerror(
"Geometry contains invalid coordinates");
999 if (VARSIZE_ANY_EXHDR(params_text) > 0)
1002 char *params = text_to_cstring(params_text);
1004 for (param=params; ; param=NULL)
1007 param = strtok(param,
" ");
1009 POSTGIS_DEBUGF(3,
"Param: %s", param);
1012 val = strchr(key,
'=');
1013 if (!val || *(val + 1) ==
'\0')
1015 lwpgerror(
"Missing value for buffer parameter %s", key);
1021 POSTGIS_DEBUGF(3,
"Param: %s : %s", key, val);
1023 if ( !strcmp(key,
"endcap") )
1028 if ( !strcmp(val,
"round") )
1030 endCapStyle = ENDCAP_ROUND;
1032 else if ( !strcmp(val,
"flat") ||
1033 !strcmp(val,
"butt") )
1035 endCapStyle = ENDCAP_FLAT;
1037 else if ( !strcmp(val,
"square") )
1039 endCapStyle = ENDCAP_SQUARE;
1043 lwpgerror(
"Invalid buffer end cap "
1044 "style: %s (accept: "
1045 "'round', 'flat', 'butt' "
1052 else if ( !strcmp(key,
"join") )
1054 if ( !strcmp(val,
"round") )
1056 joinStyle = JOIN_ROUND;
1058 else if ( !strcmp(val,
"mitre") ||
1059 !strcmp(val,
"miter") )
1061 joinStyle = JOIN_MITRE;
1063 else if ( !strcmp(val,
"bevel") )
1065 joinStyle = JOIN_BEVEL;
1069 lwpgerror(
"Invalid buffer end cap "
1070 "style: %s (accept: "
1071 "'round', 'mitre', 'miter' "
1077 else if ( !strcmp(key,
"mitre_limit") ||
1078 !strcmp(key,
"miter_limit") )
1081 mitreLimit = atof(val);
1083 else if ( !strcmp(key,
"quad_segs") )
1086 quadsegs = atoi(val);
1088 else if ( !strcmp(key,
"side") )
1090 if ( !strcmp(val,
"both") )
1094 else if ( !strcmp(val,
"left") )
1098 else if ( !strcmp(val,
"right") )
1105 lwpgerror(
"Invalid side parameter: %s (accept: 'right', 'left', 'both')", val);
1112 "Invalid buffer parameter: %s (accept: 'endcap', 'join', 'mitre_limit', 'miter_limit', 'quad_segs' and 'side')",
1121 POSTGIS_DEBUGF(3,
"endCap:%d joinStyle:%d mitreLimit:%g",
1122 endCapStyle, joinStyle, mitreLimit);
1124 bufferparams = GEOSBufferParams_create();
1127 if (GEOSBufferParams_setEndCapStyle(bufferparams, endCapStyle) &&
1128 GEOSBufferParams_setJoinStyle(bufferparams, joinStyle) &&
1129 GEOSBufferParams_setMitreLimit(bufferparams, mitreLimit) &&
1130 GEOSBufferParams_setQuadrantSegments(bufferparams, quadsegs) &&
1131 GEOSBufferParams_setSingleSided(bufferparams, singleside))
1133 g3 = GEOSBufferWithParams(g1, bufferparams, size);
1137 lwpgerror(
"Error setting buffer parameters.");
1139 GEOSBufferParams_destroy(bufferparams);
1143 lwpgerror(
"Error setting buffer parameters.");
1146 GEOSGeom_destroy(g1);
1150 POSTGIS_DEBUGF(3,
"result: %s", GEOSGeomToWKT(g3));
1155 GEOSGeom_destroy(g3);
1159 elog(ERROR,
"GEOS buffer() threw an error (result postgis geometry formation)!");
1163 PG_FREE_IF_COPY(geom1, 0);
1164 PG_RETURN_POINTER(
result);
1183 gser_input = PG_GETARG_GSERIALIZED_P(0);
1184 npoints = PG_GETARG_INT32(1);
1189 if (PG_NARGS() > 2 && ! PG_ARGISNULL(2))
1191 seed = PG_GETARG_INT32(2);
1194 lwpgerror(
"ST_GeneratePoints: seed must be greater than zero");
1203 PG_FREE_IF_COPY(gser_input, 0);
1210 gser_result = geometry_serialize(lwgeom_result);
1212 PG_RETURN_POINTER(gser_result);
1238 static const double DEFAULT_MITRE_LIMIT = 5.0;
1239 static const int DEFAULT_JOIN_STYLE = JOIN_ROUND;
1240 double mitreLimit = DEFAULT_MITRE_LIMIT;
1241 int joinStyle = DEFAULT_JOIN_STYLE;
1243 char *paramstr = NULL;
1247 gser_input = PG_GETARG_GSERIALIZED_P(0);
1248 size = PG_GETARG_FLOAT8(1);
1251 if (size == 0) PG_RETURN_POINTER(gser_input);
1255 if ( ! lwgeom_input )
1256 lwpgerror(
"ST_OffsetCurve: lwgeom_from_gserialized returned NULL");
1260 PG_RETURN_POINTER(gser_input);
1265 text *wkttext = PG_GETARG_TEXT_P(2);
1266 paramstr = text_to_cstring(wkttext);
1268 POSTGIS_DEBUGF(3,
"paramstr: %s", paramstr);
1270 for ( param=paramstr; ; param=NULL )
1273 param = strtok(param,
" ");
1275 POSTGIS_DEBUGF(3,
"Param: %s", param);
1278 val = strchr(key,
'=');
1279 if (!val || *(val + 1) ==
'\0')
1281 lwpgerror(
"ST_OffsetCurve: Missing value for buffer parameter %s", key);
1287 POSTGIS_DEBUGF(3,
"Param: %s : %s", key, val);
1289 if ( !strcmp(key,
"join") )
1291 if ( !strcmp(val,
"round") )
1293 joinStyle = JOIN_ROUND;
1295 else if ( !(strcmp(val,
"mitre") && strcmp(val,
"miter")) )
1297 joinStyle = JOIN_MITRE;
1299 else if ( ! strcmp(val,
"bevel") )
1301 joinStyle = JOIN_BEVEL;
1306 "Invalid buffer end cap style: %s (accept: 'round', 'mitre', 'miter' or 'bevel')",
1311 else if ( !strcmp(key,
"mitre_limit") ||
1312 !strcmp(key,
"miter_limit") )
1315 mitreLimit = atof(val);
1317 else if ( !strcmp(key,
"quad_segs") )
1320 quadsegs = atoi(val);
1325 "Invalid buffer parameter: %s (accept: 'join', 'mitre_limit', 'miter_limit and 'quad_segs')",
1330 POSTGIS_DEBUGF(3,
"joinStyle:%d mitreLimit:%g", joinStyle, mitreLimit);
1334 lwgeom_result =
lwgeom_offsetcurve(lwgeom_input, size, quadsegs, joinStyle, mitreLimit);
1337 lwpgerror(
"ST_OffsetCurve: lwgeom_offsetcurve returned NULL");
1339 gser_result = geometry_serialize(lwgeom_result);
1342 PG_RETURN_POINTER(gser_result);
1351 LWGEOM *lwgeom1, *lwgeom2, *lwresult;
1354 geom1 = PG_GETARG_GSERIALIZED_P(0);
1355 geom2 = PG_GETARG_GSERIALIZED_P(1);
1356 if (PG_NARGS() > 2 && ! PG_ARGISNULL(2))
1357 prec = PG_GETARG_FLOAT8(2);
1363 result = geometry_serialize(lwresult);
1369 PG_FREE_IF_COPY(geom1, 0);
1370 PG_FREE_IF_COPY(geom2, 1);
1372 PG_RETURN_POINTER(
result);
1381 LWGEOM *lwgeom1, *lwgeom2, *lwresult;
1384 geom1 = PG_GETARG_GSERIALIZED_P(0);
1385 geom2 = PG_GETARG_GSERIALIZED_P(1);
1386 if (PG_NARGS() > 2 && ! PG_ARGISNULL(2))
1387 prec = PG_GETARG_FLOAT8(2);
1393 result = geometry_serialize(lwresult);
1399 PG_FREE_IF_COPY(geom1, 0);
1400 PG_FREE_IF_COPY(geom2, 1);
1402 PG_RETURN_POINTER(
result);
1413 LWGEOM *lwgeom, *lwresult;
1415 geom = PG_GETARG_GSERIALIZED_P(0);
1420 PG_FREE_IF_COPY(geom, 0);
1422 if (!lwresult) PG_RETURN_NULL();
1424 result = geometry_serialize(lwresult);
1426 PG_RETURN_POINTER(
result);
1433 LWGEOM *lwgeom, *lwresult;
1435 geom = PG_GETARG_GSERIALIZED_P(0);
1440 PG_FREE_IF_COPY(geom, 0);
1442 if (!lwresult) PG_RETURN_NULL();
1444 result = geometry_serialize(lwresult);
1446 PG_RETURN_POINTER(
result);
1454 LWGEOM *lwgeom, *lwresult;
1455 double gridSize = PG_GETARG_FLOAT8(1);
1456 geom = PG_GETARG_GSERIALIZED_P(0);
1461 PG_FREE_IF_COPY(geom, 0);
1463 if (!lwresult) PG_RETURN_NULL();
1465 result = geometry_serialize(lwresult);
1467 PG_RETURN_POINTER(
result);
1474 static const uint32_t geom_idx = 0;
1475 static const uint32_t box2d_idx = 1;
1477 LWGEOM *lwgeom1, *lwresult ;
1487 PG_RETURN_DATUM(PG_GETARG_DATUM(geom_idx));
1491 bbox2 = (
GBOX *)PG_GETARG_POINTER(box2d_idx);
1498 PG_RETURN_DATUM(PG_GETARG_DATUM(geom_idx));
1506 result = geometry_serialize(lwresult) ;
1508 PG_RETURN_POINTER(
result);
1520 result = geometry_serialize(lwresult) ;
1521 PG_RETURN_POINTER(
result);
1535 geom1 = PG_GETARG_GSERIALIZED_P(0);
1539 PG_RETURN_BOOL(
true);
1546 lwpgerror(
"unable to deserialize input");
1553 PG_RETURN_BOOL(
false);
1556 result = GEOSisValid(g1);
1557 GEOSGeom_destroy(g1);
1561 elog(ERROR,
"GEOS isvalid() threw an error!");
1565 PG_FREE_IF_COPY(geom1, 0);
1573 char *reason_str = NULL;
1575 const GEOSGeometry *g1 = NULL;
1577 geom = PG_GETARG_GSERIALIZED_P(0);
1584 reason_str = GEOSisValidReason(g1);
1585 GEOSGeom_destroy((GEOSGeometry *)g1);
1587 result = cstring_to_text(reason_str);
1588 GEOSFree(reason_str);
1595 PG_FREE_IF_COPY(geom, 0);
1596 PG_RETURN_POINTER(
result);
1603 const GEOSGeometry *g1 = NULL;
1605 char *geos_reason = NULL;
1606 char *reason = NULL;
1607 GEOSGeometry *geos_location = NULL;
1613 AttInMetadata *attinmeta;
1620 get_call_result_type(fcinfo, 0, &tupdesc);
1621 BlessTupleDesc(tupdesc);
1627 attinmeta = TupleDescGetAttInMetadata(tupdesc);
1629 geom = PG_GETARG_GSERIALIZED_P(0);
1630 flags = PG_GETARG_INT32(1);
1638 valid = GEOSisValidDetail(g1, flags, &geos_reason, &geos_location);
1639 GEOSGeom_destroy((GEOSGeometry *)g1);
1642 reason = pstrdup(geos_reason);
1643 GEOSFree(geos_reason);
1645 if ( geos_location )
1647 location =
GEOS2LWGEOM(geos_location, GEOSHasZ(geos_location));
1648 GEOSGeom_destroy(geos_location);
1654 lwpgerror(
"GEOS isvaliddetail() threw an exception!");
1665 values[0] = valid ?
"t" :
"f";
1673 tuple = BuildTupleFromCStrings(attinmeta, values);
1674 result = (HeapTupleHeader) palloc(tuple->t_len);
1675 memcpy(
result, tuple->t_data, tuple->t_len);
1676 heap_freetuple(tuple);
1678 PG_RETURN_HEAPTUPLEHEADER(
result);
1693 GEOSGeometry *g1, *g2;
1697 geom1 = PG_GETARG_GSERIALIZED_P(0);
1698 geom2 = PG_GETARG_GSERIALIZED_P(1);
1703 PG_RETURN_BOOL(
false);
1714 PG_RETURN_BOOL(
false);
1728 GEOSGeom_destroy(g1);
1732 result = GEOSOverlaps(g1,g2);
1734 GEOSGeom_destroy(g1);
1735 GEOSGeom_destroy(g2);
1738 PG_FREE_IF_COPY(geom1, 0);
1739 PG_FREE_IF_COPY(geom2, 1);
1748 SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
1749 SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
1750 const GSERIALIZED *geom1 = shared_gserialized_get(shared_geom1);
1751 const GSERIALIZED *geom2 = shared_gserialized_get(shared_geom2);
1753 GEOSGeometry *g1, *g2;
1760 PG_RETURN_BOOL(
false);
1762 POSTGIS_DEBUG(3,
"contains called.");
1772 PG_RETURN_BOOL(
false);
1781 SHARED_GSERIALIZED *shared_gpoly =
is_poly(geom1) ? shared_geom1 : shared_geom2;
1782 SHARED_GSERIALIZED *shared_gpoint =
is_point(geom1) ? shared_geom1 : shared_geom2;
1783 const GSERIALIZED *gpoly = shared_gserialized_get(shared_gpoly);
1784 const GSERIALIZED *gpoint = shared_gserialized_get(shared_gpoint);
1788 POSTGIS_DEBUG(3,
"Point in Polygon test requested...short-circuiting.");
1795 retval = (pip_result == 1);
1800 int found_completely_inside =
LW_FALSE;
1803 for (uint32_t i = 0; i < mpoint->
ngeoms; i++)
1814 if (pip_result == 1)
1815 found_completely_inside =
LW_TRUE;
1817 if (pip_result == -1)
1824 retval = retval && found_completely_inside;
1830 elog(ERROR,
"Type isn't point or multipoint!");
1831 PG_RETURN_BOOL(
false);
1851 POSTGIS_DEBUG(4,
"containsPrepared: cache is live, running preparedcontains");
1853 GEOSGeom_destroy(g1);
1858 if (!g1)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
1863 GEOSGeom_destroy(g1);
1865 POSTGIS_DEBUG(4,
"containsPrepared: cache is not ready, running standard contains");
1866 result = GEOSContains( g1, g2);
1867 GEOSGeom_destroy(g1);
1868 GEOSGeom_destroy(g2);
1873 PG_RETURN_BOOL(
result > 0);
1880 PG_RETURN_DATUM(CallerFInfoFunctionCall2(
contains, fcinfo->flinfo, InvalidOid,
1881 PG_GETARG_DATUM(1), PG_GETARG_DATUM(0)));
1889 SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
1890 SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
1891 const GSERIALIZED *geom1 = shared_gserialized_get(shared_geom1);
1892 const GSERIALIZED *geom2 = shared_gserialized_get(shared_geom2);
1901 PG_RETURN_BOOL(
false);
1911 PG_RETURN_BOOL(
false);
1921 if (!g)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
1923 GEOSGeom_destroy(g);
1931 if (!g1)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
1935 GEOSGeom_destroy(g1);
1938 result = GEOSRelatePattern( g1, g2,
"T**FF*FF*" );
1939 GEOSGeom_destroy(g1);
1940 GEOSGeom_destroy(g2);
1955 SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
1956 SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
1957 const GSERIALIZED *geom1 = shared_gserialized_get(shared_geom1);
1958 const GSERIALIZED *geom2 = shared_gserialized_get(shared_geom2);
1966 PG_RETURN_BOOL(
false);
1979 PG_RETURN_BOOL(
false);
1988 SHARED_GSERIALIZED *shared_gpoly =
is_poly(geom1) ? shared_geom1 : shared_geom2;
1989 SHARED_GSERIALIZED *shared_gpoint =
is_point(geom1) ? shared_geom1 : shared_geom2;
1990 const GSERIALIZED *gpoly = shared_gserialized_get(shared_gpoly);
1991 const GSERIALIZED *gpoint = shared_gserialized_get(shared_gpoint);
1995 POSTGIS_DEBUG(3,
"Point in Polygon test requested...short-circuiting.");
2002 retval = (pip_result != -1);
2010 for (i = 0; i < mpoint->
ngeoms; i++)
2026 elog(ERROR,
"Type isn't point or multipoint!");
2030 PG_RETURN_BOOL(retval);
2044 if (!g1)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
2046 GEOSGeom_destroy(g1);
2054 if (!g1)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
2058 GEOSGeom_destroy(g1);
2061 result = GEOSRelatePattern( g1, g2,
"******FF*" );
2062 GEOSGeom_destroy(g1);
2063 GEOSGeom_destroy(g2);
2086 SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
2087 SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
2088 const GSERIALIZED *geom1 = shared_gserialized_get(shared_geom1);
2089 const GSERIALIZED *geom2 = shared_gserialized_get(shared_geom2);
2090 GEOSGeometry *g1, *g2;
2093 char *patt =
"**F**F***";
2099 PG_RETURN_BOOL(
false);
2110 PG_RETURN_BOOL(
false);
2113 POSTGIS_DEBUG(3,
"bounding box short-circuit missed.");
2121 SHARED_GSERIALIZED *shared_gpoly =
is_poly(geom1) ? shared_geom1 : shared_geom2;
2122 SHARED_GSERIALIZED *shared_gpoint =
is_point(geom1) ? shared_geom1 : shared_geom2;
2123 const GSERIALIZED *gpoly = shared_gserialized_get(shared_gpoly);
2124 const GSERIALIZED *gpoint = shared_gserialized_get(shared_gpoint);
2128 POSTGIS_DEBUG(3,
"Point in Polygon test requested...short-circuiting.");
2135 retval = (pip_result != -1);
2143 for (i = 0; i < mpoint->
ngeoms; i++)
2159 elog(ERROR,
"Type isn't point or multipoint!");
2163 PG_RETURN_BOOL(retval);
2181 GEOSGeom_destroy(g1);
2185 result = GEOSRelatePattern(g1,g2,patt);
2187 GEOSGeom_destroy(g1);
2188 GEOSGeom_destroy(g2);
2200 GEOSGeometry *g1, *g2;
2204 geom1 = PG_GETARG_GSERIALIZED_P(0);
2205 geom2 = PG_GETARG_GSERIALIZED_P(1);
2210 PG_RETURN_BOOL(
false);
2221 PG_RETURN_BOOL(
false);
2234 GEOSGeom_destroy(g1);
2238 result = GEOSCrosses(g1,g2);
2240 GEOSGeom_destroy(g1);
2241 GEOSGeom_destroy(g2);
2245 PG_FREE_IF_COPY(geom1, 0);
2246 PG_FREE_IF_COPY(geom2, 1);
2254 SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
2255 SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
2256 const GSERIALIZED *geom1 = shared_gserialized_get(shared_geom1);
2257 const GSERIALIZED *geom2 = shared_gserialized_get(shared_geom2);
2266 PG_RETURN_BOOL(
false);
2276 PG_RETURN_BOOL(
false);
2285 SHARED_GSERIALIZED *shared_gpoly =
is_poly(geom1) ? shared_geom1 : shared_geom2;
2286 SHARED_GSERIALIZED *shared_gpoint =
is_point(geom1) ? shared_geom1 : shared_geom2;
2287 const GSERIALIZED *gpoly = shared_gserialized_get(shared_gpoly);
2288 const GSERIALIZED *gpoint = shared_gserialized_get(shared_gpoint);
2292 POSTGIS_DEBUG(3,
"Point in Polygon test requested...short-circuiting.");
2299 retval = (pip_result != -1);
2305 for (uint32_t i = 0; i < mpoint->
ngeoms; i++)
2321 elog(ERROR,
"Type isn't point or multipoint!");
2325 PG_RETURN_BOOL(retval);
2333 if ( prep_cache->
gcache.argnum == 1 )
2338 GEOSGeom_destroy(g);
2346 GEOSGeom_destroy(g);
2354 if (!g1)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
2358 GEOSGeom_destroy(g1);
2361 result = GEOSIntersects( g1, g2);
2362 GEOSGeom_destroy(g1);
2363 GEOSGeom_destroy(g2);
2377 GEOSGeometry *g1, *g2;
2381 geom1 = PG_GETARG_GSERIALIZED_P(0);
2382 geom2 = PG_GETARG_GSERIALIZED_P(1);
2387 PG_RETURN_BOOL(
false);
2398 PG_RETURN_BOOL(
false);
2411 GEOSGeom_destroy(g1);
2415 result = GEOSTouches(g1,g2);
2417 GEOSGeom_destroy(g1);
2418 GEOSGeom_destroy(g2);
2422 PG_FREE_IF_COPY(geom1, 0);
2423 PG_FREE_IF_COPY(geom2, 1);
2434 GEOSGeometry *g1, *g2;
2438 geom1 = PG_GETARG_GSERIALIZED_P(0);
2439 geom2 = PG_GETARG_GSERIALIZED_P(1);
2444 PG_RETURN_BOOL(
true);
2455 PG_RETURN_BOOL(
true);
2468 GEOSGeom_destroy(g1);
2472 result = GEOSDisjoint(g1,g2);
2474 GEOSGeom_destroy(g1);
2475 GEOSGeom_destroy(g2);
2479 PG_FREE_IF_COPY(geom1, 0);
2480 PG_FREE_IF_COPY(geom2, 1);
2494 GEOSGeometry *g1, *g2;
2497 geom1 = PG_GETARG_GSERIALIZED_P(0);
2498 geom2 = PG_GETARG_GSERIALIZED_P(1);
2511 GEOSGeom_destroy(g1);
2516 ptxt = DatumGetTextP(DirectFunctionCall2(text_left,
2517 PG_GETARG_DATUM(2), Int32GetDatum(9)));
2518 patt = text_to_cstring(ptxt);
2523 for ( i = 0; i < strlen(patt); i++ )
2525 if ( patt[i] ==
't' ) patt[i] =
'T';
2526 if ( patt[i] ==
'f' ) patt[i] =
'F';
2529 result = GEOSRelatePattern(g1,g2,patt);
2530 GEOSGeom_destroy(g1);
2531 GEOSGeom_destroy(g2);
2536 PG_FREE_IF_COPY(geom1, 0);
2537 PG_FREE_IF_COPY(geom2, 1);
2549 GEOSGeometry *g1, *g2;
2552 int bnr = GEOSRELATE_BNR_OGC;
2555 geom1 = PG_GETARG_GSERIALIZED_P(0);
2556 geom2 = PG_GETARG_GSERIALIZED_P(1);
2559 if ( PG_NARGS() > 2 )
2560 bnr = PG_GETARG_INT32(2);
2570 GEOSGeom_destroy(g1);
2574 POSTGIS_DEBUG(3,
"constructed geometries ");
2576 POSTGIS_DEBUGF(3,
"%s", GEOSGeomToWKT(g1));
2577 POSTGIS_DEBUGF(3,
"%s", GEOSGeomToWKT(g2));
2579 relate_str = GEOSRelateBoundaryNodeRule(g1, g2, bnr);
2581 GEOSGeom_destroy(g1);
2582 GEOSGeom_destroy(g2);
2586 result = cstring_to_text(relate_str);
2587 GEOSFree(relate_str);
2589 PG_FREE_IF_COPY(geom1, 0);
2590 PG_FREE_IF_COPY(geom2, 1);
2592 PG_RETURN_TEXT_P(
result);
2601 GEOSGeometry *g1, *g2;
2605 geom1 = PG_GETARG_GSERIALIZED_P(0);
2606 geom2 = PG_GETARG_GSERIALIZED_P(1);
2611 PG_RETURN_BOOL(
true);
2622 PG_RETURN_BOOL(
false);
2630 if (VARSIZE(geom1) == VARSIZE(geom2) && !memcmp(geom1, geom2, VARSIZE(geom1))) {
2631 PG_RETURN_BOOL(
true);
2645 GEOSGeom_destroy(g1);
2649 result = GEOSEquals(g1,g2);
2651 GEOSGeom_destroy(g1);
2652 GEOSGeom_destroy(g2);
2656 PG_FREE_IF_COPY(geom1, 0);
2657 PG_FREE_IF_COPY(geom2, 1);
2669 POSTGIS_DEBUG(2,
"issimple called");
2671 geom = PG_GETARG_GSERIALIZED_P(0);
2674 PG_RETURN_BOOL(
true);
2679 PG_FREE_IF_COPY(geom, 0);
2695 geom = PG_GETARG_GSERIALIZED_P(0);
2699 PG_RETURN_BOOL(
false);
2707 if ( GEOSGeomTypeId(g1) != GEOS_LINESTRING )
2709 GEOSGeom_destroy(g1);
2710 elog(ERROR,
"ST_IsRing() should only be called on a linear feature");
2714 GEOSGeom_destroy(g1);
2718 PG_FREE_IF_COPY(geom, 0);
2731 lwpgerror(
"%s: GEOS2LWGEOM returned NULL", __func__);
2735 POSTGIS_DEBUGF(4,
"%s: GEOS2LWGEOM returned a %s", __func__,
lwgeom_summary(lwgeom, 0));
2739 result = geometry_serialize(lwgeom);
2754 lwpgerror(
"POSTGIS2GEOS: unable to deserialize input");
2764 ArrayIterator iterator;
2767 uint32_t nelems_not_null = 0;
2768 iterator = array_create_iterator(array, 0, NULL);
2769 while(array_iterate(iterator, &
value, &isnull) )
2773 array_free_iterator(iterator);
2775 return nelems_not_null;
2781 ArrayIterator iterator;
2784 bool gotsrid =
false;
2789 iterator = array_create_iterator(array, 0, NULL);
2791 while (array_iterate(iterator, &
value, &isnull))
2803 lwpgerror(
"Geometry deserializing geometry");
2821 GEOSGeometry**
ARRAY2GEOS(ArrayType* array, uint32_t nelems,
int* is3d,
int* srid)
2823 ArrayIterator iterator;
2826 bool gotsrid =
false;
2829 GEOSGeometry** geos_geoms = palloc(nelems *
sizeof(GEOSGeometry*));
2831 iterator = array_create_iterator(array, 0, NULL);
2833 while(array_iterate(iterator, &
value, &isnull))
2846 lwpgerror(
"Geometry could not be converted to GEOS");
2848 for (j = 0; j < i; j++) {
2849 GEOSGeom_destroy(geos_geoms[j]);
2862 for (j = 0; j <= i; j++) {
2863 GEOSGeom_destroy(geos_geoms[j]);
2872 array_free_iterator(iterator);
2880 GEOSGeometry *geosgeom;
2885 geom = PG_GETARG_GSERIALIZED_P(0);
2887 if ( ! geosgeom ) PG_RETURN_NULL();
2890 GEOSGeom_destroy(geosgeom);
2892 PG_FREE_IF_COPY(geom, 0);
2894 PG_RETURN_POINTER(lwgeom_result);
2904 GEOSGeometry *geos_result;
2905 const GEOSGeometry **vgeoms;
2907 #if POSTGIS_DEBUG_LEVEL >= 3
2911 #if POSTGIS_DEBUG_LEVEL >= 3
2915 if (PG_ARGISNULL(0))
2918 array = PG_GETARG_ARRAYTYPE_P(0);
2924 POSTGIS_DEBUGF(3,
"polygonize_garray: number of non-null elements: %d", nelems);
2929 vgeoms = (
const GEOSGeometry**)
ARRAY2GEOS(array, nelems, &is3d, &srid);
2931 POSTGIS_DEBUG(3,
"polygonize_garray: invoking GEOSpolygonize");
2933 geos_result = GEOSPolygonize(vgeoms, nelems);
2935 POSTGIS_DEBUG(3,
"polygonize_garray: GEOSpolygonize returned");
2937 for (i=0; i<nelems; ++i) GEOSGeom_destroy((GEOSGeometry *)vgeoms[i]);
2940 if ( ! geos_result ) PG_RETURN_NULL();
2942 GEOSSetSRID(geos_result, srid);
2944 GEOSGeom_destroy(geos_result);
2947 elog(ERROR,
"%s returned an error", __func__);
2951 PG_RETURN_POINTER(
result);
2958 Datum* result_array_data;
2959 ArrayType *array, *
result;
2961 uint32 nelems, nclusters, i;
2962 GEOSGeometry **geos_inputs, **geos_results;
2971 if (PG_ARGISNULL(0))
2974 array = PG_GETARG_ARRAYTYPE_P(0);
2977 POSTGIS_DEBUGF(3,
"clusterintersecting_garray: number of non-null elements: %d", nelems);
2979 if ( nelems == 0 ) PG_RETURN_NULL();
2986 geos_inputs =
ARRAY2GEOS(array, nelems, &is3d, &srid);
2994 elog(ERROR,
"clusterintersecting: Error performing clustering");
2999 if (!geos_results) PG_RETURN_NULL();
3001 result_array_data = palloc(nclusters *
sizeof(Datum));
3002 for (i=0; i<nclusters; ++i)
3004 result_array_data[i] = PointerGetDatum(
GEOS2POSTGIS(geos_results[i], is3d));
3005 GEOSGeom_destroy(geos_results[i]);
3009 get_typlenbyvalalign(array->elemtype, &elmlen, &elmbyval, &elmalign);
3010 result = construct_array(result_array_data, nclusters, array->elemtype, elmlen, elmbyval, elmalign);
3014 elog(ERROR,
"clusterintersecting: Error constructing return-array");
3018 PG_RETURN_POINTER(
result);
3024 Datum* result_array_data;
3025 ArrayType *array, *
result;
3027 uint32 nelems, nclusters, i;
3039 if (PG_ARGISNULL(0))
3042 array = PG_GETARG_ARRAYTYPE_P(0);
3044 tolerance = PG_GETARG_FLOAT8(1);
3047 lwpgerror(
"Tolerance must be a positive number.");
3053 POSTGIS_DEBUGF(3,
"cluster_within_distance_garray: number of non-null elements: %d", nelems);
3055 if ( nelems == 0 ) PG_RETURN_NULL();
3070 elog(ERROR,
"cluster_within: Error performing clustering");
3075 if (!lw_results) PG_RETURN_NULL();
3077 result_array_data = palloc(nclusters *
sizeof(Datum));
3078 for (i=0; i<nclusters; ++i)
3080 result_array_data[i] = PointerGetDatum(geometry_serialize(lw_results[i]));
3085 get_typlenbyvalalign(array->elemtype, &elmlen, &elmbyval, &elmalign);
3086 result = construct_array(result_array_data, nclusters, array->elemtype, elmlen, elmbyval, elmalign);
3090 elog(ERROR,
"clusterwithin: Error constructing return-array");
3094 PG_RETURN_POINTER(
result);
3101 bool directed =
false;
3103 LWGEOM *lwgeom1, *lwresult ;
3105 geom1 = PG_GETARG_GSERIALIZED_P(0);
3107 if ( PG_NARGS() > 1 )
3108 directed = PG_GETARG_BOOL(1);
3113 result = geometry_serialize(lwresult) ;
3118 PG_FREE_IF_COPY(geom1, 0);
3120 PG_RETURN_POINTER(
result);
3135 LWGEOM *lwgeom_in, *lwgeom_out;
3137 geom = PG_GETARG_GSERIALIZED_P(0);
3145 PG_FREE_IF_COPY(geom, 0);
3149 result = geometry_serialize(lwgeom_out) ;
3152 PG_FREE_IF_COPY(geom, 0);
3153 PG_RETURN_POINTER(
result);
3165 LWGEOM *lwgeom_in, *lwgeom_out;
3166 double tolerance = 0.0;
3169 geom = PG_GETARG_GSERIALIZED_P(0);
3170 tolerance = PG_GETARG_FLOAT8(1);
3171 flags = PG_GETARG_INT32(2);
3179 PG_FREE_IF_COPY(geom, 0);
3183 result = geometry_serialize(lwgeom_out) ;
3186 PG_FREE_IF_COPY(geom, 0);
3187 PG_RETURN_POINTER(
result);
3198 #if POSTGIS_GEOS_VERSION < 31100
3200 lwpgerror(
"The GEOS version this PostGIS binary "
3201 "was compiled against (%d) doesn't support "
3202 "'GEOSConstrainedDelaunayTriangulation' function (3.11.0+ required)",
3210 LWGEOM *lwgeom_out = lwgeom_triangulate_polygon(lwgeom_in);
3215 PG_FREE_IF_COPY(geom, 0);
3219 result = geometry_serialize(lwgeom_out);
3222 PG_FREE_IF_COPY(geom, 0);
3223 PG_RETURN_POINTER(
result);
3232 Datum
ST_Snap(PG_FUNCTION_ARGS);
3237 LWGEOM *lwgeom1, *lwgeom2, *lwresult;
3240 geom1 = PG_GETARG_GSERIALIZED_P(0);
3241 geom2 = PG_GETARG_GSERIALIZED_P(1);
3242 tolerance = PG_GETARG_FLOAT8(2);
3247 lwresult =
lwgeom_snap(lwgeom1, lwgeom2, tolerance);
3250 PG_FREE_IF_COPY(geom1, 0);
3251 PG_FREE_IF_COPY(geom2, 1);
3253 result = geometry_serialize(lwresult);
3256 PG_RETURN_POINTER(
result);
3288 LWGEOM *lwgeom_in, *lwblade_in, *lwgeom_out;
3290 in = PG_GETARG_GSERIALIZED_P(0);
3291 blade_in = PG_GETARG_GSERIALIZED_P(1);
3299 lwpgerror(
"Input Geometry contains invalid coordinates");
3305 lwpgerror(
"Blade Geometry contains invalid coordinates");
3316 PG_FREE_IF_COPY(in, 0);
3317 PG_FREE_IF_COPY(blade_in, 1);
3321 out = geometry_serialize(lwgeom_out);
3323 PG_FREE_IF_COPY(in, 0);
3324 PG_FREE_IF_COPY(blade_in, 1);
3326 PG_RETURN_POINTER(out);
3349 LWGEOM *g1, *g2, *lwgeom_out;
3351 geom1 = PG_GETARG_GSERIALIZED_P(0);
3352 geom2 = PG_GETARG_GSERIALIZED_P(1);
3363 PG_FREE_IF_COPY(geom1, 0);
3364 PG_FREE_IF_COPY(geom2, 1);
3368 out = geometry_serialize(lwgeom_out);
3371 PG_FREE_IF_COPY(geom1, 0);
3372 PG_FREE_IF_COPY(geom2, 1);
3373 PG_RETURN_POINTER(out);
3385 Datum
ST_Node(PG_FUNCTION_ARGS);
3392 geom1 = PG_GETARG_GSERIALIZED_P(0);
3401 PG_FREE_IF_COPY(geom1, 0);
3405 out = geometry_serialize(lwgeom_out);
3408 PG_FREE_IF_COPY(geom1, 0);
3409 PG_RETURN_POINTER(out);
3431 int custom_clip_envelope;
3432 int return_polygons;
3435 if (PG_ARGISNULL(0))
3439 if (PG_ARGISNULL(2))
3441 lwpgerror(
"Tolerance must be a positive number.");
3445 tolerance = PG_GETARG_FLOAT8(2);
3449 lwpgerror(
"Tolerance must be a positive number.");
3454 if (PG_ARGISNULL(3))
3456 lwpgerror(
"return_polygons must be true or false.");
3459 return_polygons = PG_GETARG_BOOL(3);
3462 custom_clip_envelope = !PG_ARGISNULL(1);
3463 if (custom_clip_envelope) {
3464 clip = PG_GETARG_GSERIALIZED_P(1);
3467 lwpgerror(
"Could not determine envelope of clipping geometry.");
3468 PG_FREE_IF_COPY(clip, 1);
3471 PG_FREE_IF_COPY(clip, 1);
3475 input = PG_GETARG_GSERIALIZED_P(0);
3481 lwpgerror(
"Could not read input geometry.");
3482 PG_FREE_IF_COPY(input, 0);
3486 lwgeom_result =
lwgeom_voronoi_diagram(lwgeom_input, custom_clip_envelope ? &clip_envelope : NULL, tolerance, !return_polygons);
3491 lwpgerror(
"Error computing Voronoi diagram.");
3492 PG_FREE_IF_COPY(input, 0);
3496 result = geometry_serialize(lwgeom_result);
3499 PG_FREE_IF_COPY(input, 0);
3500 PG_RETURN_POINTER(
result);
3515 GEOSGeometry* input_geos;
3521 input = PG_GETARG_GSERIALIZED_P(0);
3526 error = GEOSMinimumClearance(input_geos, &
result);
3527 GEOSGeom_destroy(input_geos);
3530 PG_FREE_IF_COPY(input, 0);
3531 PG_RETURN_FLOAT8(
result);
3547 GEOSGeometry* input_geos;
3548 GEOSGeometry* result_geos;
3553 input = PG_GETARG_GSERIALIZED_P(0);
3559 result_geos = GEOSMinimumClearanceLine(input_geos);
3560 GEOSGeom_destroy(input_geos);
3564 GEOSSetSRID(result_geos, srid);
3566 GEOSGeom_destroy(result_geos);
3568 PG_FREE_IF_COPY(input, 0);
3569 PG_RETURN_POINTER(
result);
3583 GEOSGeometry* input_geos;
3584 GEOSGeometry* result_geos;
3589 input = PG_GETARG_GSERIALIZED_P(0);
3595 result_geos = GEOSMinimumRotatedRectangle(input_geos);
3596 GEOSGeom_destroy(input_geos);
3600 GEOSSetSRID(result_geos, srid);
3602 GEOSGeom_destroy(result_geos);
3604 PG_FREE_IF_COPY(input, 0);
3605 PG_RETURN_POINTER(
result);
char result[OUT_DOUBLE_BUFFER_SIZE]
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,...
int gserialized_datum_get_internals_p(Datum gsdatum, GBOX *gbox, lwflags_t *flags, uint8_t *type, int32_t *srid)
Peak into a GSERIALIZED datum to find its bounding box and some other metadata.
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...
LWPOINT * lwpoint_construct_empty(int32_t srid, char hasz, char hasm)
LWGEOM * lwgeom_centroid(const LWGEOM *geom)
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)
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_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.
char * lwgeom_to_hexwkb_buffer(const LWGEOM *geom, uint8_t variant)
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.
#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_difference_prec(const LWGEOM *geom1, const LWGEOM *geom2, double gridSize)
LWGEOM * lwgeom_union_prec(const LWGEOM *geom1, const LWGEOM *geom2, double gridSize)
LWGEOM * lwgeom_unaryunion_prec(const LWGEOM *geom1, double gridSize)
LWGEOM * lwgeom_buildarea(const LWGEOM *geom)
Take a geometry and return an areal geometry (Polygon or MultiPolygon).
LWGEOM * lwgeom_symdifference_prec(const LWGEOM *geom1, const LWGEOM *geom2, double gridSize)
LWGEOM * lwgeom_intersection_prec(const LWGEOM *geom1, const LWGEOM *geom2, double gridSize)
LWGEOM * lwgeom_linemerge_directed(const LWGEOM *geom1, int directed)
LWGEOM * lwgeom_clip_by_rect(const LWGEOM *geom1, double x0, double y0, double x1, double y1)
LWGEOM * lwgeom_reduceprecision(const LWGEOM *geom, double gridSize)
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.
This library is the generic geometry handling section of PostGIS.
int lwpoint_is_empty(const LWPOINT *point)
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, SHARED_GSERIALIZED *g1, SHARED_GSERIALIZED *g2)
Given a couple potential geometries and a function call context, return a prepared structure for one ...
RTREE_POLY_CACHE * GetRtreeCache(FunctionCallInfo fcinfo, SHARED_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 ST_ReducePrecision(PG_FUNCTION_ARGS)
Datum polygonize_garray(PG_FUNCTION_ARGS)
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_SimplifyPolygonHull(PG_FUNCTION_ARGS)
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)
static int pip_short_circuit(RTREE_POLY_CACHE *poly_cache, LWPOINT *point, const GSERIALIZED *gpoly)
Datum ST_ClipByBox2d(PG_FUNCTION_ARGS)
Datum crosses(PG_FUNCTION_ARGS)
Datum ST_SymDifference(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)
Datum ST_MaximumInscribedCircle(PG_FUNCTION_ARGS)
GSERIALIZED * GEOS2POSTGIS(GEOSGeom geom, char want3d)
Datum ST_DelaunayTriangles(PG_FUNCTION_ARGS)
Datum ST_ConcaveHull(PG_FUNCTION_ARGS)
static char is_poly(const GSERIALIZED *g)
Datum boundary(PG_FUNCTION_ARGS)
Datum postgis_geos_version(PG_FUNCTION_ARGS)
GEOSGeometry * POSTGIS2GEOS(const GSERIALIZED *pglwgeom)
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)
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 ST_TriangulatePolygon(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)
#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()