Take a list of LWGEOMs and a number of clusters and return an integer array indicating which cluster each geometry is in.
322{
323 uint32_t num_non_empty = 0;
324
325 assert(k > 0);
326 assert(n > 0);
327 assert(max_radius >= 0);
328 assert(geoms);
329
330 if (n < k)
331 {
333 "%s: number of geometries is less than the number of clusters requested, not all clusters will get data",
334 __func__);
335 k = n;
336 }
337
338
340
341
342 uint8_t *geom_valid =
lwalloc(
sizeof(uint8_t) * n);
343 memset(geom_valid, 0, sizeof(uint8_t) * n);
344
345
346 int *clusters =
lwalloc(
sizeof(
int) * n);
347 for (uint32_t i = 0; i < n; i++)
349
350
352 memset(centers, 0,
sizeof(
POINT4D) * n);
353
354
355 double *radii =
lwalloc(
sizeof(
double) * n);
356 memset(radii, 0, sizeof(double) * n);
357
358
359 for (uint32_t i = 0; i < n; i++)
360 {
361 const LWGEOM *geom = geoms[i];
362
364
365
367 continue;
368
369
371 {
377 {
380 lwerror(
"%s has an input point geometry with weight in M less or equal to 0",
381 __func__);
382 }
383 }
385 {
386
389 continue;
391 {
393 continue;
394 }
398 }
399 else
400 {
401
404 continue;
408 }
410 objs_dense[num_non_empty++] = out;
411 }
412
413 if (num_non_empty < k)
414 {
416 "%s: number of non-empty geometries (%d) is less than the number of clusters (%d) requested, not all clusters will get data",
417 __func__,
418 num_non_empty,
419 k);
420 k = num_non_empty;
421 }
422
424
425 if (num_non_empty > 0)
426 {
427 uint32_t *clusters_dense =
lwalloc(
sizeof(uint32_t) * num_non_empty);
428 memset(clusters_dense, 0, sizeof(uint32_t) * num_non_empty);
429 uint32_t output_cluster_count =
kmeans(objs_dense, clusters_dense, num_non_empty, centers, radii, k, max_radius);
430
431 uint32_t d = 0;
432 for (uint32_t i = 0; i < n; i++)
433 if (geom_valid[i])
434 clusters[i] = (int)clusters_dense[d++];
435
436 converged = output_cluster_count > 0;
438 }
439
440
445
446
447 if (converged)
448 return clusters;
449
450
452 return NULL;
453}
int gbox_is_valid(const GBOX *gbox)
Return false if any of the dimensions is NaN or infinite.
double lwpoint_get_m(const LWPOINT *point)
void lwgeom_free(LWGEOM *geom)
LWGEOM * lwgeom_centroid(const LWGEOM *geom)
double lwpoint_get_x(const LWPOINT *point)
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
void * lwalloc(size_t size)
double lwpoint_get_z(const LWPOINT *point)
#define LW_TRUE
Return types for functions with status returns.
const GBOX * lwgeom_get_bbox(const LWGEOM *lwgeom)
Get a non-empty geometry bounding box, computing and caching it if not already there.
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
double lwpoint_get_y(const LWPOINT *point)
void lwnotice(const char *fmt,...) __attribute__((format(printf
Write a notice out to the notice handler.
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
static uint32_t lwgeom_get_type(const LWGEOM *geom)
Return LWTYPE number.
static LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
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 uint32_t kmeans(POINT4D *objs, uint32_t *clusters, uint32_t n, POINT4D *centers, double *radii, uint32_t min_k, double max_radius)
#define KMEANS_NULL_CLUSTER
Datum centroid(PG_FUNCTION_ARGS)