PostGIS  3.4.0dev-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 390 of file lwgeom_geos_cluster.c.

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