PostGIS  3.7.0dev-r@@SVN_REVISION@@

◆ pgis_union_geometry_array()

Datum pgis_union_geometry_array ( PG_FUNCTION_ARGS  )

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

528 {
529  ArrayType *array;
530 
531  ArrayIterator iterator;
532  Datum value;
533  bool isnull;
534 
535  int is3d = LW_FALSE, gotsrid = LW_FALSE;
536  int nelems = 0, geoms_size = 0, curgeom = 0, count = 0;
537 
538  GSERIALIZED *gser_out = NULL;
539 
540  GEOSGeometry *g = NULL;
541  GEOSGeometry *g_union = NULL;
542  GEOSGeometry **geoms = NULL;
543 
544  int32_t srid = SRID_UNKNOWN;
545 
546  int empty_type = 0;
547 
548  /* Null array, null geometry (should be empty?) */
549  if ( PG_ARGISNULL(0) )
550  PG_RETURN_NULL();
551 
552  array = PG_GETARG_ARRAYTYPE_P(0);
553  nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
554 
555  /* Empty array? Null return */
556  if ( nelems == 0 ) PG_RETURN_NULL();
557 
558  /* Quick scan for nulls */
559  iterator = array_create_iterator(array, 0, NULL);
560  while (array_iterate(iterator, &value, &isnull))
561  {
562  /* Skip null array items */
563  if (isnull) continue;
564  count++;
565  }
566  array_free_iterator(iterator);
567 
568 
569  /* All-nulls? Return null */
570  if ( count == 0 )
571  PG_RETURN_NULL();
572 
573  /* Ok, we really need GEOS now ;) */
574  initGEOS(lwpgnotice, lwgeom_geos_error);
575 
576  /* One geom, good geom? Return it */
577  if ( count == 1 && nelems == 1 )
578  {
579 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
580 #pragma GCC diagnostic push
581 #pragma GCC diagnostic ignored "-Wsign-compare"
582 #endif
583  g = POSTGIS2GEOS((GSERIALIZED *)(ARR_DATA_PTR(array)));
584 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
585 #pragma GCC diagnostic pop
586 #endif
587  srid = GEOSGetSRID(g);
588  g_union = GEOSUnaryUnion(g);
589  GEOSGeom_destroy(g);
590  if (!g_union) HANDLE_GEOS_ERROR("GEOSUnaryUnion");
591  GEOSSetSRID(g_union, srid);
592  gser_out = GEOS2POSTGIS(g_union, is3d);
593  GEOSGeom_destroy(g_union);
594  PG_RETURN_POINTER(gser_out);
595  }
596 
597  /*
598  ** Collect the non-empty inputs and stuff them into a GEOS collection
599  */
600  geoms_size = nelems;
601  geoms = palloc(sizeof(GEOSGeometry*) * geoms_size);
602 
603  /*
604  ** We need to convert the array of GSERIALIZED into a GEOS collection.
605  ** First make an array of GEOS geometries.
606  */
607  iterator = array_create_iterator(array, 0, NULL);
608  while (array_iterate(iterator, &value, &isnull))
609  {
610  GSERIALIZED *gser_in;
611 
612  /* Skip null array items */
613  if (isnull) continue;
614  gser_in = (GSERIALIZED *)DatumGetPointer(value);
615 
616  /* Check for SRID mismatch in array elements */
617  if ( gotsrid )
618  gserialized_error_if_srid_mismatch_reference(gser_in, srid, __func__);
619  else
620  {
621  /* Initialize SRID/dimensions info */
622  srid = gserialized_get_srid(gser_in);
623  is3d = gserialized_has_z(gser_in);
624  gotsrid = 1;
625  }
626 
627  /* Don't include empties in the union */
628  if ( gserialized_is_empty(gser_in) )
629  {
630  int gser_type = gserialized_get_type(gser_in);
631  if (gser_type > empty_type)
632  {
633  empty_type = gser_type;
634  POSTGIS_DEBUGF(4, "empty_type = %d gser_type = %d", empty_type, gser_type);
635  }
636  }
637  else
638  {
639  g = POSTGIS2GEOS(gser_in);
640 
641  /* Uh oh! Exception thrown at construction... */
642  if ( ! g )
643  {
645  "One of the geometries in the set "
646  "could not be converted to GEOS");
647  }
648 
649  /* Ensure we have enough space in our storage array */
650  if ( curgeom == geoms_size )
651  {
652  geoms_size *= 2;
653  geoms = repalloc( geoms, sizeof(GEOSGeometry*) * geoms_size );
654  }
655 
656  geoms[curgeom] = g;
657  curgeom++;
658  }
659 
660  }
661  array_free_iterator(iterator);
662 
663  /*
664  ** Take our GEOS geometries and turn them into a GEOS collection,
665  ** then pass that into cascaded union.
666  */
667  if (curgeom > 0)
668  {
669  g = GEOSGeom_createCollection(GEOS_GEOMETRYCOLLECTION, geoms, curgeom);
670  if (!g) HANDLE_GEOS_ERROR("Could not create GEOS COLLECTION from geometry array");
671 
672  g_union = GEOSUnaryUnion(g);
673  GEOSGeom_destroy(g);
674  if (!g_union) HANDLE_GEOS_ERROR("GEOSUnaryUnion");
675 
676  GEOSSetSRID(g_union, srid);
677  gser_out = GEOS2POSTGIS(g_union, is3d);
678  GEOSGeom_destroy(g_union);
679  }
680  /* No real geometries in our array, any empties? */
681  else
682  {
683  /* If it was only empties, we'll return the largest type number */
684  if ( empty_type > 0 )
685  {
686  PG_RETURN_POINTER(geometry_serialize(lwgeom_construct_empty(empty_type, srid, is3d, 0)));
687  }
688  /* Nothing but NULL, returns NULL */
689  else
690  {
691  PG_RETURN_NULL();
692  }
693  }
694 
695  if ( ! gser_out )
696  {
697  /* Union returned a NULL geometry */
698  PG_RETURN_NULL();
699  }
700 
701  PG_RETURN_POINTER(gser_out);
702 }
void gserialized_error_if_srid_mismatch_reference(const GSERIALIZED *g1, const int32_t srid2, const char *funcname)
Definition: gserialized.c:447
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:155
int gserialized_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
Definition: gserialized.c:181
int gserialized_has_z(const GSERIALIZED *g)
Check if a GSERIALIZED has a Z ordinate.
Definition: gserialized.c:203
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:118
void lwgeom_geos_error(const char *fmt,...)
#define LW_FALSE
Definition: liblwgeom.h:94
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:215
LWGEOM * lwgeom_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
Definition: lwgeom.c:2191
int value
Definition: genraster.py:62
int count
Definition: genraster.py:57
GSERIALIZED * GEOS2POSTGIS(GEOSGeom geom, char want3d)
GEOSGeometry * POSTGIS2GEOS(const GSERIALIZED *pglwgeom)
#define HANDLE_GEOS_ERROR(label)

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: