PostGIS  2.4.9dev-r@@SVN_REVISION@@

◆ pgis_union_geometry_array()

Datum pgis_union_geometry_array ( PG_FUNCTION_ARGS  )

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

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

Referenced by pgis_geometry_union_finalfn(), and ST_FrechetDistance().

368 {
369  /*
370  ** For GEOS >= 3.3, use the new UnaryUnion functionality to merge the
371  ** terminal collection from the ST_Union aggregate
372  */
373  ArrayType *array;
374 
375  ArrayIterator iterator;
376  Datum value;
377  bool isnull;
378 
379  int is3d = LW_FALSE, gotsrid = LW_FALSE;
380  int nelems = 0, geoms_size = 0, curgeom = 0, count = 0;
381 
382  GSERIALIZED *gser_out = NULL;
383 
384  GEOSGeometry *g = NULL;
385  GEOSGeometry *g_union = NULL;
386  GEOSGeometry **geoms = NULL;
387 
388  int srid = SRID_UNKNOWN;
389 
390  int empty_type = 0;
391 
392  /* Null array, null geometry (should be empty?) */
393  if ( PG_ARGISNULL(0) )
394  PG_RETURN_NULL();
395 
396  array = PG_GETARG_ARRAYTYPE_P(0);
397  nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
398 
399  /* Empty array? Null return */
400  if ( nelems == 0 ) PG_RETURN_NULL();
401 
402  /* Quick scan for nulls */
403 #if POSTGIS_PGSQL_VERSION >= 95
404  iterator = array_create_iterator(array, 0, NULL);
405 #else
406  iterator = array_create_iterator(array, 0);
407 #endif
408  while( array_iterate(iterator, &value, &isnull) )
409  {
410  /* Skip null array items */
411  if ( isnull )
412  continue;
413 
414  count++;
415  }
416  array_free_iterator(iterator);
417 
418 
419  /* All-nulls? Return null */
420  if ( count == 0 )
421  PG_RETURN_NULL();
422 
423  /* One geom, good geom? Return it */
424  if ( count == 1 && nelems == 1 )
425  PG_RETURN_POINTER((GSERIALIZED *)(ARR_DATA_PTR(array)));
426 
427  /* Ok, we really need GEOS now ;) */
428  initGEOS(lwpgnotice, lwgeom_geos_error);
429 
430  /*
431  ** Collect the non-empty inputs and stuff them into a GEOS collection
432  */
433  geoms_size = nelems;
434  geoms = palloc(sizeof(GEOSGeometry*) * geoms_size);
435 
436  /*
437  ** We need to convert the array of GSERIALIZED into a GEOS collection.
438  ** First make an array of GEOS geometries.
439  */
440 #if POSTGIS_PGSQL_VERSION >= 95
441  iterator = array_create_iterator(array, 0, NULL);
442 #else
443  iterator = array_create_iterator(array, 0);
444 #endif
445  while( array_iterate(iterator, &value, &isnull) )
446  {
447  GSERIALIZED *gser_in;
448 
449  /* Skip null array items */
450  if ( isnull )
451  continue;
452 
453  gser_in = (GSERIALIZED *)DatumGetPointer(value);
454 
455  /* Check for SRID mismatch in array elements */
456  if ( gotsrid )
457  {
459  }
460  else
461  {
462  /* Initialize SRID/dimensions info */
463  srid = gserialized_get_srid(gser_in);
464  is3d = gserialized_has_z(gser_in);
465  gotsrid = 1;
466  }
467 
468  /* Don't include empties in the union */
469  if ( gserialized_is_empty(gser_in) )
470  {
471  int gser_type = gserialized_get_type(gser_in);
472  if (gser_type > empty_type)
473  {
474  empty_type = gser_type;
475  POSTGIS_DEBUGF(4, "empty_type = %d gser_type = %d", empty_type, gser_type);
476  }
477  }
478  else
479  {
480  g = (GEOSGeometry *)POSTGIS2GEOS(gser_in);
481 
482  /* Uh oh! Exception thrown at construction... */
483  if ( ! g )
484  {
485  HANDLE_GEOS_ERROR("One of the geometries in the set "
486  "could not be converted to GEOS");
487  PG_RETURN_NULL();
488  }
489 
490  /* Ensure we have enough space in our storage array */
491  if ( curgeom == geoms_size )
492  {
493  geoms_size *= 2;
494  geoms = repalloc( geoms, sizeof(GEOSGeometry*) * geoms_size );
495  }
496 
497  geoms[curgeom] = g;
498  curgeom++;
499  }
500 
501  }
502  array_free_iterator(iterator);
503 
504  /*
505  ** Take our GEOS geometries and turn them into a GEOS collection,
506  ** then pass that into cascaded union.
507  */
508  if (curgeom > 0)
509  {
510  g = GEOSGeom_createCollection(GEOS_GEOMETRYCOLLECTION, geoms, curgeom);
511  if ( ! g )
512  {
513  HANDLE_GEOS_ERROR("Could not create GEOS COLLECTION from geometry array");
514  PG_RETURN_NULL();
515  }
516 
517  g_union = GEOSUnaryUnion(g);
518  GEOSGeom_destroy(g);
519  if ( ! g_union )
520  {
521  HANDLE_GEOS_ERROR("GEOSUnaryUnion");
522  PG_RETURN_NULL();
523  }
524 
525  GEOSSetSRID(g_union, srid);
526  gser_out = GEOS2POSTGIS(g_union, is3d);
527  GEOSGeom_destroy(g_union);
528  }
529  /* No real geometries in our array, any empties? */
530  else
531  {
532  /* If it was only empties, we'll return the largest type number */
533  if ( empty_type > 0 )
534  {
535  PG_RETURN_POINTER(geometry_serialize(lwgeom_construct_empty(empty_type, srid, is3d, 0)));
536  }
537  /* Nothing but NULL, returns NULL */
538  else
539  {
540  PG_RETURN_NULL();
541  }
542  }
543 
544  if ( ! gser_out )
545  {
546  /* Union returned a NULL geometry */
547  PG_RETURN_NULL();
548  }
549 
550  PG_RETURN_POINTER(gser_out);
551 }
uint32_t gserialized_get_type(const GSERIALIZED *s)
Extract the geometry type from the serialized form (it hides in the anonymous data area...
Definition: g_serialized.c:86
void error_if_srid_mismatch(int srid1, int srid2)
Definition: lwutil.c:371
int gserialized_has_z(const GSERIALIZED *gser)
Check if a GSERIALIZED has a Z ordinate.
Definition: g_serialized.c:45
int gserialized_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
Definition: g_serialized.c:179
void lwgeom_geos_error(const char *fmt,...)
#define LW_FALSE
Definition: liblwgeom.h:77
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:188
int count
Definition: genraster.py:56
LWGEOM * lwgeom_construct_empty(uint8_t type, int srid, char hasz, char hasm)
Definition: lwgeom.c:1851
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)
GEOSGeometry * POSTGIS2GEOS(GSERIALIZED *pglwgeom)
GSERIALIZED * GEOS2POSTGIS(GEOSGeom geom, char want3d)
int value
Definition: genraster.py:61
#define HANDLE_GEOS_ERROR(label)
int32_t gserialized_get_srid(const GSERIALIZED *s)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
Definition: g_serialized.c:100
Here is the call graph for this function:
Here is the caller graph for this function: