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"
53 #define HANDLE_GEOS_ERROR(label) \
55 if (strstr(lwgeom_geos_errmsg, "InterruptedException")) \
57 (errcode(ERRCODE_QUERY_CANCELED), errmsg("canceling statement due to user request"))); \
59 lwpgerror("%s: %s", (label), lwgeom_geos_errmsg); \
69 Datum
touches(PG_FUNCTION_ARGS);
71 Datum
crosses(PG_FUNCTION_ARGS);
73 Datum
within(PG_FUNCTION_ARGS);
75 Datum
covers(PG_FUNCTION_ARGS);
77 Datum
isvalid(PG_FUNCTION_ARGS);
80 Datum
buffer(PG_FUNCTION_ARGS);
89 Datum
isring(PG_FUNCTION_ARGS);
120 text *
result = cstring_to_text(ver);
121 PG_RETURN_POINTER(
result);
183 geom1 = PG_GETARG_GSERIALIZED_P(0);
184 geom2 = PG_GETARG_GSERIALIZED_P(1);
198 GEOSGeom_destroy(g1);
202 retcode = GEOSHausdorffDistance(g1, g2, &
result);
203 GEOSGeom_destroy(g1);
204 GEOSGeom_destroy(g2);
208 PG_FREE_IF_COPY(geom1, 0);
209 PG_FREE_IF_COPY(geom2, 1);
233 geom1 = PG_GETARG_GSERIALIZED_P(0);
234 geom2 = PG_GETARG_GSERIALIZED_P(1);
235 densifyFrac = PG_GETARG_FLOAT8(2);
249 GEOSGeom_destroy(g1);
253 retcode = GEOSHausdorffDistanceDensify(g1, g2, densifyFrac, &
result);
254 GEOSGeom_destroy(g1);
255 GEOSGeom_destroy(g2);
259 PG_FREE_IF_COPY(geom1, 0);
260 PG_FREE_IF_COPY(geom2, 1);
275 #if POSTGIS_GEOS_VERSION < 37
277 lwpgerror(
"The GEOS version this PostGIS binary "
278 "was compiled against (%d) doesn't support "
279 "'GEOSFechetDistance' function (3.7.0+ required)",
292 geom1 = PG_GETARG_GSERIALIZED_P(0);
293 geom2 = PG_GETARG_GSERIALIZED_P(1);
294 densifyFrac = PG_GETARG_FLOAT8(2);
308 GEOSGeom_destroy(g1);
312 if (densifyFrac <= 0.0)
314 retcode = GEOSFrechetDistance(g1, g2, &
result);
318 retcode = GEOSFrechetDistanceDensify(g1, g2, densifyFrac, &
result);
321 GEOSGeom_destroy(g1);
322 GEOSGeom_destroy(g2);
326 PG_FREE_IF_COPY(geom1, 0);
327 PG_FREE_IF_COPY(geom2, 1);
345 #if POSTGIS_GEOS_VERSION < 39
347 lwpgerror(
"The GEOS version this PostGIS binary "
348 "was compiled against (%d) doesn't support "
349 "'GEOSMaximumInscribedCircle' function (3.9.0+ required)",
357 TupleDesc resultTupleDesc;
358 HeapTuple resultTuple;
360 Datum result_values[3];
361 bool result_is_null[3];
369 geom = PG_GETARG_GSERIALIZED_P(0);
378 center = geometry_serialize(lwcenter);
379 nearest = geometry_serialize(lwnearest);
384 GEOSGeometry *ginput, *gcircle, *gcenter, *gnearest;
385 double width, height, size, tolerance;
392 lwpgerror(
"Geometry contains invalid coordinates");
402 size = width > height ? width : height;
403 tolerance = size / 1000.0;
414 gcircle = GEOSMaximumInscribedCircle(ginput, tolerance);
417 lwpgerror(
"Error calculating GEOSMaximumInscribedCircle.");
418 GEOSGeom_destroy(ginput);
424 gcircle = GEOSLargestEmptyCircle(ginput, NULL, tolerance);
427 lwpgerror(
"Error calculating GEOSLargestEmptyCircle.");
428 GEOSGeom_destroy(ginput);
433 gcenter = GEOSGeomGetStartPoint(gcircle);
434 gnearest = GEOSGeomGetEndPoint(gcircle);
435 GEOSDistance(gcenter, gnearest, &radius);
436 GEOSSetSRID(gcenter, srid);
437 GEOSSetSRID(gnearest, srid);
441 GEOSGeom_destroy(gcenter);
442 GEOSGeom_destroy(gnearest);
443 GEOSGeom_destroy(gcircle);
444 GEOSGeom_destroy(ginput);
447 get_call_result_type(fcinfo, NULL, &resultTupleDesc);
448 BlessTupleDesc(resultTupleDesc);
450 result_values[0] = PointerGetDatum(center);
451 result_is_null[0] =
false;
452 result_values[1] = PointerGetDatum(nearest);
453 result_is_null[1] =
false;
454 result_values[2] = Float8GetDatum(radius);
455 result_is_null[2] =
false;
456 resultTuple = heap_form_tuple(resultTupleDesc, result_values, result_is_null);
458 result = HeapTupleGetDatum(resultTuple);
478 ArrayIterator iterator;
483 int nelems = 0, geoms_size = 0, curgeom = 0,
count = 0;
487 GEOSGeometry *g = NULL;
488 GEOSGeometry *g_union = NULL;
489 GEOSGeometry **geoms = NULL;
496 if ( PG_ARGISNULL(0) )
499 array = PG_GETARG_ARRAYTYPE_P(0);
500 nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
503 if ( nelems == 0 ) PG_RETURN_NULL();
506 iterator = array_create_iterator(array, 0, NULL);
507 while (array_iterate(iterator, &
value, &isnull))
510 if (isnull)
continue;
513 array_free_iterator(iterator);
521 if (
count == 1 && nelems == 1 )
523 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
524 #pragma GCC diagnostic push
525 #pragma GCC diagnostic ignored "-Wsign-compare"
527 PG_RETURN_POINTER((
GSERIALIZED *)(ARR_DATA_PTR(array)));
528 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
529 #pragma GCC diagnostic pop
540 geoms = palloc(
sizeof(GEOSGeometry*) * geoms_size);
546 iterator = array_create_iterator(array, 0, NULL);
547 while (array_iterate(iterator, &
value, &isnull))
552 if (isnull)
continue;
570 if (gser_type > empty_type)
572 empty_type = gser_type;
573 POSTGIS_DEBUGF(4,
"empty_type = %d gser_type = %d", empty_type, gser_type);
584 "One of the geometries in the set "
585 "could not be converted to GEOS");
589 if ( curgeom == geoms_size )
592 geoms = repalloc( geoms,
sizeof(GEOSGeometry*) * geoms_size );
600 array_free_iterator(iterator);
608 g = GEOSGeom_createCollection(GEOS_GEOMETRYCOLLECTION, geoms, curgeom);
609 if (!g)
HANDLE_GEOS_ERROR(
"Could not create GEOS COLLECTION from geometry array");
611 g_union = GEOSUnaryUnion(g);
615 GEOSSetSRID(g_union, srid);
617 GEOSGeom_destroy(g_union);
623 if ( empty_type > 0 )
640 PG_RETURN_POINTER(gser_out);
661 geoms = palloc(list_length(state->
geoms) *
sizeof(
LWGEOM*));
664 foreach (l, state->
geoms)
671 geoms[ngeoms++] = geom;
682 empty_type =
type > empty_type ?
type : empty_type;
700 gser_out = geometry_serialize(out);
721 PG_RETURN_POINTER(gser_out);
737 LWGEOM *lwgeom1, *lwresult ;
740 geom1 = PG_GETARG_GSERIALIZED_P(0);
741 if (PG_NARGS() > 1 && ! PG_ARGISNULL(1))
742 prec = PG_GETARG_FLOAT8(1);
747 result = geometry_serialize(lwresult) ;
752 PG_FREE_IF_COPY(geom1, 0);
754 PG_RETURN_POINTER(
result);
763 LWGEOM *lwgeom1, *lwgeom2, *lwresult;
764 double gridSize = -1;
766 geom1 = PG_GETARG_GSERIALIZED_P(0);
767 geom2 = PG_GETARG_GSERIALIZED_P(1);
768 if (PG_NARGS() > 2 && ! PG_ARGISNULL(2))
769 gridSize = PG_GETARG_FLOAT8(2);
775 result = geometry_serialize(lwresult);
781 PG_FREE_IF_COPY(geom1, 0);
782 PG_FREE_IF_COPY(geom2, 1);
784 PG_RETURN_POINTER(
result);
792 PG_RETURN_DATUM(DirectFunctionCall2(
794 PG_GETARG_DATUM(0), PG_GETARG_DATUM(1)
809 LWGEOM *lwgeom1, *lwgeom2, *lwresult ;
812 geom1 = PG_GETARG_GSERIALIZED_P(0);
813 geom2 = PG_GETARG_GSERIALIZED_P(1);
814 if (PG_NARGS() > 2 && ! PG_ARGISNULL(2))
815 prec = PG_GETARG_FLOAT8(2);
821 result = geometry_serialize(lwresult) ;
827 PG_FREE_IF_COPY(geom1, 0);
828 PG_FREE_IF_COPY(geom2, 1);
830 PG_RETURN_POINTER(
result);
838 GEOSGeometry *g1, *g3;
843 geom1 = PG_GETARG_GSERIALIZED_P(0);
847 PG_RETURN_POINTER(geom1);
853 lwpgerror(
"POSTGIS2GEOS: unable to deserialize input");
861 result = geometry_serialize(lwgeom);
863 PG_RETURN_POINTER(
result);
874 g3 = GEOSBoundary(g1);
878 GEOSGeom_destroy(g1);
882 POSTGIS_DEBUGF(3,
"result: %s", GEOSGeomToWKT(g3));
884 GEOSSetSRID(g3, srid);
890 GEOSGeom_destroy(g1);
891 GEOSGeom_destroy(g3);
893 "GEOS2POSTGIS threw an error (result postgis geometry "
898 GEOSGeom_destroy(g1);
899 GEOSGeom_destroy(g3);
901 PG_FREE_IF_COPY(geom1, 0);
903 PG_RETURN_POINTER(
result);
910 GEOSGeometry *g1, *g3;
916 geom1 = PG_GETARG_GSERIALIZED_P(0);
920 PG_RETURN_POINTER(geom1);
931 g3 = GEOSConvexHull(g1);
932 GEOSGeom_destroy(g1);
936 POSTGIS_DEBUGF(3,
"result: %s", GEOSGeomToWKT(g3));
938 GEOSSetSRID(g3, srid);
941 GEOSGeom_destroy(g3);
946 "convexhull() failed to convert GEOS geometry to LWGEOM");
958 result = geometry_serialize(lwout);
963 elog(ERROR,
"GEOS convexhull() threw an error (result postgis geometry formation)!");
967 PG_FREE_IF_COPY(geom1, 0);
968 PG_RETURN_POINTER(
result);
977 GEOSGeometry *g1, *g3;
981 gs1 = PG_GETARG_GSERIALIZED_P(0);
982 tolerance = PG_GETARG_FLOAT8(1);
988 PG_RETURN_POINTER(gs1);
992 lwpgerror(
"Geometry contains invalid coordinates");
1003 g3 = GEOSTopologyPreserveSimplify(g1,tolerance);
1004 GEOSGeom_destroy(g1);
1008 POSTGIS_DEBUGF(3,
"result: %s", GEOSGeomToWKT(g3));
1013 GEOSGeom_destroy(g3);
1017 elog(ERROR,
"GEOS topologypreservesimplify() threw an error (result postgis geometry formation)!");
1021 PG_FREE_IF_COPY(gs1, 0);
1022 PG_RETURN_POINTER(
result);
1028 GEOSBufferParams *bufferparams;
1029 GEOSGeometry *g1, *g3 = NULL;
1046 const double DEFAULT_MITRE_LIMIT = 5.0;
1047 const int DEFAULT_ENDCAP_STYLE = ENDCAP_ROUND;
1048 const int DEFAULT_JOIN_STYLE = JOIN_ROUND;
1049 double mitreLimit = DEFAULT_MITRE_LIMIT;
1050 int endCapStyle = DEFAULT_ENDCAP_STYLE;
1051 int joinStyle = DEFAULT_JOIN_STYLE;
1054 double size = PG_GETARG_FLOAT8(1);
1059 params_text = PG_GETARG_TEXT_P(2);
1063 params_text = cstring_to_text(
"");
1072 PG_RETURN_POINTER(geometry_serialize(lwg));
1079 lwpgerror(
"Geometry contains invalid coordinates");
1091 if (VARSIZE_ANY_EXHDR(params_text) > 0)
1094 char *params = text_to_cstring(params_text);
1096 for (param=params; ; param=NULL)
1099 param = strtok(param,
" ");
1101 POSTGIS_DEBUGF(3,
"Param: %s", param);
1104 val = strchr(key,
'=');
1105 if (!val || *(val + 1) ==
'\0')
1107 lwpgerror(
"Missing value for buffer parameter %s", key);
1113 POSTGIS_DEBUGF(3,
"Param: %s : %s", key, val);
1115 if ( !strcmp(key,
"endcap") )
1120 if ( !strcmp(val,
"round") )
1122 endCapStyle = ENDCAP_ROUND;
1124 else if ( !strcmp(val,
"flat") ||
1125 !strcmp(val,
"butt") )
1127 endCapStyle = ENDCAP_FLAT;
1129 else if ( !strcmp(val,
"square") )
1131 endCapStyle = ENDCAP_SQUARE;
1135 lwpgerror(
"Invalid buffer end cap "
1136 "style: %s (accept: "
1137 "'round', 'flat', 'butt' "
1144 else if ( !strcmp(key,
"join") )
1146 if ( !strcmp(val,
"round") )
1148 joinStyle = JOIN_ROUND;
1150 else if ( !strcmp(val,
"mitre") ||
1151 !strcmp(val,
"miter") )
1153 joinStyle = JOIN_MITRE;
1155 else if ( !strcmp(val,
"bevel") )
1157 joinStyle = JOIN_BEVEL;
1161 lwpgerror(
"Invalid buffer end cap "
1162 "style: %s (accept: "
1163 "'round', 'mitre', 'miter' "
1169 else if ( !strcmp(key,
"mitre_limit") ||
1170 !strcmp(key,
"miter_limit") )
1173 mitreLimit = atof(val);
1175 else if ( !strcmp(key,
"quad_segs") )
1178 quadsegs = atoi(val);
1180 else if ( !strcmp(key,
"side") )
1182 if ( !strcmp(val,
"both") )
1186 else if ( !strcmp(val,
"left") )
1190 else if ( !strcmp(val,
"right") )
1197 lwpgerror(
"Invalid side parameter: %s (accept: 'right', 'left', 'both')", val);
1204 "Invalid buffer parameter: %s (accept: 'endcap', 'join', 'mitre_limit', 'miter_limit', 'quad_segs' and 'side')",
1213 POSTGIS_DEBUGF(3,
"endCap:%d joinStyle:%d mitreLimit:%g",
1214 endCapStyle, joinStyle, mitreLimit);
1216 bufferparams = GEOSBufferParams_create();
1219 if (GEOSBufferParams_setEndCapStyle(bufferparams, endCapStyle) &&
1220 GEOSBufferParams_setJoinStyle(bufferparams, joinStyle) &&
1221 GEOSBufferParams_setMitreLimit(bufferparams, mitreLimit) &&
1222 GEOSBufferParams_setQuadrantSegments(bufferparams, quadsegs) &&
1223 GEOSBufferParams_setSingleSided(bufferparams, singleside))
1225 g3 = GEOSBufferWithParams(g1, bufferparams, size);
1229 lwpgerror(
"Error setting buffer parameters.");
1231 GEOSBufferParams_destroy(bufferparams);
1235 lwpgerror(
"Error setting buffer parameters.");
1238 GEOSGeom_destroy(g1);
1242 POSTGIS_DEBUGF(3,
"result: %s", GEOSGeomToWKT(g3));
1247 GEOSGeom_destroy(g3);
1251 elog(ERROR,
"GEOS buffer() threw an error (result postgis geometry formation)!");
1255 PG_FREE_IF_COPY(geom1, 0);
1256 PG_RETURN_POINTER(
result);
1275 gser_input = PG_GETARG_GSERIALIZED_P(0);
1276 npoints = PG_GETARG_INT32(1);
1281 if (PG_NARGS() > 2 && ! PG_ARGISNULL(2))
1283 seed = PG_GETARG_INT32(2);
1286 lwpgerror(
"ST_GeneratePoints: seed must be greater than zero");
1295 PG_FREE_IF_COPY(gser_input, 0);
1302 gser_result = geometry_serialize(lwgeom_result);
1304 PG_RETURN_POINTER(gser_result);
1330 static const double DEFAULT_MITRE_LIMIT = 5.0;
1331 static const int DEFAULT_JOIN_STYLE = JOIN_ROUND;
1332 double mitreLimit = DEFAULT_MITRE_LIMIT;
1333 int joinStyle = DEFAULT_JOIN_STYLE;
1335 char *paramstr = NULL;
1339 gser_input = PG_GETARG_GSERIALIZED_P(0);
1340 size = PG_GETARG_FLOAT8(1);
1343 if (size == 0) PG_RETURN_POINTER(gser_input);
1347 if ( ! lwgeom_input )
1348 lwpgerror(
"ST_OffsetCurve: lwgeom_from_gserialized returned NULL");
1352 PG_RETURN_POINTER(gser_input);
1357 text *wkttext = PG_GETARG_TEXT_P(2);
1358 paramstr = text_to_cstring(wkttext);
1360 POSTGIS_DEBUGF(3,
"paramstr: %s", paramstr);
1362 for ( param=paramstr; ; param=NULL )
1365 param = strtok(param,
" ");
1367 POSTGIS_DEBUGF(3,
"Param: %s", param);
1370 val = strchr(key,
'=');
1371 if (!val || *(val + 1) ==
'\0')
1373 lwpgerror(
"ST_OffsetCurve: Missing value for buffer parameter %s", key);
1379 POSTGIS_DEBUGF(3,
"Param: %s : %s", key, val);
1381 if ( !strcmp(key,
"join") )
1383 if ( !strcmp(val,
"round") )
1385 joinStyle = JOIN_ROUND;
1387 else if ( !(strcmp(val,
"mitre") && strcmp(val,
"miter")) )
1389 joinStyle = JOIN_MITRE;
1391 else if ( ! strcmp(val,
"bevel") )
1393 joinStyle = JOIN_BEVEL;
1398 "Invalid buffer end cap style: %s (accept: 'round', 'mitre', 'miter' or 'bevel')",
1403 else if ( !strcmp(key,
"mitre_limit") ||
1404 !strcmp(key,
"miter_limit") )
1407 mitreLimit = atof(val);
1409 else if ( !strcmp(key,
"quad_segs") )
1412 quadsegs = atoi(val);
1417 "Invalid buffer parameter: %s (accept: 'join', 'mitre_limit', 'miter_limit and 'quad_segs')",
1422 POSTGIS_DEBUGF(3,
"joinStyle:%d mitreLimit:%g", joinStyle, mitreLimit);
1426 lwgeom_result =
lwgeom_offsetcurve(lwgeom_input, size, quadsegs, joinStyle, mitreLimit);
1429 lwpgerror(
"ST_OffsetCurve: lwgeom_offsetcurve returned NULL");
1431 gser_result = geometry_serialize(lwgeom_result);
1434 PG_RETURN_POINTER(gser_result);
1443 LWGEOM *lwgeom1, *lwgeom2, *lwresult;
1446 geom1 = PG_GETARG_GSERIALIZED_P(0);
1447 geom2 = PG_GETARG_GSERIALIZED_P(1);
1448 if (PG_NARGS() > 2 && ! PG_ARGISNULL(2))
1449 prec = PG_GETARG_FLOAT8(2);
1455 result = geometry_serialize(lwresult);
1461 PG_FREE_IF_COPY(geom1, 0);
1462 PG_FREE_IF_COPY(geom2, 1);
1464 PG_RETURN_POINTER(
result);
1473 LWGEOM *lwgeom1, *lwgeom2, *lwresult;
1476 geom1 = PG_GETARG_GSERIALIZED_P(0);
1477 geom2 = PG_GETARG_GSERIALIZED_P(1);
1478 if (PG_NARGS() > 2 && ! PG_ARGISNULL(2))
1479 prec = PG_GETARG_FLOAT8(2);
1485 result = geometry_serialize(lwresult);
1491 PG_FREE_IF_COPY(geom1, 0);
1492 PG_FREE_IF_COPY(geom2, 1);
1494 PG_RETURN_POINTER(
result);
1505 LWGEOM *lwgeom, *lwresult;
1507 geom = PG_GETARG_GSERIALIZED_P(0);
1512 PG_FREE_IF_COPY(geom, 0);
1514 if (!lwresult) PG_RETURN_NULL();
1516 result = geometry_serialize(lwresult);
1518 PG_RETURN_POINTER(
result);
1525 LWGEOM *lwgeom, *lwresult;
1527 geom = PG_GETARG_GSERIALIZED_P(0);
1532 PG_FREE_IF_COPY(geom, 0);
1534 if (!lwresult) PG_RETURN_NULL();
1536 result = geometry_serialize(lwresult);
1538 PG_RETURN_POINTER(
result);
1546 LWGEOM *lwgeom, *lwresult;
1547 double gridSize = PG_GETARG_FLOAT8(1);
1548 geom = PG_GETARG_GSERIALIZED_P(0);
1553 PG_FREE_IF_COPY(geom, 0);
1555 if (!lwresult) PG_RETURN_NULL();
1557 result = geometry_serialize(lwresult);
1559 PG_RETURN_POINTER(
result);
1566 static const uint32_t geom_idx = 0;
1567 static const uint32_t box2d_idx = 1;
1569 LWGEOM *lwgeom1, *lwresult ;
1579 PG_RETURN_DATUM(PG_GETARG_DATUM(geom_idx));
1583 bbox2 = (
GBOX *)PG_GETARG_POINTER(box2d_idx);
1589 PG_RETURN_DATUM(PG_GETARG_DATUM(geom_idx));
1597 result = geometry_serialize(lwresult) ;
1599 PG_RETURN_POINTER(
result);
1611 result = geometry_serialize(lwresult) ;
1612 PG_RETURN_POINTER(
result);
1626 geom1 = PG_GETARG_GSERIALIZED_P(0);
1630 PG_RETURN_BOOL(
true);
1637 lwpgerror(
"unable to deserialize input");
1648 PG_RETURN_BOOL(
false);
1651 result = GEOSisValid(g1);
1652 GEOSGeom_destroy(g1);
1656 elog(ERROR,
"GEOS isvalid() threw an error!");
1660 PG_FREE_IF_COPY(geom1, 0);
1668 char *reason_str = NULL;
1670 const GEOSGeometry *g1 = NULL;
1672 geom = PG_GETARG_GSERIALIZED_P(0);
1679 reason_str = GEOSisValidReason(g1);
1680 GEOSGeom_destroy((GEOSGeometry *)g1);
1682 result = cstring_to_text(reason_str);
1683 GEOSFree(reason_str);
1690 PG_FREE_IF_COPY(geom, 0);
1691 PG_RETURN_POINTER(
result);
1698 const GEOSGeometry *g1 = NULL;
1700 char *geos_reason = NULL;
1701 char *reason = NULL;
1702 GEOSGeometry *geos_location = NULL;
1708 AttInMetadata *attinmeta;
1715 get_call_result_type(fcinfo, 0, &tupdesc);
1716 BlessTupleDesc(tupdesc);
1722 attinmeta = TupleDescGetAttInMetadata(tupdesc);
1724 geom = PG_GETARG_GSERIALIZED_P(0);
1725 flags = PG_GETARG_INT32(1);
1733 valid = GEOSisValidDetail(g1, flags, &geos_reason, &geos_location);
1734 GEOSGeom_destroy((GEOSGeometry *)g1);
1737 reason = pstrdup(geos_reason);
1738 GEOSFree(geos_reason);
1740 if ( geos_location )
1742 location =
GEOS2LWGEOM(geos_location, GEOSHasZ(geos_location));
1743 GEOSGeom_destroy(geos_location);
1749 lwpgerror(
"GEOS isvaliddetail() threw an exception!");
1760 values[0] = valid ?
"t" :
"f";
1768 tuple = BuildTupleFromCStrings(attinmeta, values);
1769 result = (HeapTupleHeader) palloc(tuple->t_len);
1770 memcpy(
result, tuple->t_data, tuple->t_len);
1771 heap_freetuple(tuple);
1773 PG_RETURN_HEAPTUPLEHEADER(
result);
1788 GEOSGeometry *g1, *g2;
1792 geom1 = PG_GETARG_GSERIALIZED_P(0);
1793 geom2 = PG_GETARG_GSERIALIZED_P(1);
1798 PG_RETURN_BOOL(
false);
1809 PG_RETURN_BOOL(
false);
1823 GEOSGeom_destroy(g1);
1827 result = GEOSOverlaps(g1,g2);
1829 GEOSGeom_destroy(g1);
1830 GEOSGeom_destroy(g2);
1833 PG_FREE_IF_COPY(geom1, 0);
1834 PG_FREE_IF_COPY(geom2, 1);
1843 SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
1844 SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
1845 const GSERIALIZED *geom1 = shared_gserialized_get(shared_geom1);
1846 const GSERIALIZED *geom2 = shared_gserialized_get(shared_geom2);
1848 GEOSGeometry *g1, *g2;
1855 PG_RETURN_BOOL(
false);
1857 POSTGIS_DEBUG(3,
"contains called.");
1867 PG_RETURN_BOOL(
false);
1876 SHARED_GSERIALIZED *shared_gpoly =
is_poly(geom1) ? shared_geom1 : shared_geom2;
1877 SHARED_GSERIALIZED *shared_gpoint =
is_point(geom1) ? shared_geom1 : shared_geom2;
1878 const GSERIALIZED *gpoly = shared_gserialized_get(shared_gpoly);
1879 const GSERIALIZED *gpoint = shared_gserialized_get(shared_gpoint);
1883 POSTGIS_DEBUG(3,
"Point in Polygon test requested...short-circuiting.");
1890 retval = (pip_result == 1);
1895 int found_completely_inside =
LW_FALSE;
1898 for (uint32_t i = 0; i < mpoint->
ngeoms; i++)
1909 if (pip_result == 1)
1910 found_completely_inside =
LW_TRUE;
1912 if (pip_result == -1)
1919 retval = retval && found_completely_inside;
1925 elog(ERROR,
"Type isn't point or multipoint!");
1926 PG_RETURN_BOOL(
false);
1946 POSTGIS_DEBUG(4,
"containsPrepared: cache is live, running preparedcontains");
1948 GEOSGeom_destroy(g1);
1953 if (!g1)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
1958 GEOSGeom_destroy(g1);
1960 POSTGIS_DEBUG(4,
"containsPrepared: cache is not ready, running standard contains");
1961 result = GEOSContains( g1, g2);
1962 GEOSGeom_destroy(g1);
1963 GEOSGeom_destroy(g2);
1968 PG_RETURN_BOOL(
result > 0);
1975 PG_RETURN_DATUM(CallerFInfoFunctionCall2(
contains, fcinfo->flinfo, InvalidOid,
1976 PG_GETARG_DATUM(1), PG_GETARG_DATUM(0)));
1984 SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
1985 SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
1986 const GSERIALIZED *geom1 = shared_gserialized_get(shared_geom1);
1987 const GSERIALIZED *geom2 = shared_gserialized_get(shared_geom2);
1996 PG_RETURN_BOOL(
false);
2006 PG_RETURN_BOOL(
false);
2016 if (!g)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
2018 GEOSGeom_destroy(g);
2026 if (!g1)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
2030 GEOSGeom_destroy(g1);
2033 result = GEOSRelatePattern( g1, g2,
"T**FF*FF*" );
2034 GEOSGeom_destroy(g1);
2035 GEOSGeom_destroy(g2);
2050 SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
2051 SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
2052 const GSERIALIZED *geom1 = shared_gserialized_get(shared_geom1);
2053 const GSERIALIZED *geom2 = shared_gserialized_get(shared_geom2);
2061 PG_RETURN_BOOL(
false);
2074 PG_RETURN_BOOL(
false);
2083 SHARED_GSERIALIZED *shared_gpoly =
is_poly(geom1) ? shared_geom1 : shared_geom2;
2084 SHARED_GSERIALIZED *shared_gpoint =
is_point(geom1) ? shared_geom1 : shared_geom2;
2085 const GSERIALIZED *gpoly = shared_gserialized_get(shared_gpoly);
2086 const GSERIALIZED *gpoint = shared_gserialized_get(shared_gpoint);
2090 POSTGIS_DEBUG(3,
"Point in Polygon test requested...short-circuiting.");
2097 retval = (pip_result != -1);
2105 for (i = 0; i < mpoint->
ngeoms; i++)
2121 elog(ERROR,
"Type isn't point or multipoint!");
2125 PG_RETURN_BOOL(retval);
2139 if (!g1)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
2141 GEOSGeom_destroy(g1);
2149 if (!g1)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
2153 GEOSGeom_destroy(g1);
2156 result = GEOSRelatePattern( g1, g2,
"******FF*" );
2157 GEOSGeom_destroy(g1);
2158 GEOSGeom_destroy(g2);
2181 SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
2182 SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
2183 const GSERIALIZED *geom1 = shared_gserialized_get(shared_geom1);
2184 const GSERIALIZED *geom2 = shared_gserialized_get(shared_geom2);
2185 GEOSGeometry *g1, *g2;
2188 char *patt =
"**F**F***";
2194 PG_RETURN_BOOL(
false);
2205 PG_RETURN_BOOL(
false);
2208 POSTGIS_DEBUG(3,
"bounding box short-circuit missed.");
2216 SHARED_GSERIALIZED *shared_gpoly =
is_poly(geom1) ? shared_geom1 : shared_geom2;
2217 SHARED_GSERIALIZED *shared_gpoint =
is_point(geom1) ? shared_geom1 : shared_geom2;
2218 const GSERIALIZED *gpoly = shared_gserialized_get(shared_gpoly);
2219 const GSERIALIZED *gpoint = shared_gserialized_get(shared_gpoint);
2223 POSTGIS_DEBUG(3,
"Point in Polygon test requested...short-circuiting.");
2230 retval = (pip_result != -1);
2238 for (i = 0; i < mpoint->
ngeoms; i++)
2254 elog(ERROR,
"Type isn't point or multipoint!");
2258 PG_RETURN_BOOL(retval);
2276 GEOSGeom_destroy(g1);
2280 result = GEOSRelatePattern(g1,g2,patt);
2282 GEOSGeom_destroy(g1);
2283 GEOSGeom_destroy(g2);
2295 GEOSGeometry *g1, *g2;
2299 geom1 = PG_GETARG_GSERIALIZED_P(0);
2300 geom2 = PG_GETARG_GSERIALIZED_P(1);
2305 PG_RETURN_BOOL(
false);
2316 PG_RETURN_BOOL(
false);
2329 GEOSGeom_destroy(g1);
2333 result = GEOSCrosses(g1,g2);
2335 GEOSGeom_destroy(g1);
2336 GEOSGeom_destroy(g2);
2340 PG_FREE_IF_COPY(geom1, 0);
2341 PG_FREE_IF_COPY(geom2, 1);
2349 SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
2350 SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
2351 const GSERIALIZED *geom1 = shared_gserialized_get(shared_geom1);
2352 const GSERIALIZED *geom2 = shared_gserialized_get(shared_geom2);
2361 PG_RETURN_BOOL(
false);
2371 PG_RETURN_BOOL(
false);
2380 SHARED_GSERIALIZED *shared_gpoly =
is_poly(geom1) ? shared_geom1 : shared_geom2;
2381 SHARED_GSERIALIZED *shared_gpoint =
is_point(geom1) ? shared_geom1 : shared_geom2;
2382 const GSERIALIZED *gpoly = shared_gserialized_get(shared_gpoly);
2383 const GSERIALIZED *gpoint = shared_gserialized_get(shared_gpoint);
2387 POSTGIS_DEBUG(3,
"Point in Polygon test requested...short-circuiting.");
2394 retval = (pip_result != -1);
2400 for (uint32_t i = 0; i < mpoint->
ngeoms; i++)
2416 elog(ERROR,
"Type isn't point or multipoint!");
2420 PG_RETURN_BOOL(retval);
2428 if ( prep_cache->
gcache.argnum == 1 )
2433 GEOSGeom_destroy(g);
2441 GEOSGeom_destroy(g);
2449 if (!g1)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
2453 GEOSGeom_destroy(g1);
2456 result = GEOSIntersects( g1, g2);
2457 GEOSGeom_destroy(g1);
2458 GEOSGeom_destroy(g2);
2472 GEOSGeometry *g1, *g2;
2476 geom1 = PG_GETARG_GSERIALIZED_P(0);
2477 geom2 = PG_GETARG_GSERIALIZED_P(1);
2482 PG_RETURN_BOOL(
false);
2493 PG_RETURN_BOOL(
false);
2506 GEOSGeom_destroy(g1);
2510 result = GEOSTouches(g1,g2);
2512 GEOSGeom_destroy(g1);
2513 GEOSGeom_destroy(g2);
2517 PG_FREE_IF_COPY(geom1, 0);
2518 PG_FREE_IF_COPY(geom2, 1);
2529 GEOSGeometry *g1, *g2;
2533 geom1 = PG_GETARG_GSERIALIZED_P(0);
2534 geom2 = PG_GETARG_GSERIALIZED_P(1);
2539 PG_RETURN_BOOL(
true);
2550 PG_RETURN_BOOL(
true);
2563 GEOSGeom_destroy(g1);
2567 result = GEOSDisjoint(g1,g2);
2569 GEOSGeom_destroy(g1);
2570 GEOSGeom_destroy(g2);
2574 PG_FREE_IF_COPY(geom1, 0);
2575 PG_FREE_IF_COPY(geom2, 1);
2589 GEOSGeometry *g1, *g2;
2592 geom1 = PG_GETARG_GSERIALIZED_P(0);
2593 geom2 = PG_GETARG_GSERIALIZED_P(1);
2606 GEOSGeom_destroy(g1);
2611 ptxt = DatumGetTextP(DirectFunctionCall2(text_left,
2612 PG_GETARG_DATUM(2), Int32GetDatum(9)));
2613 patt = text_to_cstring(ptxt);
2618 for ( i = 0; i < strlen(patt); i++ )
2620 if ( patt[i] ==
't' ) patt[i] =
'T';
2621 if ( patt[i] ==
'f' ) patt[i] =
'F';
2624 result = GEOSRelatePattern(g1,g2,patt);
2625 GEOSGeom_destroy(g1);
2626 GEOSGeom_destroy(g2);
2631 PG_FREE_IF_COPY(geom1, 0);
2632 PG_FREE_IF_COPY(geom2, 1);
2644 GEOSGeometry *g1, *g2;
2647 int bnr = GEOSRELATE_BNR_OGC;
2650 geom1 = PG_GETARG_GSERIALIZED_P(0);
2651 geom2 = PG_GETARG_GSERIALIZED_P(1);
2654 if ( PG_NARGS() > 2 )
2655 bnr = PG_GETARG_INT32(2);
2665 GEOSGeom_destroy(g1);
2669 POSTGIS_DEBUG(3,
"constructed geometries ");
2671 POSTGIS_DEBUGF(3,
"%s", GEOSGeomToWKT(g1));
2672 POSTGIS_DEBUGF(3,
"%s", GEOSGeomToWKT(g2));
2674 relate_str = GEOSRelateBoundaryNodeRule(g1, g2, bnr);
2676 GEOSGeom_destroy(g1);
2677 GEOSGeom_destroy(g2);
2681 result = cstring_to_text(relate_str);
2682 GEOSFree(relate_str);
2684 PG_FREE_IF_COPY(geom1, 0);
2685 PG_FREE_IF_COPY(geom2, 1);
2687 PG_RETURN_TEXT_P(
result);
2696 GEOSGeometry *g1, *g2;
2700 geom1 = PG_GETARG_GSERIALIZED_P(0);
2701 geom2 = PG_GETARG_GSERIALIZED_P(1);
2706 PG_RETURN_BOOL(
true);
2717 PG_RETURN_BOOL(
false);
2725 if (VARSIZE(geom1) == VARSIZE(geom2) && !memcmp(geom1, geom2, VARSIZE(geom1))) {
2726 PG_RETURN_BOOL(
true);
2740 GEOSGeom_destroy(g1);
2744 result = GEOSEquals(g1,g2);
2746 GEOSGeom_destroy(g1);
2747 GEOSGeom_destroy(g2);
2751 PG_FREE_IF_COPY(geom1, 0);
2752 PG_FREE_IF_COPY(geom2, 1);
2764 POSTGIS_DEBUG(2,
"issimple called");
2766 geom = PG_GETARG_GSERIALIZED_P(0);
2769 PG_RETURN_BOOL(
true);
2774 PG_FREE_IF_COPY(geom, 0);
2790 geom = PG_GETARG_GSERIALIZED_P(0);
2794 PG_RETURN_BOOL(
false);
2802 if ( GEOSGeomTypeId(g1) != GEOS_LINESTRING )
2804 GEOSGeom_destroy(g1);
2805 elog(ERROR,
"ST_IsRing() should only be called on a linear feature");
2809 GEOSGeom_destroy(g1);
2813 PG_FREE_IF_COPY(geom, 0);
2826 lwpgerror(
"%s: GEOS2LWGEOM returned NULL", __func__);
2830 POSTGIS_DEBUGF(4,
"%s: GEOS2LWGEOM returned a %s", __func__,
lwgeom_summary(lwgeom, 0));
2834 result = geometry_serialize(lwgeom);
2849 lwpgerror(
"POSTGIS2GEOS: unable to deserialize input");
2859 ArrayIterator iterator;
2862 uint32_t nelems_not_null = 0;
2863 iterator = array_create_iterator(array, 0, NULL);
2864 while(array_iterate(iterator, &
value, &isnull) )
2868 array_free_iterator(iterator);
2870 return nelems_not_null;
2876 ArrayIterator iterator;
2879 bool gotsrid =
false;
2884 iterator = array_create_iterator(array, 0, NULL);
2886 while (array_iterate(iterator, &
value, &isnull))
2898 lwpgerror(
"Geometry deserializing geometry");
2916 GEOSGeometry**
ARRAY2GEOS(ArrayType* array, uint32_t nelems,
int* is3d,
int* srid)
2918 ArrayIterator iterator;
2921 bool gotsrid =
false;
2924 GEOSGeometry** geos_geoms = palloc(nelems *
sizeof(GEOSGeometry*));
2926 iterator = array_create_iterator(array, 0, NULL);
2928 while(array_iterate(iterator, &
value, &isnull))
2941 lwpgerror(
"Geometry could not be converted to GEOS");
2943 for (j = 0; j < i; j++) {
2944 GEOSGeom_destroy(geos_geoms[j]);
2957 for (j = 0; j <= i; j++) {
2958 GEOSGeom_destroy(geos_geoms[j]);
2967 array_free_iterator(iterator);
2975 GEOSGeometry *geosgeom;
2980 geom = PG_GETARG_GSERIALIZED_P(0);
2982 if ( ! geosgeom ) PG_RETURN_NULL();
2985 GEOSGeom_destroy(geosgeom);
2987 PG_FREE_IF_COPY(geom, 0);
2989 PG_RETURN_POINTER(lwgeom_result);
2999 GEOSGeometry *geos_result;
3000 const GEOSGeometry **vgeoms;
3002 #if POSTGIS_DEBUG_LEVEL >= 3
3006 #if POSTGIS_DEBUG_LEVEL >= 3
3010 if (PG_ARGISNULL(0))
3013 array = PG_GETARG_ARRAYTYPE_P(0);
3019 POSTGIS_DEBUGF(3,
"polygonize_garray: number of non-null elements: %d", nelems);
3024 vgeoms = (
const GEOSGeometry**)
ARRAY2GEOS(array, nelems, &is3d, &srid);
3026 POSTGIS_DEBUG(3,
"polygonize_garray: invoking GEOSpolygonize");
3028 geos_result = GEOSPolygonize(vgeoms, nelems);
3030 POSTGIS_DEBUG(3,
"polygonize_garray: GEOSpolygonize returned");
3032 for (i=0; i<nelems; ++i) GEOSGeom_destroy((GEOSGeometry *)vgeoms[i]);
3035 if ( ! geos_result ) PG_RETURN_NULL();
3037 GEOSSetSRID(geos_result, srid);
3039 GEOSGeom_destroy(geos_result);
3042 elog(ERROR,
"%s returned an error", __func__);
3046 PG_RETURN_POINTER(
result);
3053 Datum* result_array_data;
3054 ArrayType *array, *
result;
3056 uint32 nelems, nclusters, i;
3057 GEOSGeometry **geos_inputs, **geos_results;
3066 if (PG_ARGISNULL(0))
3069 array = PG_GETARG_ARRAYTYPE_P(0);
3072 POSTGIS_DEBUGF(3,
"clusterintersecting_garray: number of non-null elements: %d", nelems);
3074 if ( nelems == 0 ) PG_RETURN_NULL();
3081 geos_inputs =
ARRAY2GEOS(array, nelems, &is3d, &srid);
3089 elog(ERROR,
"clusterintersecting: Error performing clustering");
3094 if (!geos_results) PG_RETURN_NULL();
3096 result_array_data = palloc(nclusters *
sizeof(Datum));
3097 for (i=0; i<nclusters; ++i)
3099 result_array_data[i] = PointerGetDatum(
GEOS2POSTGIS(geos_results[i], is3d));
3100 GEOSGeom_destroy(geos_results[i]);
3104 get_typlenbyvalalign(array->elemtype, &elmlen, &elmbyval, &elmalign);
3105 result = construct_array(result_array_data, nclusters, array->elemtype, elmlen, elmbyval, elmalign);
3109 elog(ERROR,
"clusterintersecting: Error constructing return-array");
3113 PG_RETURN_POINTER(
result);
3119 Datum* result_array_data;
3120 ArrayType *array, *
result;
3122 uint32 nelems, nclusters, i;
3134 if (PG_ARGISNULL(0))
3137 array = PG_GETARG_ARRAYTYPE_P(0);
3139 tolerance = PG_GETARG_FLOAT8(1);
3142 lwpgerror(
"Tolerance must be a positive number.");
3148 POSTGIS_DEBUGF(3,
"cluster_within_distance_garray: number of non-null elements: %d", nelems);
3150 if ( nelems == 0 ) PG_RETURN_NULL();
3165 elog(ERROR,
"cluster_within: Error performing clustering");
3170 if (!lw_results) PG_RETURN_NULL();
3172 result_array_data = palloc(nclusters *
sizeof(Datum));
3173 for (i=0; i<nclusters; ++i)
3175 result_array_data[i] = PointerGetDatum(geometry_serialize(lw_results[i]));
3180 get_typlenbyvalalign(array->elemtype, &elmlen, &elmbyval, &elmalign);
3181 result = construct_array(result_array_data, nclusters, array->elemtype, elmlen, elmbyval, elmalign);
3185 elog(ERROR,
"clusterwithin: Error constructing return-array");
3189 PG_RETURN_POINTER(
result);
3197 LWGEOM *lwgeom1, *lwresult ;
3199 geom1 = PG_GETARG_GSERIALIZED_P(0);
3205 result = geometry_serialize(lwresult) ;
3210 PG_FREE_IF_COPY(geom1, 0);
3212 PG_RETURN_POINTER(
result);
3227 LWGEOM *lwgeom_in, *lwgeom_out;
3229 geom = PG_GETARG_GSERIALIZED_P(0);
3237 PG_FREE_IF_COPY(geom, 0);
3241 result = geometry_serialize(lwgeom_out) ;
3244 PG_FREE_IF_COPY(geom, 0);
3245 PG_RETURN_POINTER(
result);
3257 LWGEOM *lwgeom_in, *lwgeom_out;
3258 double tolerance = 0.0;
3261 geom = PG_GETARG_GSERIALIZED_P(0);
3262 tolerance = PG_GETARG_FLOAT8(1);
3263 flags = PG_GETARG_INT32(2);
3271 PG_FREE_IF_COPY(geom, 0);
3275 result = geometry_serialize(lwgeom_out) ;
3278 PG_FREE_IF_COPY(geom, 0);
3279 PG_RETURN_POINTER(
result);
3287 Datum
ST_Snap(PG_FUNCTION_ARGS);
3292 LWGEOM *lwgeom1, *lwgeom2, *lwresult;
3295 geom1 = PG_GETARG_GSERIALIZED_P(0);
3296 geom2 = PG_GETARG_GSERIALIZED_P(1);
3297 tolerance = PG_GETARG_FLOAT8(2);
3302 lwresult =
lwgeom_snap(lwgeom1, lwgeom2, tolerance);
3305 PG_FREE_IF_COPY(geom1, 0);
3306 PG_FREE_IF_COPY(geom2, 1);
3308 result = geometry_serialize(lwresult);
3311 PG_RETURN_POINTER(
result);
3343 LWGEOM *lwgeom_in, *lwblade_in, *lwgeom_out;
3345 in = PG_GETARG_GSERIALIZED_P(0);
3346 blade_in = PG_GETARG_GSERIALIZED_P(1);
3354 lwpgerror(
"Input Geometry contains invalid coordinates");
3360 lwpgerror(
"Blade Geometry contains invalid coordinates");
3371 PG_FREE_IF_COPY(in, 0);
3372 PG_FREE_IF_COPY(blade_in, 1);
3376 out = geometry_serialize(lwgeom_out);
3378 PG_FREE_IF_COPY(in, 0);
3379 PG_FREE_IF_COPY(blade_in, 1);
3381 PG_RETURN_POINTER(out);
3404 LWGEOM *g1, *g2, *lwgeom_out;
3406 geom1 = PG_GETARG_GSERIALIZED_P(0);
3407 geom2 = PG_GETARG_GSERIALIZED_P(1);
3418 PG_FREE_IF_COPY(geom1, 0);
3419 PG_FREE_IF_COPY(geom2, 1);
3423 out = geometry_serialize(lwgeom_out);
3426 PG_FREE_IF_COPY(geom1, 0);
3427 PG_FREE_IF_COPY(geom2, 1);
3428 PG_RETURN_POINTER(out);
3440 Datum
ST_Node(PG_FUNCTION_ARGS);
3447 geom1 = PG_GETARG_GSERIALIZED_P(0);
3456 PG_FREE_IF_COPY(geom1, 0);
3460 out = geometry_serialize(lwgeom_out);
3463 PG_FREE_IF_COPY(geom1, 0);
3464 PG_RETURN_POINTER(out);
3486 int custom_clip_envelope;
3487 int return_polygons;
3490 if (PG_ARGISNULL(0))
3494 if (PG_ARGISNULL(2))
3496 lwpgerror(
"Tolerance must be a positive number.");
3500 tolerance = PG_GETARG_FLOAT8(2);
3504 lwpgerror(
"Tolerance must be a positive number.");
3509 if (PG_ARGISNULL(3))
3511 lwpgerror(
"return_polygons must be true or false.");
3514 return_polygons = PG_GETARG_BOOL(3);
3517 custom_clip_envelope = !PG_ARGISNULL(1);
3518 if (custom_clip_envelope) {
3519 clip = PG_GETARG_GSERIALIZED_P(1);
3522 lwpgerror(
"Could not determine envelope of clipping geometry.");
3523 PG_FREE_IF_COPY(clip, 1);
3526 PG_FREE_IF_COPY(clip, 1);
3530 input = PG_GETARG_GSERIALIZED_P(0);
3536 lwpgerror(
"Could not read input geometry.");
3537 PG_FREE_IF_COPY(input, 0);
3541 lwgeom_result =
lwgeom_voronoi_diagram(lwgeom_input, custom_clip_envelope ? &clip_envelope : NULL, tolerance, !return_polygons);
3546 lwpgerror(
"Error computing Voronoi diagram.");
3547 PG_FREE_IF_COPY(input, 0);
3551 result = geometry_serialize(lwgeom_result);
3554 PG_FREE_IF_COPY(input, 0);
3555 PG_RETURN_POINTER(
result);
3570 GEOSGeometry* input_geos;
3576 input = PG_GETARG_GSERIALIZED_P(0);
3581 error = GEOSMinimumClearance(input_geos, &
result);
3582 GEOSGeom_destroy(input_geos);
3585 PG_FREE_IF_COPY(input, 0);
3586 PG_RETURN_FLOAT8(
result);
3602 GEOSGeometry* input_geos;
3603 GEOSGeometry* result_geos;
3608 input = PG_GETARG_GSERIALIZED_P(0);
3614 result_geos = GEOSMinimumClearanceLine(input_geos);
3615 GEOSGeom_destroy(input_geos);
3619 GEOSSetSRID(result_geos, srid);
3621 GEOSGeom_destroy(result_geos);
3623 PG_FREE_IF_COPY(input, 0);
3624 PG_RETURN_POINTER(
result);
3638 GEOSGeometry* input_geos;
3639 GEOSGeometry* result_geos;
3644 input = PG_GETARG_GSERIALIZED_P(0);
3650 result_geos = GEOSMinimumRotatedRectangle(input_geos);
3651 GEOSGeom_destroy(input_geos);
3655 GEOSSetSRID(result_geos, srid);
3657 GEOSGeom_destroy(result_geos);
3659 PG_FREE_IF_COPY(input, 0);
3660 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 * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
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)
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.
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_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)
void lwcollection_free(LWCOLLECTION *col)
LWGEOM * lwgeom_intersection_prec(const LWGEOM *geom1, const LWGEOM *geom2, double gridSize)
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)
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_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)
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)
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)
#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()