PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches

◆ 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 identified 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 * lwalloc(size_t size)
Definition lwutil.c:227
void lwfree(void *mem)
Definition lwutil.c:248
double lwgeom_mindistance2d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling min distance calculations and dwithin calculations.
Definition measures.c:222
#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:199
uint32_t UF_find(UNIONFIND *uf, uint32_t i)
Definition lwunionfind.c:62
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: