PostGIS  3.3.9dev-r@@SVN_REVISION@@

◆ union_dbscan_general()

static int union_dbscan_general ( LWGEOM **  geoms,
uint32_t  num_geoms,
UNIONFIND uf,
double  eps,
uint32_t  min_points,
char **  in_a_cluster_ret 
)
static

Definition at line 391 of file lwgeom_geos_cluster.c.

392 {
393  uint32_t p, i;
394  struct STRTree tree;
395  struct QueryContext cxt =
396  {
397  .items_found = NULL,
398  .num_items_found = 0,
399  .items_found_size = 0
400  };
401  int success = LW_SUCCESS;
402  uint32_t* neighbors;
403  char* in_a_cluster;
404  char* is_in_core;
405 
406  in_a_cluster = lwalloc(num_geoms * sizeof(char));
407  memset(in_a_cluster, 0, num_geoms * sizeof(char));
408 
409  if (in_a_cluster_ret)
410  *in_a_cluster_ret = in_a_cluster;
411 
412  /* Bail if we don't even have enough inputs to make a cluster. */
413  if (num_geoms < min_points)
414  {
415  if (!in_a_cluster_ret)
416  lwfree(in_a_cluster);
417  return LW_SUCCESS;
418  }
419 
420  tree = make_strtree((void**) geoms, num_geoms, LW_TRUE);
421  if (tree.tree == NULL)
422  {
423  destroy_strtree(&tree);
424  return LW_FAILURE;
425  }
426 
427  is_in_core = lwalloc(num_geoms * sizeof(char));
428  memset(is_in_core, 0, num_geoms * sizeof(char));
429  neighbors = lwalloc(min_points * sizeof(uint32_t));
430 
431  for (p = 0; p < num_geoms; p++)
432  {
433  uint32_t num_neighbors = 0;
434  int rv;
435 
436  if (lwgeom_is_empty(geoms[p]))
437  continue;
438 
439  rv = dbscan_update_context(tree.tree, &cxt, geoms, p, eps);
440  if (rv == LW_FAILURE)
441  {
442  destroy_strtree(&tree);
443  return LW_FAILURE;
444  }
445 
446  /* We didn't find enough points to do anything, even if they are all within eps. */
447  if (cxt.num_items_found < min_points)
448  continue;
449 
450  for (i = 0; i < cxt.num_items_found; i++)
451  {
452  uint32_t q = *((uint32_t*) cxt.items_found[i]);
453 
454  if (num_neighbors >= min_points)
455  {
456  /* If we've already identified p as a core point, and it's already
457  * in the same cluster in q, then there's nothing to learn by
458  * computing the distance.
459  */
460  if (UF_find(uf, p) == UF_find(uf, q))
461  continue;
462 
463  /* Similarly, if q is already identifed as a border point of another
464  * cluster, there's no point figuring out what the distance is.
465  */
466  if (in_a_cluster[q] && !is_in_core[q])
467  continue;
468  }
469 
470  double mindist = lwgeom_mindistance2d_tolerance(geoms[p], geoms[q], eps);
471  if (mindist == FLT_MAX)
472  {
473  success = LW_FAILURE;
474  break;
475  }
476 
477  if (mindist <= eps)
478  {
479  /* If we haven't hit min_points yet, we don't know if we can union p and q.
480  * Just set q aside for now.
481  */
482  if (num_neighbors < min_points)
483  {
484  neighbors[num_neighbors++] = q;
485 
486  /* If we just hit min_points, we can now union all of the neighbor geometries
487  * we've been saving.
488  */
489  if (num_neighbors == min_points)
490  {
491  uint32_t j;
492  is_in_core[p] = LW_TRUE;
493  in_a_cluster[p] = LW_TRUE;
494  for (j = 0; j < num_neighbors; j++)
495  {
496  union_if_available(uf, p, neighbors[j], is_in_core, in_a_cluster);
497  }
498  }
499  }
500  else
501  {
502  /* If we're above min_points, no need to store our neighbors, just go ahead
503  * and union them now. This may allow us to cut out some distance
504  * computations.
505  */
506  union_if_available(uf, p, q, is_in_core, in_a_cluster);
507  }
508  }
509  }
510 
511  if (!success)
512  break;
513  }
514 
515  lwfree(neighbors);
516  lwfree(is_in_core);
517 
518  /* Free in_a_cluster if we're not giving it to our caller */
519  if (!in_a_cluster_ret)
520  lwfree(in_a_cluster);
521 
522  if (cxt.items_found)
523  lwfree(cxt.items_found);
524 
525  destroy_strtree(&tree);
526  return success;
527 }
#define LW_FAILURE
Definition: liblwgeom.h:111
#define LW_SUCCESS
Definition: liblwgeom.h:112
void lwfree(void *mem)
Definition: lwutil.c:242
double lwgeom_mindistance2d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling min distance calculations and dwithin calculations.
Definition: measures.c:210
void * lwalloc(size_t size)
Definition: lwutil.c:227
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:108
static int dbscan_update_context(GEOSSTRtree *tree, struct QueryContext *cxt, LWGEOM **geoms, uint32_t p, double eps)
static struct STRTree make_strtree(void **geoms, uint32_t num_geoms, char is_lwgeom)
Make a GEOSSTRtree that stores a pointer to a variable containing the array index of the input geoms.
static void destroy_strtree(struct STRTree *tree)
Clean up STRTree after use.
static void union_if_available(UNIONFIND *uf, uint32_t p, uint32_t q, char *is_in_core, char *in_a_cluster)
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
Definition: lwinline.h:203
uint32_t UF_find(UNIONFIND *uf, uint32_t i)
Definition: lwunionfind.c:62
uint32_t num_items_found
GEOSSTRtree * tree

References dbscan_update_context(), destroy_strtree(), QueryContext::items_found, LW_FAILURE, LW_SUCCESS, LW_TRUE, lwalloc(), lwfree(), lwgeom_is_empty(), lwgeom_mindistance2d_tolerance(), make_strtree(), QueryContext::num_items_found, STRTree::tree, UF_find(), and union_if_available().

Referenced by union_dbscan().

Here is the call graph for this function:
Here is the caller graph for this function: