26 #include "../postgis_config.h"
31 #include "windowapi.h"
38 #include "lwgeom_pg.h"
66 cluster_context* context = WinGetPartitionLocalMemory(win_obj, context_sz);
74 Datum arg = WinGetFuncArgInPartition(win_obj, 0, i, WINDOW_SEEK_HEAD,
false, is_null, NULL);
94 Datum arg = WinGetFuncArgInPartition(win_obj, 0, i, WINDOW_SEEK_HEAD,
false, is_null, NULL);
121 WindowObject win_obj = PG_WINDOW_OBJECT();
122 uint32_t row = WinGetCurrentPosition(win_obj);
123 uint32_t ngeoms = WinGetPartitionRowCount(win_obj);
129 uint32_t* result_ids;
131 char* is_in_cluster = NULL;
133 bool tolerance_is_null;
134 bool minpoints_is_null;
135 Datum tolerance_datum = WinGetFuncArgCurrent(win_obj, 1, &tolerance_is_null);
136 Datum minpoints_datum = WinGetFuncArgCurrent(win_obj, 2, &minpoints_is_null);
137 double tolerance = DatumGetFloat8(tolerance_datum);
138 int minpoints = DatumGetInt32(minpoints_datum);
143 if (tolerance_is_null || tolerance < 0)
145 lwpgerror(
"Tolerance must be a positive number", tolerance);
148 if (minpoints_is_null || minpoints < 0)
150 lwpgerror(
"Minpoints must be a positive number", minpoints);
156 for (i = 0; i < ngeoms; i++)
164 lwpgerror(
"Error reading geometry.");
169 if (
union_dbscan(geoms, ngeoms, uf, tolerance, minpoints, minpoints > 1 ? &is_in_cluster : NULL) ==
LW_SUCCESS)
172 for (i = 0; i < ngeoms; i++)
183 lwpgerror(
"Error during clustering");
188 for (i = 0; i < ngeoms; i++)
190 if (minpoints > 1 && !is_in_cluster[i])
214 WindowObject win_obj = PG_WINDOW_OBJECT();
215 uint32_t row = WinGetCurrentPosition(win_obj);
216 uint32_t ngeoms = WinGetPartitionRowCount(win_obj);
222 uint32_t* result_ids;
225 bool tolerance_is_null;
226 double tolerance = DatumGetFloat8(WinGetFuncArgCurrent(win_obj, 1, &tolerance_is_null));
229 if (tolerance_is_null || tolerance < 0)
231 lwpgerror(
"Tolerance must be a positive number", tolerance);
239 for (i = 0; i < ngeoms; i++)
247 lwpgerror(
"Error reading geometry.");
257 for (i = 0; i < ngeoms; i++)
266 lwpgerror(
"Error during clustering");
271 for (i = 0; i < ngeoms; i++)
290 WindowObject win_obj = PG_WINDOW_OBJECT();
291 uint32_t row = WinGetCurrentPosition(win_obj);
292 uint32_t ngeoms = WinGetPartitionRowCount(win_obj);
298 uint32_t* result_ids;
299 GEOSGeometry** geoms =
lwalloc(ngeoms *
sizeof(GEOSGeometry*));
306 for (i = 0; i < ngeoms; i++)
314 lwpgerror(
"Error reading geometry.");
322 for (i = 0; i < ngeoms; i++)
324 GEOSGeom_destroy(geoms[i]);
331 lwpgerror(
"Error during clustering");
336 for (i = 0; i < ngeoms; i++)
356 WindowObject winobj = PG_WINDOW_OBJECT();
358 int64 curpos, rowcount;
360 rowcount = WinGetPartitionRowCount(winobj);
362 WinGetPartitionLocalMemory(winobj,
369 double max_radius = 0.0;
375 argdatum = WinGetFuncArgCurrent(winobj, 1, &isnull);
376 k = DatumGetInt32(argdatum);
377 if (isnull || k <= 0)
385 N = (int) WinGetPartitionRowCount(winobj);
394 argdatum = WinGetFuncArgCurrent(winobj, 2, &isnull);
397 max_radius = DatumGetFloat8(argdatum);
404 lwpgerror(
"K (%d) must be smaller than the number of rows in the group (%d)", k, N);
407 geoms = palloc(
sizeof(
LWGEOM*) * N);
408 for (i = 0; i < N; i++)
411 Datum arg = WinGetFuncArgInPartition(winobj, 0, i,
412 WINDOW_SEEK_HEAD,
false, &isnull, &isout);
429 for (i = 0; i < N; i++)
443 memcpy(context->
result,
r,
sizeof(
int) * N);
451 curpos = WinGetCurrentPosition(winobj);
452 PG_RETURN_INT32(context->
result[curpos]);
468 #if POSTGIS_GEOS_VERSION >= 30800
478 for (uint32 i = 0; i < ngeoms; i++)
481 GEOSGeom_destroy(geoms[i]);
486 #if POSTGIS_GEOS_VERSION >= 31200
524 int64 rowcount = WinGetPartitionRowCount(winobj);
526 GEOSGeometry** geoms;
527 uint32 i, ngeoms = 0, gtype;
530 geoms = palloc(rowcount *
sizeof(GEOSGeometry*));
531 for (i = 0; i < rowcount; i++)
535 bool isempty, ispolygonal;
539 d = WinGetFuncArgInPartition(winobj, 0, i,
540 WINDOW_SEEK_HEAD,
false, &isnull, &isout);
554 context->
idx[i] = -1;
564 if (isempty || !ispolygonal)
566 context->
idx[i] = -1;
574 context->
idx[i] = -1;
578 context->
idx[i] = ngeoms;
579 geoms[ngeoms] = geos;
589 geos = GEOSGeom_createCollection(
590 GEOS_GEOMETRYCOLLECTION,
629 WindowObject winobj = PG_WINDOW_OBJECT();
630 int64 curpos = WinGetCurrentPosition(winobj);
631 int64 rowcount = WinGetPartitionRowCount(winobj);
634 MemoryContext uppercontext = fcinfo->flinfo->fn_mcxt;
635 MemoryContext oldcontext;
642 double tolerance = 0.0;
643 bool simplifyBoundary =
true;
644 GEOSGeometry *output = NULL;
645 GEOSGeometry *input = NULL;
648 elog(ERROR,
"%s: Could not find upper context", __func__);
658 d = WinGetFuncArgCurrent(winobj, 1, &isnull);
660 tolerance = DatumGetFloat8(d);
666 d = WinGetFuncArgCurrent(winobj, 2, &isnull);
668 simplifyBoundary = DatumGetBool(d);
681 output = GEOSCoverageSimplifyVW(input, tolerance, !simplifyBoundary);
685 GEOSCoverageIsValid(input, tolerance, &output);
689 elog(ERROR,
"Unknown mode, never get here");
692 GEOSGeom_destroy(input);
699 oldcontext = MemoryContextSwitchTo(uppercontext);
701 MemoryContextSwitchTo(oldcontext);
702 GEOSGeom_destroy(output);
712 if (context->
idx[curpos] < 0)
725 oldcontext = MemoryContextSwitchTo(uppercontext);
735 MemoryContextSwitchTo(oldcontext);
739 if (curpos == rowcount - 1)
742 if (!
result) PG_RETURN_NULL();
744 PG_RETURN_POINTER(
result);
754 #if POSTGIS_GEOS_VERSION < 31200
756 lwpgerror(
"The GEOS version this PostGIS binary "
757 "was compiled against (%d) doesn't support "
758 "'GEOSCoverageSimplifyVW' function (3.12.0+ required)",
774 #if POSTGIS_GEOS_VERSION < 31200
776 lwpgerror(
"The GEOS version this PostGIS binary "
777 "was compiled against (%d) doesn't support "
778 "'GEOSCoverageIsValid' function (3.12.0+ required)",
798 #if POSTGIS_GEOS_VERSION < 30800
799 lwpgerror(
"The GEOS version this PostGIS binary "
800 "was compiled against (%d) doesn't support "
801 "'GEOSCoverageUnion' function (3.8.0+ required)",
812 GEOSGeometry **geoms = NULL;
813 GEOSGeometry *geos = NULL;
814 GEOSGeometry *geos_result = NULL;
817 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
818 uint32 nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
819 ArrayIterator iterator = array_create_iterator(array, 0, NULL);
826 geoms = palloc(
sizeof(GEOSGeometry *) * nelems);
830 while (array_iterate(iterator, &
value, &isnull))
834 if (isnull)
continue;
844 geoms[ngeoms++] = geos;
846 array_free_iterator(iterator);
851 geos = GEOSGeom_createCollection(
852 GEOS_GEOMETRYCOLLECTION,
861 geos_result = GEOSCoverageUnion(geos);
862 GEOSGeom_destroy(geos);
867 GEOSGeom_destroy(geos_result);
869 PG_RETURN_POINTER(
result);
char result[OUT_DOUBLE_BUFFER_SIZE]
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.
uint32_t gserialized_get_type(const GSERIALIZED *g)
Extract the geometry type from the serialized form (it hides in the anonymous data area,...
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, uint8_t autofix)
LWGEOM * GEOS2LWGEOM(const GEOSGeometry *geom, uint8_t want3d)
void lwgeom_geos_error(const char *fmt,...)
int union_intersecting_pairs(GEOSGeometry **geoms, uint32_t num_geoms, UNIONFIND *uf)
int union_dbscan(LWGEOM **geoms, uint32_t num_geoms, UNIONFIND *uf, double eps, uint32_t min_points, char **is_in_cluster_ret)
LWPOINT * lwpoint_construct_empty(int32_t srid, char hasz, char hasm)
void lwgeom_free(LWGEOM *geom)
LWGEOM * lwcollection_getsubgeom(LWCOLLECTION *col, int gnum)
int * lwgeom_cluster_kmeans(const LWGEOM **geoms, uint32_t n, uint32_t k, double max_radius)
Take a list of LWGEOMs and a number of clusters and return an integer array indicating which cluster ...
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
void lwcollection_free(LWCOLLECTION *col)
void * lwalloc(size_t size)
#define LW_TRUE
Return types for functions with status returns.
This library is the generic geometry handling section of PostGIS.
void lwnotice(const char *fmt,...)
Write a notice out to the notice handler.
Datum ST_CoverageInvalidEdges(PG_FUNCTION_ARGS)
Datum ST_ClusterWithinWin(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(ST_ClusterDBSCAN)
Datum ST_ClusterIntersectingWin(PG_FUNCTION_ARGS)
Datum ST_CoverageUnion(PG_FUNCTION_ARGS)
static GEOSGeometry * read_geos_from_partition(WindowObject win_obj, uint32_t i, bool *is_null)
static coverage_context * coverage_context_fetch(WindowObject winobj, int64 rowcount)
static GEOSGeometry * coverage_read_partition_into_collection(WindowObject winobj, coverage_context *context)
Datum ST_CoverageSimplify(PG_FUNCTION_ARGS)
static Datum coverage_window_calculation(PG_FUNCTION_ARGS, int mode)
Datum ST_ClusterKMeans(PG_FUNCTION_ARGS)
static cluster_context * fetch_cluster_context(WindowObject win_obj, uint32_t ngeoms)
static LWGEOM * read_lwgeom_from_partition(WindowObject win_obj, uint32_t i, bool *is_null)
Datum ST_ClusterDBSCAN(PG_FUNCTION_ARGS)
static void coverage_destroy_geoms(GEOSGeometry **geoms, uint32 ngeoms)
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
uint32_t * UF_get_collapsed_cluster_ids(UNIONFIND *uf, const char *is_in_cluster)
void UF_destroy(UNIONFIND *uf)
UNIONFIND * UF_create(uint32_t N)
GSERIALIZED * GEOS2POSTGIS(GEOSGeom geom, char want3d)
GEOSGeometry * POSTGIS2GEOS(const GSERIALIZED *pglwgeom)
#define HANDLE_GEOS_ERROR(label)
#define POSTGIS_GEOS_VERSION
cluster_entry clusters[1]