PostGIS  3.0.6dev-r@@SVN_REVISION@@

◆ pgis_union_geometry_array()

Datum pgis_union_geometry_array ( PG_FUNCTION_ARGS  )

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

345 {
346  ArrayType *array;
347 
348  ArrayIterator iterator;
349  Datum value;
350  bool isnull;
351 
352  int is3d = LW_FALSE, gotsrid = LW_FALSE;
353  int nelems = 0, geoms_size = 0, curgeom = 0, count = 0;
354 
355  GSERIALIZED *gser_out = NULL;
356 
357  GEOSGeometry *g = NULL;
358  GEOSGeometry *g_union = NULL;
359  GEOSGeometry **geoms = NULL;
360 
361  int32_t srid = SRID_UNKNOWN;
362 
363  int empty_type = 0;
364 
365  /* Null array, null geometry (should be empty?) */
366  if ( PG_ARGISNULL(0) )
367  PG_RETURN_NULL();
368 
369  array = PG_GETARG_ARRAYTYPE_P(0);
370  nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
371 
372  /* Empty array? Null return */
373  if ( nelems == 0 ) PG_RETURN_NULL();
374 
375  /* Quick scan for nulls */
376  iterator = array_create_iterator(array, 0, NULL);
377  while (array_iterate(iterator, &value, &isnull))
378  {
379  /* Skip null array items */
380  if (isnull) continue;
381  count++;
382  }
383  array_free_iterator(iterator);
384 
385 
386  /* All-nulls? Return null */
387  if ( count == 0 )
388  PG_RETURN_NULL();
389 
390  /* One geom, good geom? Return it */
391  if ( count == 1 && nelems == 1 )
392  {
393 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
394 #pragma GCC diagnostic push
395 #pragma GCC diagnostic ignored "-Wsign-compare"
396 #endif
397  PG_RETURN_POINTER((GSERIALIZED *)(ARR_DATA_PTR(array)));
398 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
399 #pragma GCC diagnostic pop
400 #endif
401  }
402 
403  /* Ok, we really need GEOS now ;) */
404  initGEOS(lwpgnotice, lwgeom_geos_error);
405 
406  /*
407  ** Collect the non-empty inputs and stuff them into a GEOS collection
408  */
409  geoms_size = nelems;
410  geoms = palloc(sizeof(GEOSGeometry*) * geoms_size);
411 
412  /*
413  ** We need to convert the array of GSERIALIZED into a GEOS collection.
414  ** First make an array of GEOS geometries.
415  */
416  iterator = array_create_iterator(array, 0, NULL);
417  while (array_iterate(iterator, &value, &isnull))
418  {
419  GSERIALIZED *gser_in;
420 
421  /* Skip null array items */
422  if (isnull) continue;
423  gser_in = (GSERIALIZED *)DatumGetPointer(value);
424 
425  /* Check for SRID mismatch in array elements */
426  if ( gotsrid )
427  gserialized_error_if_srid_mismatch_reference(gser_in, srid, __func__);
428  else
429  {
430  /* Initialize SRID/dimensions info */
431  srid = gserialized_get_srid(gser_in);
432  is3d = gserialized_has_z(gser_in);
433  gotsrid = 1;
434  }
435 
436  /* Don't include empties in the union */
437  if ( gserialized_is_empty(gser_in) )
438  {
439  int gser_type = gserialized_get_type(gser_in);
440  if (gser_type > empty_type)
441  {
442  empty_type = gser_type;
443  POSTGIS_DEBUGF(4, "empty_type = %d gser_type = %d", empty_type, gser_type);
444  }
445  }
446  else
447  {
448  g = POSTGIS2GEOS(gser_in);
449 
450  /* Uh oh! Exception thrown at construction... */
451  if ( ! g )
452  {
454  "One of the geometries in the set "
455  "could not be converted to GEOS");
456  }
457 
458  /* Ensure we have enough space in our storage array */
459  if ( curgeom == geoms_size )
460  {
461  geoms_size *= 2;
462  geoms = repalloc( geoms, sizeof(GEOSGeometry*) * geoms_size );
463  }
464 
465  geoms[curgeom] = g;
466  curgeom++;
467  }
468 
469  }
470  array_free_iterator(iterator);
471 
472  /*
473  ** Take our GEOS geometries and turn them into a GEOS collection,
474  ** then pass that into cascaded union.
475  */
476  if (curgeom > 0)
477  {
478  g = GEOSGeom_createCollection(GEOS_GEOMETRYCOLLECTION, geoms, curgeom);
479  if (!g) HANDLE_GEOS_ERROR("Could not create GEOS COLLECTION from geometry array");
480 
481  g_union = GEOSUnaryUnion(g);
482  GEOSGeom_destroy(g);
483  if (!g_union) HANDLE_GEOS_ERROR("GEOSUnaryUnion");
484 
485  GEOSSetSRID(g_union, srid);
486  gser_out = GEOS2POSTGIS(g_union, is3d);
487  GEOSGeom_destroy(g_union);
488  }
489  /* No real geometries in our array, any empties? */
490  else
491  {
492  /* If it was only empties, we'll return the largest type number */
493  if ( empty_type > 0 )
494  {
495  PG_RETURN_POINTER(geometry_serialize(lwgeom_construct_empty(empty_type, srid, is3d, 0)));
496  }
497  /* Nothing but NULL, returns NULL */
498  else
499  {
500  PG_RETURN_NULL();
501  }
502  }
503 
504  if ( ! gser_out )
505  {
506  /* Union returned a NULL geometry */
507  PG_RETURN_NULL();
508  }
509 
510  PG_RETURN_POINTER(gser_out);
511 }
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:2083
int value
Definition: genraster.py:62
int count
Definition: genraster.py:57
#define HANDLE_GEOS_ERROR(label)
GEOSGeometry * POSTGIS2GEOS(GSERIALIZED *pglwgeom)
GSERIALIZED * GEOS2POSTGIS(GEOSGeom geom, char want3d)
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)

References genraster::count, geometry_serialize(), 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: