PostGIS  3.3.9dev-r@@SVN_REVISION@@

◆ pgis_union_geometry_array()

Datum pgis_union_geometry_array ( PG_FUNCTION_ARGS  )

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

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