PostGIS  2.1.10dev-r@@SVN_REVISION@@
Datum pgis_union_geometry_array ( PG_FUNCTION_ARGS  )

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

References error_if_srid_mismatch(), geometry_serialize(), GEOS2POSTGIS(), gserialized_get_srid(), gserialized_get_type(), gserialized_has_z(), gserialized_is_empty(), LW_FALSE, lwerror(), lwgeom_construct_empty(), lwgeom_geos_errmsg, lwgeom_geos_error(), lwnotice(), POSTGIS2GEOS(), and SRID_UNKNOWN.

Referenced by pgis_geometry_union_finalfn().

248 {
249  /*
250  ** For GEOS >= 3.3, use the new UnaryUnion functionality to merge the
251  ** terminal collection from the ST_Union aggregate
252  */
253  Datum datum;
254  ArrayType *array;
255 
256  int is3d = LW_FALSE, gotsrid = LW_FALSE;
257  int nelems = 0, i = 0, geoms_size = 0, curgeom = 0;
258 
259  GSERIALIZED *gser_out = NULL;
260 
261  GEOSGeometry *g = NULL;
262  GEOSGeometry *g_union = NULL;
263  GEOSGeometry **geoms = NULL;
264 
265  int srid = SRID_UNKNOWN;
266 
267  size_t offset = 0;
268  bits8 *bitmap;
269  int bitmask;
270  int empty_type = 0;
271 
272  datum = PG_GETARG_DATUM(0);
273 
274  /* Null array, null geometry (should be empty?) */
275  if ( (Pointer *)datum == NULL ) PG_RETURN_NULL();
276 
277  array = DatumGetArrayTypeP(datum);
278 
279  /* How many things in our array? */
280  nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
281 
282  /* PgSQL supplies a bitmap of which array entries are null */
283  bitmap = ARR_NULLBITMAP(array);
284 
285  /* Empty array? Null return */
286  if ( nelems == 0 ) PG_RETURN_NULL();
287 
288  /* One-element union is the element itself! */
289  if ( nelems == 1 )
290  {
291  /* If the element is a NULL then we need to handle it separately */
292  if (bitmap && (*bitmap & 1) == 0)
293  PG_RETURN_NULL();
294  else
295  PG_RETURN_POINTER((GSERIALIZED *)(ARR_DATA_PTR(array)));
296  }
297 
298  /* Ok, we really need GEOS now ;) */
299  initGEOS(lwnotice, lwgeom_geos_error);
300 
301  /*
302  ** Collect the non-empty inputs and stuff them into a GEOS collection
303  */
304  geoms_size = nelems;
305  geoms = palloc( sizeof(GEOSGeometry*) * geoms_size );
306 
307  /*
308  ** We need to convert the array of GSERIALIZED into a GEOS collection.
309  ** First make an array of GEOS geometries.
310  */
311  offset = 0;
312  bitmap = ARR_NULLBITMAP(array);
313  bitmask = 1;
314  for ( i = 0; i < nelems; i++ )
315  {
316  /* Only work on non-NULL entries in the array */
317  if ((bitmap && (*bitmap & bitmask) != 0) || !bitmap)
318  {
319  GSERIALIZED *gser_in = (GSERIALIZED *)(ARR_DATA_PTR(array)+offset);
320 
321  /* Check for SRID mismatch in array elements */
322  if ( gotsrid )
323  {
325  }
326  else
327  {
328  /* Initialize SRID/dimensions info */
329  srid = gserialized_get_srid(gser_in);
330  is3d = gserialized_has_z(gser_in);
331  gotsrid = 1;
332  }
333 
334  /* Don't include empties in the union */
335  if ( gserialized_is_empty(gser_in) )
336  {
337  int gser_type = gserialized_get_type(gser_in);
338  if (gser_type > empty_type)
339  {
340  empty_type = gser_type;
341  POSTGIS_DEBUGF(4, "empty_type = %d gser_type = %d", empty_type, gser_type);
342  }
343  }
344  else
345  {
346  g = (GEOSGeometry *)POSTGIS2GEOS(gser_in);
347 
348  /* Uh oh! Exception thrown at construction... */
349  if ( ! g )
350  {
351  lwerror("One of the geometries in the set "
352  "could not be converted to GEOS: %s", lwgeom_geos_errmsg);
353  PG_RETURN_NULL();
354  }
355 
356  /* Ensure we have enough space in our storage array */
357  if ( curgeom == geoms_size )
358  {
359  geoms_size *= 2;
360  geoms = repalloc( geoms, sizeof(GEOSGeometry*) * geoms_size );
361  }
362 
363  geoms[curgeom] = g;
364  curgeom++;
365  }
366  offset += INTALIGN(VARSIZE(gser_in));
367  }
368 
369  /* Advance NULL bitmap */
370  if (bitmap)
371  {
372  bitmask <<= 1;
373  if (bitmask == 0x100)
374  {
375  bitmap++;
376  bitmask = 1;
377  }
378  }
379  }
380 
381  /*
382  ** Take our GEOS geometries and turn them into a GEOS collection,
383  ** then pass that into cascaded union.
384  */
385  if (curgeom > 0)
386  {
387  g = GEOSGeom_createCollection(GEOS_GEOMETRYCOLLECTION, geoms, curgeom);
388  if ( ! g )
389  {
390  lwerror("Could not create GEOS COLLECTION from geometry array: %s", lwgeom_geos_errmsg);
391  PG_RETURN_NULL();
392  }
393 
394  g_union = GEOSUnaryUnion(g);
395  GEOSGeom_destroy(g);
396  if ( ! g_union )
397  {
398  lwerror("GEOSUnaryUnion: %s",
400  PG_RETURN_NULL();
401  }
402 
403  GEOSSetSRID(g_union, srid);
404  gser_out = GEOS2POSTGIS(g_union, is3d);
405  GEOSGeom_destroy(g_union);
406  }
407  /* No real geometries in our array, any empties? */
408  else
409  {
410  /* If it was only empties, we'll return the largest type number */
411  if ( empty_type > 0 )
412  {
413  PG_RETURN_POINTER(geometry_serialize(lwgeom_construct_empty(empty_type, srid, is3d, 0)));
414  }
415  /* Nothing but NULL, returns NULL */
416  else
417  {
418  PG_RETURN_NULL();
419  }
420  }
421 
422  if ( ! gser_out )
423  {
424  /* Union returned a NULL geometry */
425  PG_RETURN_NULL();
426  }
427 
428  PG_RETURN_POINTER(gser_out);
429 }
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:56
void error_if_srid_mismatch(int srid1, int srid2)
Definition: lwutil.c:317
char lwgeom_geos_errmsg[LWGEOM_GEOS_ERRMSG_MAXSIZE]
int gserialized_has_z(const GSERIALIZED *gser)
Check if a GSERIALIZED has a Z ordinate.
Definition: g_serialized.c:25
int gserialized_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
Definition: g_serialized.c:140
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:67
void lwnotice(const char *fmt,...)
Write a notice out to the notice handler.
Definition: lwutil.c:54
void lwgeom_geos_error(const char *fmt,...)
#define LW_FALSE
Definition: liblwgeom.h:52
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:154
LWGEOM * lwgeom_construct_empty(uint8_t type, int srid, char hasz, char hasm)
Definition: lwgeom.c:1662
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)
GEOSGeometry * POSTGIS2GEOS(GSERIALIZED *pglwgeom)
GSERIALIZED * GEOS2POSTGIS(GEOSGeom geom, char want3d)
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:70

Here is the call graph for this function:

Here is the caller graph for this function: