PostGIS  2.2.8dev-r@@SVN_REVISION@@

◆ pgis_union_geometry_array()

Datum pgis_union_geometry_array ( PG_FUNCTION_ARGS  )

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

References genraster::count, error_if_srid_mismatch(), dumpnode::geom, geometry_serialize(), LWMPOLY::geoms, GEOS2POSTGIS(), gserialized_get_srid(), gserialized_get_type(), gserialized_has_z(), gserialized_is_empty(), HANDLE_GEOS_ERROR, LW_FALSE, LWGEOM2GEOS(), lwgeom_construct_empty(), lwgeom_from_gserialized(), lwgeom_geos_error(), lwmpoly_free(), lwpoly_as_lwgeom(), lwtype_name(), MULTIPOLYGONTYPE, LWMPOLY::ngeoms, PG_FUNCTION_INFO_V1(), POLYGONTYPE, POSTGIS2GEOS(), SRID_UNKNOWN, ST_UnaryUnion(), and genraster::value.

Referenced by hausdorffdistancedensify(), and pgis_geometry_union_finalfn().

254 {
255  /*
256  ** For GEOS >= 3.3, use the new UnaryUnion functionality to merge the
257  ** terminal collection from the ST_Union aggregate
258  */
259  ArrayType *array;
260 
261  ArrayIterator iterator;
262  Datum value;
263  bool isnull;
264 
265  int is3d = LW_FALSE, gotsrid = LW_FALSE;
266  int nelems = 0, geoms_size = 0, curgeom = 0, count = 0;
267 
268  GSERIALIZED *gser_out = NULL;
269 
270  GEOSGeometry *g = NULL;
271  GEOSGeometry *g_union = NULL;
272  GEOSGeometry **geoms = NULL;
273 
274  int srid = SRID_UNKNOWN;
275 
276  int empty_type = 0;
277 
278  /* Null array, null geometry (should be empty?) */
279  if ( PG_ARGISNULL(0) )
280  PG_RETURN_NULL();
281 
282  array = PG_GETARG_ARRAYTYPE_P(0);
283  nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
284 
285  /* Empty array? Null return */
286  if ( nelems == 0 ) PG_RETURN_NULL();
287 
288  /* Quick scan for nulls */
289 #if POSTGIS_PGSQL_VERSION >= 95
290  iterator = array_create_iterator(array, 0, NULL);
291 #else
292  iterator = array_create_iterator(array, 0);
293 #endif
294  while( array_iterate(iterator, &value, &isnull) )
295  {
296  /* Skip null array items */
297  if ( isnull )
298  continue;
299 
300  count++;
301  }
302  array_free_iterator(iterator);
303 
304 
305  /* All-nulls? Return null */
306  if ( count == 0 )
307  PG_RETURN_NULL();
308 
309  /* One geom, good geom? Return it */
310  if ( count == 1 && nelems == 1 )
311  PG_RETURN_POINTER((GSERIALIZED *)(ARR_DATA_PTR(array)));
312 
313  /* Ok, we really need GEOS now ;) */
314  initGEOS(lwpgnotice, lwgeom_geos_error);
315 
316  /*
317  ** Collect the non-empty inputs and stuff them into a GEOS collection
318  */
319  geoms_size = nelems;
320  geoms = palloc(sizeof(GEOSGeometry*) * geoms_size);
321 
322  /*
323  ** We need to convert the array of GSERIALIZED into a GEOS collection.
324  ** First make an array of GEOS geometries.
325  */
326 #if POSTGIS_PGSQL_VERSION >= 95
327  iterator = array_create_iterator(array, 0, NULL);
328 #else
329  iterator = array_create_iterator(array, 0);
330 #endif
331  while( array_iterate(iterator, &value, &isnull) )
332  {
333  GSERIALIZED *gser_in;
334 
335  /* Skip null array items */
336  if ( isnull )
337  continue;
338 
339  gser_in = (GSERIALIZED *)DatumGetPointer(value);
340 
341  /* Check for SRID mismatch in array elements */
342  if ( gotsrid )
343  {
345  }
346  else
347  {
348  /* Initialize SRID/dimensions info */
349  srid = gserialized_get_srid(gser_in);
350  is3d = gserialized_has_z(gser_in);
351  gotsrid = 1;
352  }
353 
354  /* Don't include empties in the union */
355  if ( gserialized_is_empty(gser_in) )
356  {
357  int gser_type = gserialized_get_type(gser_in);
358  if (gser_type > empty_type)
359  {
360  empty_type = gser_type;
361  POSTGIS_DEBUGF(4, "empty_type = %d gser_type = %d", empty_type, gser_type);
362  }
363  }
364  else
365  {
366  g = (GEOSGeometry *)POSTGIS2GEOS(gser_in);
367 
368  /* Uh oh! Exception thrown at construction... */
369  if ( ! g )
370  {
371  HANDLE_GEOS_ERROR("One of the geometries in the set "
372  "could not be converted to GEOS");
373  PG_RETURN_NULL();
374  }
375 
376  /* Ensure we have enough space in our storage array */
377  if ( curgeom == geoms_size )
378  {
379  geoms_size *= 2;
380  geoms = repalloc( geoms, sizeof(GEOSGeometry*) * geoms_size );
381  }
382 
383  geoms[curgeom] = g;
384  curgeom++;
385  }
386 
387  }
388  array_free_iterator(iterator);
389 
390  /*
391  ** Take our GEOS geometries and turn them into a GEOS collection,
392  ** then pass that into cascaded union.
393  */
394  if (curgeom > 0)
395  {
396  g = GEOSGeom_createCollection(GEOS_GEOMETRYCOLLECTION, geoms, curgeom);
397  if ( ! g )
398  {
399  HANDLE_GEOS_ERROR("Could not create GEOS COLLECTION from geometry array");
400  PG_RETURN_NULL();
401  }
402 
403  g_union = GEOSUnaryUnion(g);
404  GEOSGeom_destroy(g);
405  if ( ! g_union )
406  {
407  HANDLE_GEOS_ERROR("GEOSUnaryUnion");
408  PG_RETURN_NULL();
409  }
410 
411  GEOSSetSRID(g_union, srid);
412  gser_out = GEOS2POSTGIS(g_union, is3d);
413  GEOSGeom_destroy(g_union);
414  }
415  /* No real geometries in our array, any empties? */
416  else
417  {
418  /* If it was only empties, we'll return the largest type number */
419  if ( empty_type > 0 )
420  {
421  PG_RETURN_POINTER(geometry_serialize(lwgeom_construct_empty(empty_type, srid, is3d, 0)));
422  }
423  /* Nothing but NULL, returns NULL */
424  else
425  {
426  PG_RETURN_NULL();
427  }
428  }
429 
430  if ( ! gser_out )
431  {
432  /* Union returned a NULL geometry */
433  PG_RETURN_NULL();
434  }
435 
436  PG_RETURN_POINTER(gser_out);
437 }
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:55
void error_if_srid_mismatch(int srid1, int srid2)
Definition: lwutil.c:341
int gserialized_has_z(const GSERIALIZED *gser)
Check if a GSERIALIZED has a Z ordinate.
Definition: g_serialized.c:24
int gserialized_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
Definition: g_serialized.c:139
void lwgeom_geos_error(const char *fmt,...)
#define LW_FALSE
Definition: liblwgeom.h:62
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:172
int count
Definition: genraster.py:56
LWGEOM * lwgeom_construct_empty(uint8_t type, int srid, char hasz, char hasm)
Definition: lwgeom.c:1807
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:69
Here is the call graph for this function:
Here is the caller graph for this function: