PostGIS 3.0.6dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches

◆ pgis_union_geometry_array()

Datum pgis_union_geometry_array ( PG_FUNCTION_ARGS  )

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

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

References geometry_serialize(), GEOS2POSTGIS(), gserialized_error_if_srid_mismatch_reference(), gserialized_get_srid(), gserialized_get_type(), gserialized_has_z(), gserialized_is_empty(), HANDLE_GEOS_ERROR, LW_FALSE, lwgeom_construct_empty(), lwgeom_geos_error(), POSTGIS2GEOS(), and SRID_UNKNOWN.

Here is the call graph for this function: