PostGIS  3.4.0dev-r@@SVN_REVISION@@

◆ ST_ClusterKMeans()

Datum ST_ClusterKMeans ( PG_FUNCTION_ARGS  )

Definition at line 354 of file lwgeom_window.c.

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

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: