PostGIS  3.2.2dev-r@@SVN_REVISION@@

◆ pgis_union_geometry_array()

Datum pgis_union_geometry_array ( PG_FUNCTION_ARGS  )

Definition at line 475 of file postgis/lwgeom_geos.c.

476 {
477  ArrayType *array;
478 
479  ArrayIterator iterator;
480  Datum value;
481  bool isnull;
482 
483  int is3d = LW_FALSE, gotsrid = LW_FALSE;
484  int nelems = 0, geoms_size = 0, curgeom = 0, count = 0;
485 
486  GSERIALIZED *gser_out = NULL;
487 
488  GEOSGeometry *g = NULL;
489  GEOSGeometry *g_union = NULL;
490  GEOSGeometry **geoms = NULL;
491 
492  int32_t srid = SRID_UNKNOWN;
493 
494  int empty_type = 0;
495 
496  /* Null array, null geometry (should be empty?) */
497  if ( PG_ARGISNULL(0) )
498  PG_RETURN_NULL();
499 
500  array = PG_GETARG_ARRAYTYPE_P(0);
501  nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
502 
503  /* Empty array? Null return */
504  if ( nelems == 0 ) PG_RETURN_NULL();
505 
506  /* Quick scan for nulls */
507  iterator = array_create_iterator(array, 0, NULL);
508  while (array_iterate(iterator, &value, &isnull))
509  {
510  /* Skip null array items */
511  if (isnull) continue;
512  count++;
513  }
514  array_free_iterator(iterator);
515 
516 
517  /* All-nulls? Return null */
518  if ( count == 0 )
519  PG_RETURN_NULL();
520 
521  /* Ok, we really need GEOS now ;) */
522  initGEOS(lwpgnotice, lwgeom_geos_error);
523 
524  /* One geom, good geom? Return it */
525  if ( count == 1 && nelems == 1 )
526  {
527 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
528 #pragma GCC diagnostic push
529 #pragma GCC diagnostic ignored "-Wsign-compare"
530 #endif
531  g = POSTGIS2GEOS((GSERIALIZED *)(ARR_DATA_PTR(array)));
532 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
533 #pragma GCC diagnostic pop
534 #endif
535  g_union = GEOSUnaryUnion(g);
536  GEOSGeom_destroy(g);
537  if (!g_union) HANDLE_GEOS_ERROR("GEOSUnaryUnion");
538  GEOSSetSRID(g_union, srid);
539  gser_out = GEOS2POSTGIS(g_union, is3d);
540  GEOSGeom_destroy(g_union);
541  PG_RETURN_POINTER(gser_out);
542  }
543 
544  /*
545  ** Collect the non-empty inputs and stuff them into a GEOS collection
546  */
547  geoms_size = nelems;
548  geoms = palloc(sizeof(GEOSGeometry*) * geoms_size);
549 
550  /*
551  ** We need to convert the array of GSERIALIZED into a GEOS collection.
552  ** First make an array of GEOS geometries.
553  */
554  iterator = array_create_iterator(array, 0, NULL);
555  while (array_iterate(iterator, &value, &isnull))
556  {
557  GSERIALIZED *gser_in;
558 
559  /* Skip null array items */
560  if (isnull) continue;
561  gser_in = (GSERIALIZED *)DatumGetPointer(value);
562 
563  /* Check for SRID mismatch in array elements */
564  if ( gotsrid )
565  gserialized_error_if_srid_mismatch_reference(gser_in, srid, __func__);
566  else
567  {
568  /* Initialize SRID/dimensions info */
569  srid = gserialized_get_srid(gser_in);
570  is3d = gserialized_has_z(gser_in);
571  gotsrid = 1;
572  }
573 
574  /* Don't include empties in the union */
575  if ( gserialized_is_empty(gser_in) )
576  {
577  int gser_type = gserialized_get_type(gser_in);
578  if (gser_type > empty_type)
579  {
580  empty_type = gser_type;
581  POSTGIS_DEBUGF(4, "empty_type = %d gser_type = %d", empty_type, gser_type);
582  }
583  }
584  else
585  {
586  g = POSTGIS2GEOS(gser_in);
587 
588  /* Uh oh! Exception thrown at construction... */
589  if ( ! g )
590  {
592  "One of the geometries in the set "
593  "could not be converted to GEOS");
594  }
595 
596  /* Ensure we have enough space in our storage array */
597  if ( curgeom == geoms_size )
598  {
599  geoms_size *= 2;
600  geoms = repalloc( geoms, sizeof(GEOSGeometry*) * geoms_size );
601  }
602 
603  geoms[curgeom] = g;
604  curgeom++;
605  }
606 
607  }
608  array_free_iterator(iterator);
609 
610  /*
611  ** Take our GEOS geometries and turn them into a GEOS collection,
612  ** then pass that into cascaded union.
613  */
614  if (curgeom > 0)
615  {
616  g = GEOSGeom_createCollection(GEOS_GEOMETRYCOLLECTION, geoms, curgeom);
617  if (!g) HANDLE_GEOS_ERROR("Could not create GEOS COLLECTION from geometry array");
618 
619  g_union = GEOSUnaryUnion(g);
620  GEOSGeom_destroy(g);
621  if (!g_union) HANDLE_GEOS_ERROR("GEOSUnaryUnion");
622 
623  GEOSSetSRID(g_union, srid);
624  gser_out = GEOS2POSTGIS(g_union, is3d);
625  GEOSGeom_destroy(g_union);
626  }
627  /* No real geometries in our array, any empties? */
628  else
629  {
630  /* If it was only empties, we'll return the largest type number */
631  if ( empty_type > 0 )
632  {
633  PG_RETURN_POINTER(geometry_serialize(lwgeom_construct_empty(empty_type, srid, is3d, 0)));
634  }
635  /* Nothing but NULL, returns NULL */
636  else
637  {
638  PG_RETURN_NULL();
639  }
640  }
641 
642  if ( ! gser_out )
643  {
644  /* Union returned a NULL geometry */
645  PG_RETURN_NULL();
646  }
647 
648  PG_RETURN_POINTER(gser_out);
649 }
void gserialized_error_if_srid_mismatch_reference(const GSERIALIZED *g1, const int32_t srid2, const char *funcname)
Definition: gserialized.c:419
int32_t gserialized_get_srid(const GSERIALIZED *g)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
Definition: gserialized.c:126
int gserialized_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
Definition: gserialized.c:152
int gserialized_has_z(const GSERIALIZED *g)
Check if a GSERIALIZED has a Z ordinate.
Definition: gserialized.c:174
uint32_t gserialized_get_type(const GSERIALIZED *g)
Extract the geometry type from the serialized form (it hides in the anonymous data area,...
Definition: gserialized.c:89
void lwgeom_geos_error(const char *fmt,...)
#define LW_FALSE
Definition: liblwgeom.h:108
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:229
LWGEOM * lwgeom_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
Definition: lwgeom.c:2111
int value
Definition: genraster.py:62
int count
Definition: genraster.py:57
#define HANDLE_GEOS_ERROR(label)
GSERIALIZED * GEOS2POSTGIS(GEOSGeom geom, char want3d)
GEOSGeometry * POSTGIS2GEOS(const GSERIALIZED *pglwgeom)

References genraster::count, GEOS2POSTGIS(), gserialized_error_if_srid_mismatch_reference(), gserialized_get_srid(), gserialized_get_type(), gserialized_has_z(), gserialized_is_empty(), HANDLE_GEOS_ERROR, LW_FALSE, lwgeom_construct_empty(), lwgeom_geos_error(), POSTGIS2GEOS(), SRID_UNKNOWN, and genraster::value.

Here is the call graph for this function: