PostGIS  2.3.8dev-r@@SVN_REVISION@@

◆ pgis_union_geometry_array()

Datum pgis_union_geometry_array ( PG_FUNCTION_ARGS  )

Definition at line 292 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 hausdorffdistancedensify(), and pgis_geometry_union_finalfn().

293 {
294  /*
295  ** For GEOS >= 3.3, use the new UnaryUnion functionality to merge the
296  ** terminal collection from the ST_Union aggregate
297  */
298  ArrayType *array;
299 
300  ArrayIterator iterator;
301  Datum value;
302  bool isnull;
303 
304  int is3d = LW_FALSE, gotsrid = LW_FALSE;
305  int nelems = 0, geoms_size = 0, curgeom = 0, count = 0;
306 
307  GSERIALIZED *gser_out = NULL;
308 
309  GEOSGeometry *g = NULL;
310  GEOSGeometry *g_union = NULL;
311  GEOSGeometry **geoms = NULL;
312 
313  int srid = SRID_UNKNOWN;
314 
315  int empty_type = 0;
316 
317  /* Null array, null geometry (should be empty?) */
318  if ( PG_ARGISNULL(0) )
319  PG_RETURN_NULL();
320 
321  array = PG_GETARG_ARRAYTYPE_P(0);
322  nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
323 
324  /* Empty array? Null return */
325  if ( nelems == 0 ) PG_RETURN_NULL();
326 
327  /* Quick scan for nulls */
328 #if POSTGIS_PGSQL_VERSION >= 95
329  iterator = array_create_iterator(array, 0, NULL);
330 #else
331  iterator = array_create_iterator(array, 0);
332 #endif
333  while( array_iterate(iterator, &value, &isnull) )
334  {
335  /* Skip null array items */
336  if ( isnull )
337  continue;
338 
339  count++;
340  }
341  array_free_iterator(iterator);
342 
343 
344  /* All-nulls? Return null */
345  if ( count == 0 )
346  PG_RETURN_NULL();
347 
348  /* One geom, good geom? Return it */
349  if ( count == 1 && nelems == 1 )
350  PG_RETURN_POINTER((GSERIALIZED *)(ARR_DATA_PTR(array)));
351 
352  /* Ok, we really need GEOS now ;) */
353  initGEOS(lwpgnotice, lwgeom_geos_error);
354 
355  /*
356  ** Collect the non-empty inputs and stuff them into a GEOS collection
357  */
358  geoms_size = nelems;
359  geoms = palloc(sizeof(GEOSGeometry*) * geoms_size);
360 
361  /*
362  ** We need to convert the array of GSERIALIZED into a GEOS collection.
363  ** First make an array of GEOS geometries.
364  */
365 #if POSTGIS_PGSQL_VERSION >= 95
366  iterator = array_create_iterator(array, 0, NULL);
367 #else
368  iterator = array_create_iterator(array, 0);
369 #endif
370  while( array_iterate(iterator, &value, &isnull) )
371  {
372  GSERIALIZED *gser_in;
373 
374  /* Skip null array items */
375  if ( isnull )
376  continue;
377 
378  gser_in = (GSERIALIZED *)DatumGetPointer(value);
379 
380  /* Check for SRID mismatch in array elements */
381  if ( gotsrid )
382  {
384  }
385  else
386  {
387  /* Initialize SRID/dimensions info */
388  srid = gserialized_get_srid(gser_in);
389  is3d = gserialized_has_z(gser_in);
390  gotsrid = 1;
391  }
392 
393  /* Don't include empties in the union */
394  if ( gserialized_is_empty(gser_in) )
395  {
396  int gser_type = gserialized_get_type(gser_in);
397  if (gser_type > empty_type)
398  {
399  empty_type = gser_type;
400  POSTGIS_DEBUGF(4, "empty_type = %d gser_type = %d", empty_type, gser_type);
401  }
402  }
403  else
404  {
405  g = (GEOSGeometry *)POSTGIS2GEOS(gser_in);
406 
407  /* Uh oh! Exception thrown at construction... */
408  if ( ! g )
409  {
410  HANDLE_GEOS_ERROR("One of the geometries in the set "
411  "could not be converted to GEOS");
412  PG_RETURN_NULL();
413  }
414 
415  /* Ensure we have enough space in our storage array */
416  if ( curgeom == geoms_size )
417  {
418  geoms_size *= 2;
419  geoms = repalloc( geoms, sizeof(GEOSGeometry*) * geoms_size );
420  }
421 
422  geoms[curgeom] = g;
423  curgeom++;
424  }
425 
426  }
427  array_free_iterator(iterator);
428 
429  /*
430  ** Take our GEOS geometries and turn them into a GEOS collection,
431  ** then pass that into cascaded union.
432  */
433  if (curgeom > 0)
434  {
435  g = GEOSGeom_createCollection(GEOS_GEOMETRYCOLLECTION, geoms, curgeom);
436  if ( ! g )
437  {
438  HANDLE_GEOS_ERROR("Could not create GEOS COLLECTION from geometry array");
439  PG_RETURN_NULL();
440  }
441 
442  g_union = GEOSUnaryUnion(g);
443  GEOSGeom_destroy(g);
444  if ( ! g_union )
445  {
446  HANDLE_GEOS_ERROR("GEOSUnaryUnion");
447  PG_RETURN_NULL();
448  }
449 
450  GEOSSetSRID(g_union, srid);
451  gser_out = GEOS2POSTGIS(g_union, is3d);
452  GEOSGeom_destroy(g_union);
453  }
454  /* No real geometries in our array, any empties? */
455  else
456  {
457  /* If it was only empties, we'll return the largest type number */
458  if ( empty_type > 0 )
459  {
460  PG_RETURN_POINTER(geometry_serialize(lwgeom_construct_empty(empty_type, srid, is3d, 0)));
461  }
462  /* Nothing but NULL, returns NULL */
463  else
464  {
465  PG_RETURN_NULL();
466  }
467  }
468 
469  if ( ! gser_out )
470  {
471  /* Union returned a NULL geometry */
472  PG_RETURN_NULL();
473  }
474 
475  PG_RETURN_POINTER(gser_out);
476 }
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:69
void error_if_srid_mismatch(int srid1, int srid2)
Definition: lwutil.c:369
int gserialized_has_z(const GSERIALIZED *gser)
Check if a GSERIALIZED has a Z ordinate.
Definition: g_serialized.c:38
int gserialized_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
Definition: g_serialized.c:153
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:1820
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:83
Here is the call graph for this function:
Here is the caller graph for this function: