PostGIS  3.7.0dev-r@@SVN_REVISION@@

◆ ST_ClusterKMeans()

Datum ST_ClusterKMeans ( PG_FUNCTION_ARGS  )

Definition at line 355 of file lwgeom_window.c.

356 {
357  WindowObject winobj = PG_WINDOW_OBJECT();
358  kmeans_context *context;
359  int64 curpos, rowcount;
360 
361  rowcount = WinGetPartitionRowCount(winobj);
362  context = (kmeans_context *)
363  WinGetPartitionLocalMemory(winobj,
364  sizeof(kmeans_context) + sizeof(int) * rowcount);
365 
366  if (!context->isdone)
367  {
368  int i, k, N;
369  bool isnull, isout;
370  double max_radius = 0.0;
371  LWGEOM **geoms;
372  int *r;
373  Datum argdatum;
374 
375  /* What is K? If it's NULL or invalid, we can't proceed */
376  argdatum = WinGetFuncArgCurrent(winobj, 1, &isnull);
377  k = DatumGetInt32(argdatum);
378  if (isnull || k <= 0)
379  {
380  context->isdone = true;
381  context->isnull = true;
382  PG_RETURN_NULL();
383  }
384 
385  /* We also need a non-zero N */
386  N = (int) WinGetPartitionRowCount(winobj);
387  if (N <= 0)
388  {
389  context->isdone = true;
390  context->isnull = true;
391  PG_RETURN_NULL();
392  }
393 
394  /* Maximum cluster radius. 0 if not set*/
395  argdatum = WinGetFuncArgCurrent(winobj, 2, &isnull);
396  if (!isnull)
397  {
398  max_radius = DatumGetFloat8(argdatum);
399  if (max_radius < 0)
400  max_radius = 0.0;
401  }
402 
403  /* Error out if N < K */
404  if (N<k)
405  lwpgerror("K (%d) must be smaller than the number of rows in the group (%d)", k, N);
406 
407  /* Read all the geometries from the partition window into a list */
408  geoms = palloc(sizeof(LWGEOM*) * N);
409  for (i = 0; i < N; i++)
410  {
411  GSERIALIZED *g;
412  Datum arg = WinGetFuncArgInPartition(winobj, 0, i,
413  WINDOW_SEEK_HEAD, false, &isnull, &isout);
414 
415  /* Null geometries are entered as NULL pointers */
416  if (isnull)
417  {
418  geoms[i] = NULL;
419  continue;
420  }
421 
422  g = (GSERIALIZED*)PG_DETOAST_DATUM_COPY(arg);
423  geoms[i] = lwgeom_from_gserialized(g);
424  }
425 
426  /* Calculate k-means on the list! */
427  r = lwgeom_cluster_kmeans((const LWGEOM **)geoms, N, k, max_radius);
428 
429  /* Clean up */
430  for (i = 0; i < N; i++)
431  if (geoms[i])
432  lwgeom_free(geoms[i]);
433 
434  pfree(geoms);
435 
436  if (!r)
437  {
438  context->isdone = true;
439  context->isnull = true;
440  PG_RETURN_NULL();
441  }
442 
443  /* Safe the result */
444  memcpy(context->result, r, sizeof(int) * N);
445  lwfree(r);
446  context->isdone = true;
447  }
448 
449  if (context->isnull)
450  PG_RETURN_NULL();
451 
452  curpos = WinGetCurrentPosition(winobj);
453  PG_RETURN_INT32(context->result[curpos]);
454 }
char * r
Definition: cu_in_wkt.c:24
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
Definition: gserialized.c:268
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1218
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 ...
Definition: lwkmeans.c:321
void lwfree(void *mem)
Definition: lwutil.c:248

References kmeans_context::isdone, kmeans_context::isnull, lwfree(), lwgeom_cluster_kmeans(), lwgeom_free(), lwgeom_from_gserialized(), r, and kmeans_context::result.

Here is the call graph for this function: