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"
57 Datum
touches(PG_FUNCTION_ARGS);
59 Datum
crosses(PG_FUNCTION_ARGS);
61 Datum
within(PG_FUNCTION_ARGS);
63 Datum
covers(PG_FUNCTION_ARGS);
65 Datum
isvalid(PG_FUNCTION_ARGS);
68 Datum
buffer(PG_FUNCTION_ARGS);
77 Datum
isring(PG_FUNCTION_ARGS);
109 text *
result = cstring_to_text(ver);
110 PG_RETURN_POINTER(
result);
117 text *
result = cstring_to_text(ver);
118 PG_RETURN_POINTER(
result);
182 geom1 = PG_GETARG_GSERIALIZED_P(0);
183 geom2 = PG_GETARG_GSERIALIZED_P(1);
197 GEOSGeom_destroy(g1);
201 retcode = GEOSHausdorffDistance(g1, g2, &
result);
202 GEOSGeom_destroy(g1);
203 GEOSGeom_destroy(g2);
207 PG_FREE_IF_COPY(geom1, 0);
208 PG_FREE_IF_COPY(geom2, 1);
232 geom1 = PG_GETARG_GSERIALIZED_P(0);
233 geom2 = PG_GETARG_GSERIALIZED_P(1);
234 densifyFrac = PG_GETARG_FLOAT8(2);
248 GEOSGeom_destroy(g1);
252 retcode = GEOSHausdorffDistanceDensify(g1, g2, densifyFrac, &
result);
253 GEOSGeom_destroy(g1);
254 GEOSGeom_destroy(g2);
258 PG_FREE_IF_COPY(geom1, 0);
259 PG_FREE_IF_COPY(geom2, 1);
274 #if POSTGIS_GEOS_VERSION < 30700
276 lwpgerror(
"The GEOS version this PostGIS binary "
277 "was compiled against (%d) doesn't support "
278 "'GEOSFechetDistance' function (3.7.0+ required)",
291 geom1 = PG_GETARG_GSERIALIZED_P(0);
292 geom2 = PG_GETARG_GSERIALIZED_P(1);
293 densifyFrac = PG_GETARG_FLOAT8(2);
307 GEOSGeom_destroy(g1);
311 if (densifyFrac <= 0.0)
313 retcode = GEOSFrechetDistance(g1, g2, &
result);
317 retcode = GEOSFrechetDistanceDensify(g1, g2, densifyFrac, &
result);
320 GEOSGeom_destroy(g1);
321 GEOSGeom_destroy(g2);
325 PG_FREE_IF_COPY(geom1, 0);
326 PG_FREE_IF_COPY(geom2, 1);
338 #if POSTGIS_GEOS_VERSION < 30900
340 lwpgerror(
"The GEOS version this PostGIS binary "
341 "was compiled against (%d) doesn't support "
342 "'GEOSMaximumInscribedCircle' function (3.9.0+ required)",
350 TupleDesc resultTupleDesc;
351 HeapTuple resultTuple;
353 Datum result_values[3];
354 bool result_is_null[3];
362 geom = PG_GETARG_GSERIALIZED_P(0);
371 center = geometry_serialize(lwcenter);
372 nearest = geometry_serialize(lwnearest);
377 GEOSGeometry *ginput, *gcircle, *gcenter, *gnearest;
378 double width, height, size, tolerance;
385 lwpgerror(
"Geometry contains invalid coordinates");
395 size = width > height ? width : height;
396 tolerance = size / 1000.0;
407 gcircle = GEOSMaximumInscribedCircle(ginput, tolerance);
410 lwpgerror(
"Error calculating GEOSMaximumInscribedCircle.");
411 GEOSGeom_destroy(ginput);
417 gcircle = GEOSLargestEmptyCircle(ginput, NULL, tolerance);
420 lwpgerror(
"Error calculating GEOSLargestEmptyCircle.");
421 GEOSGeom_destroy(ginput);
426 gcenter = GEOSGeomGetStartPoint(gcircle);
427 gnearest = GEOSGeomGetEndPoint(gcircle);
428 GEOSDistance(gcenter, gnearest, &radius);
429 GEOSSetSRID(gcenter, srid);
430 GEOSSetSRID(gnearest, srid);
434 GEOSGeom_destroy(gcenter);
435 GEOSGeom_destroy(gnearest);
436 GEOSGeom_destroy(gcircle);
437 GEOSGeom_destroy(ginput);
440 get_call_result_type(fcinfo, NULL, &resultTupleDesc);
441 BlessTupleDesc(resultTupleDesc);
443 result_values[0] = PointerGetDatum(center);
444 result_is_null[0] =
false;
445 result_values[1] = PointerGetDatum(nearest);
446 result_is_null[1] =
false;
447 result_values[2] = Float8GetDatum(radius);
448 result_is_null[2] =
false;
449 resultTuple = heap_form_tuple(resultTupleDesc, result_values, result_is_null);
451 result = HeapTupleGetDatum(resultTuple);
463 #if POSTGIS_GEOS_VERSION < 30900
465 lwpgerror(
"The GEOS version this PostGIS binary "
466 "was compiled against (%d) doesn't support "
467 "'GEOSMaximumInscribedCircle' function (3.9.0+ required)",
476 TupleDesc resultTupleDesc;
477 HeapTuple resultTuple;
479 Datum result_values[3];
480 bool result_is_null[3];
481 double radius = 0.0, tolerance = 0.0;
483 bool is3d =
false, hasBoundary =
false;
488 geom = PG_GETARG_GSERIALIZED_P(0);
489 tolerance = PG_GETARG_FLOAT8(1);
490 boundary = PG_GETARG_GSERIALIZED_P(2);
502 center = geometry_serialize(lwcenter);
503 nearest = geometry_serialize(lwnearest);
508 GEOSGeometry *ginput, *gcircle, *gcenter, *gnearest;
509 GEOSGeometry *gboundary = NULL;
510 double width, height, size;
516 lwpgerror(
"Geometry contains invalid coordinates");
529 size = width > height ? width : height;
530 tolerance = size / 1000.0;
546 gcircle = GEOSLargestEmptyCircle(ginput, gboundary, tolerance);
549 lwpgerror(
"Error calculating GEOSLargestEmptyCircle.");
550 GEOSGeom_destroy(ginput);
554 gcenter = GEOSGeomGetStartPoint(gcircle);
555 gnearest = GEOSGeomGetEndPoint(gcircle);
556 GEOSDistance(gcenter, gnearest, &radius);
557 GEOSSetSRID(gcenter, srid);
558 GEOSSetSRID(gnearest, srid);
562 GEOSGeom_destroy(gcenter);
563 GEOSGeom_destroy(gnearest);
564 GEOSGeom_destroy(gcircle);
565 GEOSGeom_destroy(ginput);
566 if (gboundary) GEOSGeom_destroy(gboundary);
569 get_call_result_type(fcinfo, NULL, &resultTupleDesc);
570 BlessTupleDesc(resultTupleDesc);
572 result_values[0] = PointerGetDatum(center);
573 result_is_null[0] =
false;
574 result_values[1] = PointerGetDatum(nearest);
575 result_is_null[1] =
false;
576 result_values[2] = Float8GetDatum(radius);
577 result_is_null[2] =
false;
578 resultTuple = heap_form_tuple(resultTupleDesc, result_values, result_is_null);
580 result = HeapTupleGetDatum(resultTuple);
601 ArrayIterator iterator;
606 int nelems = 0, geoms_size = 0, curgeom = 0,
count = 0;
610 GEOSGeometry *g = NULL;
611 GEOSGeometry *g_union = NULL;
612 GEOSGeometry **geoms = NULL;
619 if ( PG_ARGISNULL(0) )
622 array = PG_GETARG_ARRAYTYPE_P(0);
623 nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
626 if ( nelems == 0 ) PG_RETURN_NULL();
629 iterator = array_create_iterator(array, 0, NULL);
630 while (array_iterate(iterator, &
value, &isnull))
633 if (isnull)
continue;
636 array_free_iterator(iterator);
644 if (
count == 1 && nelems == 1 )
646 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
647 #pragma GCC diagnostic push
648 #pragma GCC diagnostic ignored "-Wsign-compare"
650 PG_RETURN_POINTER((
GSERIALIZED *)(ARR_DATA_PTR(array)));
651 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
652 #pragma GCC diagnostic pop
663 geoms = palloc(
sizeof(GEOSGeometry*) * geoms_size);
669 iterator = array_create_iterator(array, 0, NULL);
670 while (array_iterate(iterator, &
value, &isnull))
675 if (isnull)
continue;
693 if (gser_type > empty_type)
695 empty_type = gser_type;
696 POSTGIS_DEBUGF(4,
"empty_type = %d gser_type = %d", empty_type, gser_type);
707 "One of the geometries in the set "
708 "could not be converted to GEOS");
712 if ( curgeom == geoms_size )
715 geoms = repalloc( geoms,
sizeof(GEOSGeometry*) * geoms_size );
723 array_free_iterator(iterator);
731 g = GEOSGeom_createCollection(GEOS_GEOMETRYCOLLECTION, geoms, curgeom);
732 if (!g)
HANDLE_GEOS_ERROR(
"Could not create GEOS COLLECTION from geometry array");
734 g_union = GEOSUnaryUnion(g);
738 GEOSSetSRID(g_union, srid);
740 GEOSGeom_destroy(g_union);
746 if ( empty_type > 0 )
763 PG_RETURN_POINTER(gser_out);
778 LWGEOM *lwgeom1, *lwresult ;
781 geom1 = PG_GETARG_GSERIALIZED_P(0);
782 if (PG_NARGS() > 1 && ! PG_ARGISNULL(1))
783 prec = PG_GETARG_FLOAT8(1);
788 result = geometry_serialize(lwresult) ;
793 PG_FREE_IF_COPY(geom1, 0);
795 PG_RETURN_POINTER(
result);
804 LWGEOM *lwgeom1, *lwgeom2, *lwresult;
805 double gridSize = -1;
807 geom1 = PG_GETARG_GSERIALIZED_P(0);
808 geom2 = PG_GETARG_GSERIALIZED_P(1);
809 if (PG_NARGS() > 2 && ! PG_ARGISNULL(2))
810 gridSize = PG_GETARG_FLOAT8(2);
816 result = geometry_serialize(lwresult);
822 PG_FREE_IF_COPY(geom1, 0);
823 PG_FREE_IF_COPY(geom2, 1);
825 PG_RETURN_POINTER(
result);
833 PG_RETURN_DATUM(DirectFunctionCall2(
835 PG_GETARG_DATUM(0), PG_GETARG_DATUM(1)
850 LWGEOM *lwgeom1, *lwgeom2, *lwresult ;
853 geom1 = PG_GETARG_GSERIALIZED_P(0);
854 geom2 = PG_GETARG_GSERIALIZED_P(1);
855 if (PG_NARGS() > 2 && ! PG_ARGISNULL(2))
856 prec = PG_GETARG_FLOAT8(2);
862 result = geometry_serialize(lwresult) ;
868 PG_FREE_IF_COPY(geom1, 0);
869 PG_FREE_IF_COPY(geom2, 1);
871 PG_RETURN_POINTER(
result);
878 GEOSGeometry *g1, *g3;
884 geom1 = PG_GETARG_GSERIALIZED_P(0);
888 PG_RETURN_POINTER(geom1);
899 g3 = GEOSConvexHull(g1);
900 GEOSGeom_destroy(g1);
904 POSTGIS_DEBUGF(3,
"result: %s", GEOSGeomToWKT(g3));
906 GEOSSetSRID(g3, srid);
909 GEOSGeom_destroy(g3);
914 "convexhull() failed to convert GEOS geometry to LWGEOM");
926 result = geometry_serialize(lwout);
931 elog(ERROR,
"GEOS convexhull() threw an error (result postgis geometry formation)!");
935 PG_FREE_IF_COPY(geom1, 0);
936 PG_RETURN_POINTER(
result);
943 #if POSTGIS_GEOS_VERSION < 31100
945 lwpgerror(
"The GEOS version this PostGIS binary "
946 "was compiled against (%d) doesn't support "
947 "'GEOSConcaveHull' function (3.11.0+ required)",
953 double ratio = PG_GETARG_FLOAT8(1);
954 bool allow_holes = PG_GETARG_BOOL(2);
962 PG_FREE_IF_COPY(geom, 0);
963 PG_RETURN_POINTER(
result);
971 #if POSTGIS_GEOS_VERSION < 31100
973 lwpgerror(
"The GEOS version this PostGIS binary "
974 "was compiled against (%d) doesn't support "
975 "'ST_SimplifyPolygonHull' function (3.11.0+ required)",
981 double vertex_fraction = PG_GETARG_FLOAT8(1);
982 uint32_t is_outer = PG_GETARG_BOOL(2);
990 PG_FREE_IF_COPY(geom, 0);
991 PG_RETURN_POINTER(
result);
1002 GEOSGeometry *g1, *g3;
1006 gs1 = PG_GETARG_GSERIALIZED_P(0);
1007 tolerance = PG_GETARG_FLOAT8(1);
1013 PG_RETURN_POINTER(gs1);
1017 lwpgerror(
"Geometry contains invalid coordinates");
1028 g3 = GEOSTopologyPreserveSimplify(g1,tolerance);
1029 GEOSGeom_destroy(g1);
1033 POSTGIS_DEBUGF(3,
"result: %s", GEOSGeomToWKT(g3));
1038 GEOSGeom_destroy(g3);
1042 elog(ERROR,
"GEOS topologypreservesimplify() threw an error (result postgis geometry formation)!");
1046 PG_FREE_IF_COPY(gs1, 0);
1047 PG_RETURN_POINTER(
result);
1053 GEOSBufferParams *bufferparams;
1054 GEOSGeometry *g1, *g3 = NULL;
1071 const double DEFAULT_MITRE_LIMIT = 5.0;
1072 const int DEFAULT_ENDCAP_STYLE = ENDCAP_ROUND;
1073 const int DEFAULT_JOIN_STYLE = JOIN_ROUND;
1074 double mitreLimit = DEFAULT_MITRE_LIMIT;
1075 int endCapStyle = DEFAULT_ENDCAP_STYLE;
1076 int joinStyle = DEFAULT_JOIN_STYLE;
1079 double size = PG_GETARG_FLOAT8(1);
1084 params_text = PG_GETARG_TEXT_P(2);
1088 params_text = cstring_to_text(
"");
1097 PG_RETURN_POINTER(geometry_serialize(lwg));
1104 lwpgerror(
"Geometry contains invalid coordinates");
1116 if (VARSIZE_ANY_EXHDR(params_text) > 0)
1119 char *params = text_to_cstring(params_text);
1121 for (param=params; ; param=NULL)
1124 param = strtok(param,
" ");
1126 POSTGIS_DEBUGF(3,
"Param: %s", param);
1129 val = strchr(key,
'=');
1130 if (!val || *(val + 1) ==
'\0')
1132 lwpgerror(
"Missing value for buffer parameter %s", key);
1138 POSTGIS_DEBUGF(3,
"Param: %s : %s", key, val);
1140 if ( !strcmp(key,
"endcap") )
1145 if ( !strcmp(val,
"round") )
1147 endCapStyle = ENDCAP_ROUND;
1149 else if ( !strcmp(val,
"flat") ||
1150 !strcmp(val,
"butt") )
1152 endCapStyle = ENDCAP_FLAT;
1154 else if ( !strcmp(val,
"square") )
1156 endCapStyle = ENDCAP_SQUARE;
1160 lwpgerror(
"Invalid buffer end cap "
1161 "style: %s (accept: "
1162 "'round', 'flat', 'butt' "
1169 else if ( !strcmp(key,
"join") )
1171 if ( !strcmp(val,
"round") )
1173 joinStyle = JOIN_ROUND;
1175 else if ( !strcmp(val,
"mitre") ||
1176 !strcmp(val,
"miter") )
1178 joinStyle = JOIN_MITRE;
1180 else if ( !strcmp(val,
"bevel") )
1182 joinStyle = JOIN_BEVEL;
1186 lwpgerror(
"Invalid buffer end cap "
1187 "style: %s (accept: "
1188 "'round', 'mitre', 'miter' "
1194 else if ( !strcmp(key,
"mitre_limit") ||
1195 !strcmp(key,
"miter_limit") )
1198 mitreLimit = atof(val);
1200 else if ( !strcmp(key,
"quad_segs") )
1203 quadsegs = atoi(val);
1205 else if ( !strcmp(key,
"side") )
1207 if ( !strcmp(val,
"both") )
1211 else if ( !strcmp(val,
"left") )
1215 else if ( !strcmp(val,
"right") )
1222 lwpgerror(
"Invalid side parameter: %s (accept: 'right', 'left', 'both')", val);
1229 "Invalid buffer parameter: %s (accept: 'endcap', 'join', 'mitre_limit', 'miter_limit', 'quad_segs' and 'side')",
1238 POSTGIS_DEBUGF(3,
"endCap:%d joinStyle:%d mitreLimit:%g",
1239 endCapStyle, joinStyle, mitreLimit);
1241 bufferparams = GEOSBufferParams_create();
1244 if (GEOSBufferParams_setEndCapStyle(bufferparams, endCapStyle) &&
1245 GEOSBufferParams_setJoinStyle(bufferparams, joinStyle) &&
1246 GEOSBufferParams_setMitreLimit(bufferparams, mitreLimit) &&
1247 GEOSBufferParams_setQuadrantSegments(bufferparams, quadsegs) &&
1248 GEOSBufferParams_setSingleSided(bufferparams, singleside))
1250 g3 = GEOSBufferWithParams(g1, bufferparams, size);
1254 lwpgerror(
"Error setting buffer parameters.");
1256 GEOSBufferParams_destroy(bufferparams);
1260 lwpgerror(
"Error setting buffer parameters.");
1263 GEOSGeom_destroy(g1);
1267 POSTGIS_DEBUGF(3,
"result: %s", GEOSGeomToWKT(g3));
1272 GEOSGeom_destroy(g3);
1276 elog(ERROR,
"GEOS buffer() threw an error (result postgis geometry formation)!");
1280 PG_FREE_IF_COPY(geom1, 0);
1281 PG_RETURN_POINTER(
result);
1300 gser_input = PG_GETARG_GSERIALIZED_P(0);
1301 npoints = PG_GETARG_INT32(1);
1306 if (PG_NARGS() > 2 && ! PG_ARGISNULL(2))
1308 seed = PG_GETARG_INT32(2);
1311 lwpgerror(
"ST_GeneratePoints: seed must be greater than zero");
1320 PG_FREE_IF_COPY(gser_input, 0);
1327 gser_result = geometry_serialize(lwgeom_result);
1329 PG_RETURN_POINTER(gser_result);
1355 static const double DEFAULT_MITRE_LIMIT = 5.0;
1356 static const int DEFAULT_JOIN_STYLE = JOIN_ROUND;
1357 double mitreLimit = DEFAULT_MITRE_LIMIT;
1358 int joinStyle = DEFAULT_JOIN_STYLE;
1360 char *paramstr = NULL;
1364 gser_input = PG_GETARG_GSERIALIZED_P(0);
1365 size = PG_GETARG_FLOAT8(1);
1368 if (size == 0) PG_RETURN_POINTER(gser_input);
1372 if ( ! lwgeom_input )
1373 lwpgerror(
"ST_OffsetCurve: lwgeom_from_gserialized returned NULL");
1377 PG_RETURN_POINTER(gser_input);
1382 text *wkttext = PG_GETARG_TEXT_P(2);
1383 paramstr = text_to_cstring(wkttext);
1385 POSTGIS_DEBUGF(3,
"paramstr: %s", paramstr);
1387 for ( param=paramstr; ; param=NULL )
1390 param = strtok(param,
" ");
1392 POSTGIS_DEBUGF(3,
"Param: %s", param);
1395 val = strchr(key,
'=');
1396 if (!val || *(val + 1) ==
'\0')
1398 lwpgerror(
"ST_OffsetCurve: Missing value for buffer parameter %s", key);
1404 POSTGIS_DEBUGF(3,
"Param: %s : %s", key, val);
1406 if ( !strcmp(key,
"join") )
1408 if ( !strcmp(val,
"round") )
1410 joinStyle = JOIN_ROUND;
1412 else if ( !(strcmp(val,
"mitre") && strcmp(val,
"miter")) )
1414 joinStyle = JOIN_MITRE;
1416 else if ( ! strcmp(val,
"bevel") )
1418 joinStyle = JOIN_BEVEL;
1423 "Invalid buffer end cap style: %s (accept: 'round', 'mitre', 'miter' or 'bevel')",
1428 else if ( !strcmp(key,
"mitre_limit") ||
1429 !strcmp(key,
"miter_limit") )
1432 mitreLimit = atof(val);
1434 else if ( !strcmp(key,
"quad_segs") )
1437 quadsegs = atoi(val);
1442 "Invalid buffer parameter: %s (accept: 'join', 'mitre_limit', 'miter_limit and 'quad_segs')",
1447 POSTGIS_DEBUGF(3,
"joinStyle:%d mitreLimit:%g", joinStyle, mitreLimit);
1451 lwgeom_result =
lwgeom_offsetcurve(lwgeom_input, size, quadsegs, joinStyle, mitreLimit);
1454 lwpgerror(
"ST_OffsetCurve: lwgeom_offsetcurve returned NULL");
1456 gser_result = geometry_serialize(lwgeom_result);
1459 PG_RETURN_POINTER(gser_result);
1468 LWGEOM *lwgeom1, *lwgeom2, *lwresult;
1471 geom1 = PG_GETARG_GSERIALIZED_P(0);
1472 geom2 = PG_GETARG_GSERIALIZED_P(1);
1473 if (PG_NARGS() > 2 && ! PG_ARGISNULL(2))
1474 prec = PG_GETARG_FLOAT8(2);
1480 result = geometry_serialize(lwresult);
1486 PG_FREE_IF_COPY(geom1, 0);
1487 PG_FREE_IF_COPY(geom2, 1);
1489 PG_RETURN_POINTER(
result);
1498 LWGEOM *lwgeom1, *lwgeom2, *lwresult;
1501 geom1 = PG_GETARG_GSERIALIZED_P(0);
1502 geom2 = PG_GETARG_GSERIALIZED_P(1);
1503 if (PG_NARGS() > 2 && ! PG_ARGISNULL(2))
1504 prec = PG_GETARG_FLOAT8(2);
1510 result = geometry_serialize(lwresult);
1516 PG_FREE_IF_COPY(geom1, 0);
1517 PG_FREE_IF_COPY(geom2, 1);
1519 PG_RETURN_POINTER(
result);
1530 LWGEOM *lwgeom, *lwresult;
1532 geom = PG_GETARG_GSERIALIZED_P(0);
1537 PG_FREE_IF_COPY(geom, 0);
1539 if (!lwresult) PG_RETURN_NULL();
1541 result = geometry_serialize(lwresult);
1543 PG_RETURN_POINTER(
result);
1550 LWGEOM *lwgeom, *lwresult;
1552 geom = PG_GETARG_GSERIALIZED_P(0);
1557 PG_FREE_IF_COPY(geom, 0);
1559 if (!lwresult) PG_RETURN_NULL();
1561 result = geometry_serialize(lwresult);
1563 PG_RETURN_POINTER(
result);
1571 LWGEOM *lwgeom, *lwresult;
1572 double gridSize = PG_GETARG_FLOAT8(1);
1573 geom = PG_GETARG_GSERIALIZED_P(0);
1578 PG_FREE_IF_COPY(geom, 0);
1580 if (!lwresult) PG_RETURN_NULL();
1582 result = geometry_serialize(lwresult);
1584 PG_RETURN_POINTER(
result);
1591 static const uint32_t geom_idx = 0;
1592 static const uint32_t box2d_idx = 1;
1594 LWGEOM *lwgeom1, *lwresult ;
1604 PG_RETURN_DATUM(PG_GETARG_DATUM(geom_idx));
1608 bbox2 = (
GBOX *)PG_GETARG_POINTER(box2d_idx);
1614 PG_RETURN_DATUM(PG_GETARG_DATUM(geom_idx));
1622 result = geometry_serialize(lwresult) ;
1624 PG_RETURN_POINTER(
result);
1636 result = geometry_serialize(lwresult) ;
1637 PG_RETURN_POINTER(
result);
1651 geom1 = PG_GETARG_GSERIALIZED_P(0);
1655 PG_RETURN_BOOL(
true);
1662 lwpgerror(
"unable to deserialize input");
1669 PG_RETURN_BOOL(
false);
1672 result = GEOSisValid(g1);
1673 GEOSGeom_destroy(g1);
1677 elog(ERROR,
"GEOS isvalid() threw an error!");
1681 PG_FREE_IF_COPY(geom1, 0);
1689 char *reason_str = NULL;
1691 const GEOSGeometry *g1 = NULL;
1693 geom = PG_GETARG_GSERIALIZED_P(0);
1700 reason_str = GEOSisValidReason(g1);
1701 GEOSGeom_destroy((GEOSGeometry *)g1);
1703 result = cstring_to_text(reason_str);
1704 GEOSFree(reason_str);
1711 PG_FREE_IF_COPY(geom, 0);
1712 PG_RETURN_POINTER(
result);
1719 const GEOSGeometry *g1 = NULL;
1721 char *geos_reason = NULL;
1722 char *reason = NULL;
1723 GEOSGeometry *geos_location = NULL;
1729 AttInMetadata *attinmeta;
1736 get_call_result_type(fcinfo, 0, &tupdesc);
1737 BlessTupleDesc(tupdesc);
1743 attinmeta = TupleDescGetAttInMetadata(tupdesc);
1745 geom = PG_GETARG_GSERIALIZED_P(0);
1746 flags = PG_GETARG_INT32(1);
1754 valid = GEOSisValidDetail(g1, flags, &geos_reason, &geos_location);
1755 GEOSGeom_destroy((GEOSGeometry *)g1);
1758 reason = pstrdup(geos_reason);
1759 GEOSFree(geos_reason);
1761 if ( geos_location )
1763 location =
GEOS2LWGEOM(geos_location, GEOSHasZ(geos_location));
1764 GEOSGeom_destroy(geos_location);
1770 lwpgerror(
"GEOS isvaliddetail() threw an exception!");
1781 values[0] = valid ?
"t" :
"f";
1789 tuple = BuildTupleFromCStrings(attinmeta, values);
1790 result = (HeapTupleHeader) palloc(tuple->t_len);
1791 memcpy(
result, tuple->t_data, tuple->t_len);
1792 heap_freetuple(tuple);
1794 PG_RETURN_HEAPTUPLEHEADER(
result);
1809 GEOSGeometry *g1, *g2;
1813 geom1 = PG_GETARG_GSERIALIZED_P(0);
1814 geom2 = PG_GETARG_GSERIALIZED_P(1);
1819 PG_RETURN_BOOL(
false);
1830 PG_RETURN_BOOL(
false);
1844 GEOSGeom_destroy(g1);
1848 result = GEOSOverlaps(g1,g2);
1850 GEOSGeom_destroy(g1);
1851 GEOSGeom_destroy(g2);
1854 PG_FREE_IF_COPY(geom1, 0);
1855 PG_FREE_IF_COPY(geom2, 1);
1864 SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
1865 SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
1866 const GSERIALIZED *geom1 = shared_gserialized_get(shared_geom1);
1867 const GSERIALIZED *geom2 = shared_gserialized_get(shared_geom2);
1869 GEOSGeometry *g1, *g2;
1876 PG_RETURN_BOOL(
false);
1878 POSTGIS_DEBUG(3,
"contains called.");
1888 PG_RETURN_BOOL(
false);
1897 SHARED_GSERIALIZED *shared_gpoly =
is_poly(geom1) ? shared_geom1 : shared_geom2;
1898 SHARED_GSERIALIZED *shared_gpoint =
is_point(geom1) ? shared_geom1 : shared_geom2;
1899 const GSERIALIZED *gpoly = shared_gserialized_get(shared_gpoly);
1900 const GSERIALIZED *gpoint = shared_gserialized_get(shared_gpoint);
1904 POSTGIS_DEBUG(3,
"Point in Polygon test requested...short-circuiting.");
1911 retval = (pip_result == 1);
1917 int found_completely_inside =
LW_FALSE;
1920 for (i = 0; i < mpoint->
ngeoms; i++)
1928 if (pip_result == 1)
1929 found_completely_inside =
LW_TRUE;
1931 if (pip_result == -1)
1938 retval = retval && found_completely_inside;
1944 elog(ERROR,
"Type isn't point or multipoint!");
1945 PG_RETURN_BOOL(
false);
1965 POSTGIS_DEBUG(4,
"containsPrepared: cache is live, running preparedcontains");
1967 GEOSGeom_destroy(g1);
1972 if (!g1)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
1977 GEOSGeom_destroy(g1);
1979 POSTGIS_DEBUG(4,
"containsPrepared: cache is not ready, running standard contains");
1980 result = GEOSContains( g1, g2);
1981 GEOSGeom_destroy(g1);
1982 GEOSGeom_destroy(g2);
1987 PG_RETURN_BOOL(
result > 0);
1994 PG_RETURN_DATUM(CallerFInfoFunctionCall2(
contains, fcinfo->flinfo, InvalidOid,
1995 PG_GETARG_DATUM(1), PG_GETARG_DATUM(0)));
2003 SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
2004 SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
2005 const GSERIALIZED *geom1 = shared_gserialized_get(shared_geom1);
2006 const GSERIALIZED *geom2 = shared_gserialized_get(shared_geom2);
2015 PG_RETURN_BOOL(
false);
2025 PG_RETURN_BOOL(
false);
2035 if (!g)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
2037 GEOSGeom_destroy(g);
2045 if (!g1)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
2049 GEOSGeom_destroy(g1);
2052 result = GEOSRelatePattern( g1, g2,
"T**FF*FF*" );
2053 GEOSGeom_destroy(g1);
2054 GEOSGeom_destroy(g2);
2069 SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
2070 SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
2071 const GSERIALIZED *geom1 = shared_gserialized_get(shared_geom1);
2072 const GSERIALIZED *geom2 = shared_gserialized_get(shared_geom2);
2080 PG_RETURN_BOOL(
false);
2093 PG_RETURN_BOOL(
false);
2102 SHARED_GSERIALIZED *shared_gpoly =
is_poly(geom1) ? shared_geom1 : shared_geom2;
2103 SHARED_GSERIALIZED *shared_gpoint =
is_point(geom1) ? shared_geom1 : shared_geom2;
2104 const GSERIALIZED *gpoly = shared_gserialized_get(shared_gpoly);
2105 const GSERIALIZED *gpoint = shared_gserialized_get(shared_gpoint);
2109 POSTGIS_DEBUG(3,
"Point in Polygon test requested...short-circuiting.");
2116 retval = (pip_result != -1);
2124 for (i = 0; i < mpoint->
ngeoms; i++)
2127 if (pip_result == -1)
2139 elog(ERROR,
"Type isn't point or multipoint!");
2143 PG_RETURN_BOOL(retval);
2157 if (!g1)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
2159 GEOSGeom_destroy(g1);
2167 if (!g1)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
2171 GEOSGeom_destroy(g1);
2174 result = GEOSRelatePattern( g1, g2,
"******FF*" );
2175 GEOSGeom_destroy(g1);
2176 GEOSGeom_destroy(g2);
2199 SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
2200 SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
2201 const GSERIALIZED *geom1 = shared_gserialized_get(shared_geom1);
2202 const GSERIALIZED *geom2 = shared_gserialized_get(shared_geom2);
2203 GEOSGeometry *g1, *g2;
2206 char *patt =
"**F**F***";
2212 PG_RETURN_BOOL(
false);
2223 PG_RETURN_BOOL(
false);
2226 POSTGIS_DEBUG(3,
"bounding box short-circuit missed.");
2234 SHARED_GSERIALIZED *shared_gpoly =
is_poly(geom1) ? shared_geom1 : shared_geom2;
2235 SHARED_GSERIALIZED *shared_gpoint =
is_point(geom1) ? shared_geom1 : shared_geom2;
2236 const GSERIALIZED *gpoly = shared_gserialized_get(shared_gpoly);
2237 const GSERIALIZED *gpoint = shared_gserialized_get(shared_gpoint);
2241 POSTGIS_DEBUG(3,
"Point in Polygon test requested...short-circuiting.");
2248 retval = (pip_result != -1);
2256 for (i = 0; i < mpoint->
ngeoms; i++)
2259 if (pip_result == -1)
2271 elog(ERROR,
"Type isn't point or multipoint!");
2275 PG_RETURN_BOOL(retval);
2293 GEOSGeom_destroy(g1);
2297 result = GEOSRelatePattern(g1,g2,patt);
2299 GEOSGeom_destroy(g1);
2300 GEOSGeom_destroy(g2);
2312 GEOSGeometry *g1, *g2;
2316 geom1 = PG_GETARG_GSERIALIZED_P(0);
2317 geom2 = PG_GETARG_GSERIALIZED_P(1);
2322 PG_RETURN_BOOL(
false);
2333 PG_RETURN_BOOL(
false);
2346 GEOSGeom_destroy(g1);
2350 result = GEOSCrosses(g1,g2);
2352 GEOSGeom_destroy(g1);
2353 GEOSGeom_destroy(g2);
2357 PG_FREE_IF_COPY(geom1, 0);
2358 PG_FREE_IF_COPY(geom2, 1);
2366 SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
2367 SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
2368 const GSERIALIZED *geom1 = shared_gserialized_get(shared_geom1);
2369 const GSERIALIZED *geom2 = shared_gserialized_get(shared_geom2);
2378 PG_RETURN_BOOL(
false);
2388 PG_RETURN_BOOL(
false);
2397 SHARED_GSERIALIZED *shared_gpoly =
is_poly(geom1) ? shared_geom1 : shared_geom2;
2398 SHARED_GSERIALIZED *shared_gpoint =
is_point(geom1) ? shared_geom1 : shared_geom2;
2399 const GSERIALIZED *gpoly = shared_gserialized_get(shared_gpoly);
2400 const GSERIALIZED *gpoint = shared_gserialized_get(shared_gpoint);
2404 POSTGIS_DEBUG(3,
"Point in Polygon test requested...short-circuiting.");
2411 retval = (pip_result != -1);
2419 for (i = 0; i < mpoint->
ngeoms; i++)
2422 if (pip_result != -1)
2434 elog(ERROR,
"Type isn't point or multipoint!");
2438 PG_RETURN_BOOL(retval);
2446 if ( prep_cache->
gcache.argnum == 1 )
2451 GEOSGeom_destroy(g);
2459 GEOSGeom_destroy(g);
2467 if (!g1)
HANDLE_GEOS_ERROR(
"First argument geometry could not be converted to GEOS");
2471 GEOSGeom_destroy(g1);
2474 result = GEOSIntersects( g1, g2);
2475 GEOSGeom_destroy(g1);
2476 GEOSGeom_destroy(g2);
2490 GEOSGeometry *g1, *g2;
2494 geom1 = PG_GETARG_GSERIALIZED_P(0);
2495 geom2 = PG_GETARG_GSERIALIZED_P(1);
2500 PG_RETURN_BOOL(
false);
2511 PG_RETURN_BOOL(
false);
2524 GEOSGeom_destroy(g1);
2528 result = GEOSTouches(g1,g2);
2530 GEOSGeom_destroy(g1);
2531 GEOSGeom_destroy(g2);
2535 PG_FREE_IF_COPY(geom1, 0);
2536 PG_FREE_IF_COPY(geom2, 1);
2547 GEOSGeometry *g1, *g2;
2551 geom1 = PG_GETARG_GSERIALIZED_P(0);
2552 geom2 = PG_GETARG_GSERIALIZED_P(1);
2557 PG_RETURN_BOOL(
true);
2568 PG_RETURN_BOOL(
true);
2581 GEOSGeom_destroy(g1);
2585 result = GEOSDisjoint(g1,g2);
2587 GEOSGeom_destroy(g1);
2588 GEOSGeom_destroy(g2);
2592 PG_FREE_IF_COPY(geom1, 0);
2593 PG_FREE_IF_COPY(geom2, 1);
2606 GEOSGeometry *g1, *g2;
2609 geom1 = PG_GETARG_GSERIALIZED_P(0);
2610 geom2 = PG_GETARG_GSERIALIZED_P(1);
2623 GEOSGeom_destroy(g1);
2627 patt = DatumGetCString(DirectFunctionCall1(textout, PG_GETARG_DATUM(2)));
2632 for ( i = 0; i < strlen(patt); i++ )
2634 if ( patt[i] ==
't' ) patt[i] =
'T';
2635 if ( patt[i] ==
'f' ) patt[i] =
'F';
2638 result = GEOSRelatePattern(g1,g2,patt);
2639 GEOSGeom_destroy(g1);
2640 GEOSGeom_destroy(g2);
2645 PG_FREE_IF_COPY(geom1, 0);
2646 PG_FREE_IF_COPY(geom2, 1);
2658 GEOSGeometry *g1, *g2;
2661 int bnr = GEOSRELATE_BNR_OGC;
2664 geom1 = PG_GETARG_GSERIALIZED_P(0);
2665 geom2 = PG_GETARG_GSERIALIZED_P(1);
2668 if ( PG_NARGS() > 2 )
2669 bnr = PG_GETARG_INT32(2);
2679 GEOSGeom_destroy(g1);
2683 POSTGIS_DEBUG(3,
"constructed geometries ");
2685 POSTGIS_DEBUGF(3,
"%s", GEOSGeomToWKT(g1));
2686 POSTGIS_DEBUGF(3,
"%s", GEOSGeomToWKT(g2));
2688 relate_str = GEOSRelateBoundaryNodeRule(g1, g2, bnr);
2690 GEOSGeom_destroy(g1);
2691 GEOSGeom_destroy(g2);
2695 result = cstring_to_text(relate_str);
2696 GEOSFree(relate_str);
2698 PG_FREE_IF_COPY(geom1, 0);
2699 PG_FREE_IF_COPY(geom2, 1);
2701 PG_RETURN_TEXT_P(
result);
2710 GEOSGeometry *g1, *g2;
2714 geom1 = PG_GETARG_GSERIALIZED_P(0);
2715 geom2 = PG_GETARG_GSERIALIZED_P(1);
2720 PG_RETURN_BOOL(
true);
2731 PG_RETURN_BOOL(
false);
2739 if (VARSIZE(geom1) == VARSIZE(geom2) && !memcmp(geom1, geom2, VARSIZE(geom1))) {
2740 PG_RETURN_BOOL(
true);
2754 GEOSGeom_destroy(g1);
2758 result = GEOSEquals(g1,g2);
2760 GEOSGeom_destroy(g1);
2761 GEOSGeom_destroy(g2);
2765 PG_FREE_IF_COPY(geom1, 0);
2766 PG_FREE_IF_COPY(geom2, 1);
2778 POSTGIS_DEBUG(2,
"issimple called");
2780 geom = PG_GETARG_GSERIALIZED_P(0);
2783 PG_RETURN_BOOL(
true);
2788 PG_FREE_IF_COPY(geom, 0);
2804 geom = PG_GETARG_GSERIALIZED_P(0);
2808 PG_RETURN_BOOL(
false);
2816 if ( GEOSGeomTypeId(g1) != GEOS_LINESTRING )
2818 GEOSGeom_destroy(g1);
2819 elog(ERROR,
"ST_IsRing() should only be called on a linear feature");
2823 GEOSGeom_destroy(g1);
2827 PG_FREE_IF_COPY(geom, 0);
2840 lwpgerror(
"%s: GEOS2LWGEOM returned NULL", __func__);
2844 POSTGIS_DEBUGF(4,
"%s: GEOS2LWGEOM returned a %s", __func__,
lwgeom_summary(lwgeom, 0));
2848 result = geometry_serialize(lwgeom);
2863 lwpgerror(
"POSTGIS2GEOS: unable to deserialize input");
2873 ArrayIterator iterator;
2876 uint32_t nelems_not_null = 0;
2877 iterator = array_create_iterator(array, 0, NULL);
2878 while(array_iterate(iterator, &
value, &isnull) )
2882 array_free_iterator(iterator);
2884 return nelems_not_null;
2890 ArrayIterator iterator;
2893 bool gotsrid =
false;
2898 iterator = array_create_iterator(array, 0, NULL);
2900 while (array_iterate(iterator, &
value, &isnull))
2912 lwpgerror(
"Geometry deserializing geometry");
2930 GEOSGeometry**
ARRAY2GEOS(ArrayType* array, uint32_t nelems,
int* is3d,
int* srid)
2932 ArrayIterator iterator;
2935 bool gotsrid =
false;
2938 GEOSGeometry** geos_geoms = palloc(nelems *
sizeof(GEOSGeometry*));
2940 iterator = array_create_iterator(array, 0, NULL);
2942 while(array_iterate(iterator, &
value, &isnull))
2955 lwpgerror(
"Geometry could not be converted to GEOS");
2957 for (j = 0; j < i; j++) {
2958 GEOSGeom_destroy(geos_geoms[j]);
2971 for (j = 0; j <= i; j++) {
2972 GEOSGeom_destroy(geos_geoms[j]);
2981 array_free_iterator(iterator);
2989 GEOSGeometry *geosgeom;
2994 geom = PG_GETARG_GSERIALIZED_P(0);
2996 if ( ! geosgeom ) PG_RETURN_NULL();
2999 GEOSGeom_destroy(geosgeom);
3001 PG_FREE_IF_COPY(geom, 0);
3003 PG_RETURN_POINTER(lwgeom_result);
3013 GEOSGeometry *geos_result;
3014 const GEOSGeometry **vgeoms;
3016 #if POSTGIS_DEBUG_LEVEL >= 3
3020 #if POSTGIS_DEBUG_LEVEL >= 3
3024 if (PG_ARGISNULL(0))
3027 array = PG_GETARG_ARRAYTYPE_P(0);
3033 POSTGIS_DEBUGF(3,
"polygonize_garray: number of non-null elements: %d", nelems);
3038 vgeoms = (
const GEOSGeometry**)
ARRAY2GEOS(array, nelems, &is3d, &srid);
3040 POSTGIS_DEBUG(3,
"polygonize_garray: invoking GEOSpolygonize");
3042 geos_result = GEOSPolygonize(vgeoms, nelems);
3044 POSTGIS_DEBUG(3,
"polygonize_garray: GEOSpolygonize returned");
3046 for (i=0; i<nelems; ++i) GEOSGeom_destroy((GEOSGeometry *)vgeoms[i]);
3049 if ( ! geos_result ) PG_RETURN_NULL();
3051 GEOSSetSRID(geos_result, srid);
3053 GEOSGeom_destroy(geos_result);
3056 elog(ERROR,
"%s returned an error", __func__);
3060 PG_RETURN_POINTER(
result);
3067 Datum* result_array_data;
3068 ArrayType *array, *
result;
3070 uint32 nelems, nclusters, i;
3071 GEOSGeometry **geos_inputs, **geos_results;
3080 if (PG_ARGISNULL(0))
3083 array = PG_GETARG_ARRAYTYPE_P(0);
3086 POSTGIS_DEBUGF(3,
"clusterintersecting_garray: number of non-null elements: %d", nelems);
3088 if ( nelems == 0 ) PG_RETURN_NULL();
3095 geos_inputs =
ARRAY2GEOS(array, nelems, &is3d, &srid);
3103 elog(ERROR,
"clusterintersecting: Error performing clustering");
3108 if (!geos_results) PG_RETURN_NULL();
3110 result_array_data = palloc(nclusters *
sizeof(Datum));
3111 for (i=0; i<nclusters; ++i)
3113 result_array_data[i] = PointerGetDatum(
GEOS2POSTGIS(geos_results[i], is3d));
3114 GEOSGeom_destroy(geos_results[i]);
3118 get_typlenbyvalalign(array->elemtype, &elmlen, &elmbyval, &elmalign);
3119 result = construct_array(result_array_data, nclusters, array->elemtype, elmlen, elmbyval, elmalign);
3123 elog(ERROR,
"clusterintersecting: Error constructing return-array");
3127 PG_RETURN_POINTER(
result);
3133 Datum* result_array_data;
3134 ArrayType *array, *
result;
3136 uint32 nelems, nclusters, i;
3148 if (PG_ARGISNULL(0))
3151 array = PG_GETARG_ARRAYTYPE_P(0);
3153 tolerance = PG_GETARG_FLOAT8(1);
3156 lwpgerror(
"Tolerance must be a positive number.");
3162 POSTGIS_DEBUGF(3,
"cluster_within_distance_garray: number of non-null elements: %d", nelems);
3164 if ( nelems == 0 ) PG_RETURN_NULL();
3179 elog(ERROR,
"cluster_within: Error performing clustering");
3184 if (!lw_results) PG_RETURN_NULL();
3186 result_array_data = palloc(nclusters *
sizeof(Datum));
3187 for (i=0; i<nclusters; ++i)
3189 result_array_data[i] = PointerGetDatum(geometry_serialize(lw_results[i]));
3194 get_typlenbyvalalign(array->elemtype, &elmlen, &elmbyval, &elmalign);
3195 result = construct_array(result_array_data, nclusters, array->elemtype, elmlen, elmbyval, elmalign);
3199 elog(ERROR,
"clusterwithin: Error constructing return-array");
3203 PG_RETURN_POINTER(
result);
3210 bool directed =
false;
3212 LWGEOM *lwgeom1, *lwresult ;
3214 geom1 = PG_GETARG_GSERIALIZED_P(0);
3216 if ( PG_NARGS() > 1 )
3217 directed = PG_GETARG_BOOL(1);
3222 result = geometry_serialize(lwresult) ;
3227 PG_FREE_IF_COPY(geom1, 0);
3229 PG_RETURN_POINTER(
result);
3244 LWGEOM *lwgeom_in, *lwgeom_out;
3246 geom = PG_GETARG_GSERIALIZED_P(0);
3254 PG_FREE_IF_COPY(geom, 0);
3258 result = geometry_serialize(lwgeom_out) ;
3261 PG_FREE_IF_COPY(geom, 0);
3262 PG_RETURN_POINTER(
result);
3274 LWGEOM *lwgeom_in, *lwgeom_out;
3275 double tolerance = 0.0;
3278 geom = PG_GETARG_GSERIALIZED_P(0);
3279 tolerance = PG_GETARG_FLOAT8(1);
3280 flags = PG_GETARG_INT32(2);
3288 PG_FREE_IF_COPY(geom, 0);
3292 result = geometry_serialize(lwgeom_out) ;
3295 PG_FREE_IF_COPY(geom, 0);
3296 PG_RETURN_POINTER(
result);
3307 #if POSTGIS_GEOS_VERSION < 31100
3309 lwpgerror(
"The GEOS version this PostGIS binary "
3310 "was compiled against (%d) doesn't support "
3311 "'GEOSConstrainedDelaunayTriangulation' function (3.11.0+ required)",
3324 PG_FREE_IF_COPY(geom, 0);
3328 result = geometry_serialize(lwgeom_out);
3331 PG_FREE_IF_COPY(geom, 0);
3332 PG_RETURN_POINTER(
result);
3341 Datum
ST_Snap(PG_FUNCTION_ARGS);
3346 LWGEOM *lwgeom1, *lwgeom2, *lwresult;
3349 geom1 = PG_GETARG_GSERIALIZED_P(0);
3350 geom2 = PG_GETARG_GSERIALIZED_P(1);
3351 tolerance = PG_GETARG_FLOAT8(2);
3356 lwresult =
lwgeom_snap(lwgeom1, lwgeom2, tolerance);
3359 PG_FREE_IF_COPY(geom1, 0);
3360 PG_FREE_IF_COPY(geom2, 1);
3362 result = geometry_serialize(lwresult);
3365 PG_RETURN_POINTER(
result);
3397 LWGEOM *lwgeom_in, *lwblade_in, *lwgeom_out;
3399 in = PG_GETARG_GSERIALIZED_P(0);
3400 blade_in = PG_GETARG_GSERIALIZED_P(1);
3412 PG_FREE_IF_COPY(in, 0);
3413 PG_FREE_IF_COPY(blade_in, 1);
3417 out = geometry_serialize(lwgeom_out);
3419 PG_FREE_IF_COPY(in, 0);
3420 PG_FREE_IF_COPY(blade_in, 1);
3422 PG_RETURN_POINTER(out);
3445 LWGEOM *g1, *g2, *lwgeom_out;
3447 geom1 = PG_GETARG_GSERIALIZED_P(0);
3448 geom2 = PG_GETARG_GSERIALIZED_P(1);
3459 PG_FREE_IF_COPY(geom1, 0);
3460 PG_FREE_IF_COPY(geom2, 1);
3464 out = geometry_serialize(lwgeom_out);
3467 PG_FREE_IF_COPY(geom1, 0);
3468 PG_FREE_IF_COPY(geom2, 1);
3469 PG_RETURN_POINTER(out);
3481 Datum
ST_Node(PG_FUNCTION_ARGS);
3488 geom1 = PG_GETARG_GSERIALIZED_P(0);
3497 PG_FREE_IF_COPY(geom1, 0);
3501 out = geometry_serialize(lwgeom_out);
3504 PG_FREE_IF_COPY(geom1, 0);
3505 PG_RETURN_POINTER(out);
3527 int custom_clip_envelope;
3528 int return_polygons;
3531 if (PG_ARGISNULL(0))
3535 if (PG_ARGISNULL(2))
3537 lwpgerror(
"Tolerance must be a positive number.");
3541 tolerance = PG_GETARG_FLOAT8(2);
3545 lwpgerror(
"Tolerance must be a positive number.");
3550 if (PG_ARGISNULL(3))
3552 lwpgerror(
"return_polygons must be true or false.");
3555 return_polygons = PG_GETARG_BOOL(3);
3558 custom_clip_envelope = !PG_ARGISNULL(1);
3559 if (custom_clip_envelope) {
3560 clip = PG_GETARG_GSERIALIZED_P(1);
3563 lwpgerror(
"Could not determine envelope of clipping geometry.");
3564 PG_FREE_IF_COPY(clip, 1);
3567 PG_FREE_IF_COPY(clip, 1);
3571 input = PG_GETARG_GSERIALIZED_P(0);
3577 lwpgerror(
"Could not read input geometry.");
3578 PG_FREE_IF_COPY(input, 0);
3582 lwgeom_result =
lwgeom_voronoi_diagram(lwgeom_input, custom_clip_envelope ? &clip_envelope : NULL, tolerance, !return_polygons);
3587 lwpgerror(
"Error computing Voronoi diagram.");
3588 PG_FREE_IF_COPY(input, 0);
3592 result = geometry_serialize(lwgeom_result);
3595 PG_FREE_IF_COPY(input, 0);
3596 PG_RETURN_POINTER(
result);
3611 GEOSGeometry* input_geos;
3617 input = PG_GETARG_GSERIALIZED_P(0);
3622 error = GEOSMinimumClearance(input_geos, &
result);
3623 GEOSGeom_destroy(input_geos);
3626 PG_FREE_IF_COPY(input, 0);
3627 PG_RETURN_FLOAT8(
result);
3643 GEOSGeometry* input_geos;
3644 GEOSGeometry* result_geos;
3649 input = PG_GETARG_GSERIALIZED_P(0);
3655 result_geos = GEOSMinimumClearanceLine(input_geos);
3656 GEOSGeom_destroy(input_geos);
3660 GEOSSetSRID(result_geos, srid);
3662 GEOSGeom_destroy(result_geos);
3664 PG_FREE_IF_COPY(input, 0);
3665 PG_RETURN_POINTER(
result);
3679 GEOSGeometry* input_geos;
3680 GEOSGeometry* result_geos;
3685 input = PG_GETARG_GSERIALIZED_P(0);
3691 result_geos = GEOSMinimumRotatedRectangle(input_geos);
3692 GEOSGeom_destroy(input_geos);
3696 GEOSSetSRID(result_geos, srid);
3698 GEOSGeom_destroy(result_geos);
3700 PG_FREE_IF_COPY(input, 0);
3701 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_concavehull(const LWGEOM *geom, double ratio, uint32_t allow_holes)
Take a geometry and build the concave hull.
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_simplify_polygonal(const LWGEOM *geom, double vertex_fraction, uint32_t is_outer)
Computes a boundary-respecting hull of a polygonal geometry, with hull shape determined by a target p...
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)
const char * lwgeom_geos_compiled_version(void)
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_triangulate_polygon(const LWGEOM *geom)
Take vertices of a polygon and build a constrained triangulation that respects the boundary of the po...
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 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)
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 postgis_geos_compiled_version(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 ST_LargestEmptyCircle(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 HANDLE_GEOS_ERROR(label)
#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()