PostGIS  2.5.0beta2dev-r@@SVN_REVISION@@

◆ pgis_union_geometry_array()

Datum pgis_union_geometry_array ( PG_FUNCTION_ARGS  )

Definition at line 343 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_abs_out(), pgis_geometry_union_finalfn(), and ST_FrechetDistance().

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