PostGIS  3.3.9dev-r@@SVN_REVISION@@

◆ ST_ClusterKMeans()

Datum ST_ClusterKMeans ( PG_FUNCTION_ARGS  )

Definition at line 173 of file lwgeom_window.c.

174 {
175  WindowObject winobj = PG_WINDOW_OBJECT();
176  kmeans_context *context;
177  int64 curpos, rowcount;
178 
179  rowcount = WinGetPartitionRowCount(winobj);
180  context = (kmeans_context *)
181  WinGetPartitionLocalMemory(winobj,
182  sizeof(kmeans_context) + sizeof(int) * rowcount);
183 
184  if (!context->isdone)
185  {
186  int i, k, N;
187  bool isnull, isout;
188  double max_radius = 0.0;
189  LWGEOM **geoms;
190  int *r;
191  Datum argdatum;
192 
193  /* What is K? If it's NULL or invalid, we can't procede */
194  argdatum = WinGetFuncArgCurrent(winobj, 1, &isnull);
195  k = DatumGetInt32(argdatum);
196  if (isnull || k <= 0)
197  {
198  context->isdone = true;
199  context->isnull = true;
200  PG_RETURN_NULL();
201  }
202 
203  /* We also need a non-zero N */
204  N = (int) WinGetPartitionRowCount(winobj);
205  if (N <= 0)
206  {
207  context->isdone = true;
208  context->isnull = true;
209  PG_RETURN_NULL();
210  }
211 
212  /* Maximum cluster radius. 0 if not set*/
213  argdatum = WinGetFuncArgCurrent(winobj, 2, &isnull);
214  if (!isnull)
215  {
216  max_radius = DatumGetFloat8(argdatum);
217  if (max_radius < 0)
218  max_radius = 0.0;
219  }
220 
221  /* Error out if N < K */
222  if (N<k)
223  lwpgerror("K (%d) must be smaller than the number of rows in the group (%d)", k, N);
224 
225  /* Read all the geometries from the partition window into a list */
226  geoms = palloc(sizeof(LWGEOM*) * N);
227  for (i = 0; i < N; i++)
228  {
229  GSERIALIZED *g;
230  Datum arg = WinGetFuncArgInPartition(winobj, 0, i,
231  WINDOW_SEEK_HEAD, false, &isnull, &isout);
232 
233  /* Null geometries are entered as NULL pointers */
234  if (isnull)
235  {
236  geoms[i] = NULL;
237  continue;
238  }
239 
240  g = (GSERIALIZED*)PG_DETOAST_DATUM_COPY(arg);
241  geoms[i] = lwgeom_from_gserialized(g);
242  }
243 
244  /* Calculate k-means on the list! */
245  r = lwgeom_cluster_kmeans((const LWGEOM **)geoms, N, k, max_radius);
246 
247  /* Clean up */
248  for (i = 0; i < N; i++)
249  if (geoms[i])
250  lwgeom_free(geoms[i]);
251 
252  pfree(geoms);
253 
254  if (!r)
255  {
256  context->isdone = true;
257  context->isnull = true;
258  PG_RETURN_NULL();
259  }
260 
261  /* Safe the result */
262  memcpy(context->result, r, sizeof(int) * N);
263  lwfree(r);
264  context->isdone = true;
265  }
266 
267  if (context->isnull)
268  PG_RETURN_NULL();
269 
270  curpos = WinGetCurrentPosition(winobj);
271  PG_RETURN_INT32(context->result[curpos]);
272 }
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: