]> granicus.if.org Git - postgis/commitdiff
Enhanced ST_Union(raster, uniontype) to union all bands of all rasters.
authorBborie Park <bkpark at ucdavis.edu>
Tue, 26 Mar 2013 04:14:48 +0000 (04:14 +0000)
committerBborie Park <bkpark at ucdavis.edu>
Tue, 26 Mar 2013 04:14:48 +0000 (04:14 +0000)
Ticket #2200.

git-svn-id: http://svn.osgeo.org/postgis/trunk@11207 b70326c6-7e19-0410-871a-916f4a2858ee

NEWS
doc/reference_raster.xml
raster/rt_pg/rt_pg.c
raster/test/regress/rt_union.sql
raster/test/regress/rt_union_expected

diff --git a/NEWS b/NEWS
index 2c52e32be33dc2a9b3d29d1f09efb4980cb18530..5d29123cbd19da5bda3d3fe0b20778ddea526ce1 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -123,6 +123,7 @@ PostGIS 2.1.0
   - #2178, ST_Summary now advertises presence of known srid with an [S] flag
   - #2202, Make libjson-c optional (--without-json configure switch)
   - #2231, raster2pgsql supports user naming of filename column with -n
+  - #2200, ST_Union(raster, uniontype) unions all bands of all rasters
 
 * Fixes *
 
index cb5ed90ae170d5be460e825d100fc748fc291a45..75a629099881388749324159a12d20ea347d50c9 100644 (file)
@@ -10512,7 +10512,8 @@ UPDATE wind
                                <note><para>For variant ST_Union(rast,uniontype),  band 1 is assumed.</para></note>
                                <para>Enhanced: 2.1.0 Improved Speed (fully C-Based).</para>
                                <para>Availability: 2.1.0 ST_Union(rast, unionarg) variant was introduced.</para>
-                               <para>Enhanced: 2.1.0 ST_Union(rast) (variant 1) now unions all bands of all input rasters, if no band is specified.  Prior versions of PostGIS assumed the first band.</para>
+                               <para>Enhanced: 2.1.0 ST_Union(rast) (variant 1) unions all bands of all input rasters.  Prior versions of PostGIS assumed the first band.</para>
+                               <para>Enhanced: 2.1.0 ST_Union(rast, uniontype) (variant 4) unions all bands of all input rasters.</para>
                                
                                
                        </refsection>
index ee11e2f384d0288712aec0e31bae00dd12412b92..8ebf4551d4bf2a097c586670edd7162ee12c761a 100644 (file)
@@ -4735,7 +4735,6 @@ Datum RASTER_neighborhood(PG_FUNCTION_ARGS)
        bool exclude_nodata_value = TRUE;
        double pixval;
        int isnodata = 0;
-       int inextent = 0;
 
        rt_pixel npixels = NULL;
        int count;
@@ -4859,7 +4858,6 @@ Datum RASTER_neighborhood(PG_FUNCTION_ARGS)
                        PG_FREE_IF_COPY(pgraster, 0);
                        PG_RETURN_NULL();
                }
-               inextent = 1;
        }
        /* outside band extent, set to NODATA */
        else {
@@ -4869,7 +4867,6 @@ Datum RASTER_neighborhood(PG_FUNCTION_ARGS)
                /* no NODATA, use min possible value */
                else
                        pixval = rt_band_get_min_value(band);
-               inextent = 0;
                isnodata = 1;
        }
        POSTGIS_RT_DEBUGF(4, "pixval: %f", pixval);
@@ -16253,7 +16250,7 @@ static int rtpg_union_noarg(rtpg_union_arg arg, rt_raster raster) {
 
                /* add new working rt_raster but only if working raster already exists */
                if (!rt_raster_is_empty(arg->bandarg[0].raster[0])) {
-                       arg->bandarg[i].raster[0] = rt_raster_clone(arg->bandarg[0].raster[0], 0);
+                       arg->bandarg[i].raster[0] = rt_raster_clone(arg->bandarg[0].raster[0], 0); /* shallow clone */
                        if (arg->bandarg[i].raster[0] == NULL) {
                                elog(ERROR, "rtpg_union_noarg: Unable to create working raster");
                                return 0;
@@ -16283,6 +16280,7 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS)
        int hasband[2] = {0};
        int nargs = 0;
        double _offset[4] = {0.};
+       int nbnodata = 0; /* 1 if adding bands */
 
        int i = 0;
        int j = 0;
@@ -16356,24 +16354,60 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS)
        /* process additional args if needed */
        nargs = PG_NARGS();
        POSTGIS_RT_DEBUGF(4, "nargs = %d", nargs);
-       if (!skiparg && nargs > 2) {
+       if (nargs > 2) {
                POSTGIS_RT_DEBUG(4, "processing additional arguments");
 
                /* if more than 2 arguments, determine the type of argument 3 */
                /* band number, UNION type or unionarg */
-               if (nargs > 2 && !PG_ARGISNULL(2)) {
+               if (!PG_ARGISNULL(2)) {
                        Oid calltype = get_fn_expr_argtype(fcinfo->flinfo, 2);
 
                        switch (calltype) {
                                /* UNION type */
-                               case TEXTOID:
+                               case TEXTOID: {
+                                       int idx = 0;
+                                       int numband = 0;
+
                                        POSTGIS_RT_DEBUG(4, "Processing arg 3 as UNION type");
+                                       nbnodata = 1;
+
                                        utypename = text_to_cstring(PG_GETARG_TEXT_P(2));
                                        utype = rtpg_uniontype_index_from_name(rtpg_strtoupper(utypename));
+                                       POSTGIS_RT_DEBUGF(4, "Union type: %s", utypename);
+
+                                       POSTGIS_RT_DEBUGF(4, "iwr->numband: %d", iwr->numband);
+                                       /* see if we need to append new bands */
+                                       if (raster) {
+                                               idx = iwr->numband;
+                                               numband = rt_raster_get_num_bands(raster);
+                                               POSTGIS_RT_DEBUGF(4, "numband: %d", numband);
+
+                                               /* only worry about appended bands */
+                                               if (numband > iwr->numband)
+                                                       iwr->numband = numband;
+                                       }
 
-                                       iwr->numband = 1;
-
-                                       iwr->bandarg = palloc(sizeof(struct rtpg_union_band_arg_t) * iwr->numband);
+                                       if (!iwr->numband)
+                                               iwr->numband = 1;
+                                       POSTGIS_RT_DEBUGF(4, "iwr->numband: %d", iwr->numband);
+                                       POSTGIS_RT_DEBUGF(4, "numband, idx: %d, %d", numband, idx);
+
+                                       /* bandarg set. only possible after the first call to function */
+                                       if (iwr->bandarg) {
+                                               /* only reallocate if new bands need to be added */
+                                               if (numband > idx) {
+                                                       POSTGIS_RT_DEBUG(4, "Reallocating iwr->bandarg");
+                                                       iwr->bandarg = repalloc(iwr->bandarg, sizeof(struct rtpg_union_band_arg_t) * iwr->numband);
+                                               }
+                                               /* prevent initial values step happening below */
+                                               else
+                                                       idx = iwr->numband;
+                                       }
+                                       /* bandarg not set, first call to function */
+                                       else {
+                                               POSTGIS_RT_DEBUG(4, "Allocating iwr->bandarg");
+                                               iwr->bandarg = palloc(sizeof(struct rtpg_union_band_arg_t) * iwr->numband);
+                                       }
                                        if (iwr->bandarg == NULL) {
                                                elog(ERROR, "RASTER_union_transfn: Unable to allocate memory for band information");
 
@@ -16387,22 +16421,30 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS)
                                                PG_RETURN_NULL();
                                        }
 
-                                       iwr->bandarg[0].uniontype = utype;
-                                       iwr->bandarg[0].nband = 0;
+                                       /* set initial values for bands that are "new" */
+                                       for (i = idx; i < iwr->numband; i++) {
+                                               iwr->bandarg[i].uniontype = utype;
+                                               iwr->bandarg[i].nband = i;
 
-                                       if (
-                                               iwr->bandarg[0].uniontype == UT_MEAN ||
-                                               iwr->bandarg[0].uniontype == UT_RANGE
-                                       ) {
-                                               iwr->bandarg[0].numraster = 2;
+                                               if (
+                                                       utype == UT_MEAN ||
+                                                       utype == UT_RANGE
+                                               ) {
+                                                       iwr->bandarg[i].numraster = 2;
+                                               }
+                                               else
+                                                       iwr->bandarg[i].numraster = 1;
+                                               iwr->bandarg[i].raster = NULL;
                                        }
-                                       else
-                                               iwr->bandarg[0].numraster = 1;
-                                       iwr->bandarg[0].raster = NULL;
+
                                        break;
+                               }
                                /* band number */
                                case INT2OID:
                                case INT4OID:
+                                       if (skiparg)
+                                               break;
+
                                        POSTGIS_RT_DEBUG(4, "Processing arg 3 as band number");
                                        nband = PG_GETARG_INT32(2);
                                        if (nband < 1) {
@@ -16441,6 +16483,9 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS)
                                        break;
                                /* only other type allowed is unionarg */
                                default: 
+                                       if (skiparg)
+                                               break;
+
                                        POSTGIS_RT_DEBUG(4, "Processing arg 3 as unionarg");
                                        if (!rtpg_union_unionarg_process(iwr, PG_GETARG_ARRAYTYPE_P(2))) {
                                                elog(ERROR, "RASTER_union_transfn: Unable to process unionarg");
@@ -16464,6 +16509,7 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS)
                        utypename = text_to_cstring(PG_GETARG_TEXT_P(3));
                        utype = rtpg_uniontype_index_from_name(rtpg_strtoupper(utypename));
                        iwr->bandarg[0].uniontype = utype;
+                       POSTGIS_RT_DEBUGF(4, "Union type: %s", utypename);
 
                        if (
                                utype == UT_MEAN ||
@@ -16475,6 +16521,14 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS)
 
                /* allocate space for pointers to rt_raster */
                for (i = 0; i < iwr->numband; i++) {
+                       POSTGIS_RT_DEBUGF(4, "iwr->bandarg[%d].raster @ %p", i, iwr->bandarg[i].raster);
+
+                       /* no need to allocate */
+                       if (iwr->bandarg[i].raster != NULL)
+                               continue;
+
+                       POSTGIS_RT_DEBUGF(4, "Allocating space for working rasters of band %d", i);
+
                        iwr->bandarg[i].raster = (rt_raster *) palloc(sizeof(rt_raster) * iwr->bandarg[i].numraster);
                        if (iwr->bandarg[i].raster == NULL) {
                                elog(ERROR, "RASTER_union_transfn: Unable to allocate memory for working raster(s)");
@@ -16490,12 +16544,32 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS)
                        }
 
                        memset(iwr->bandarg[i].raster, 0, sizeof(rt_raster) * iwr->bandarg[i].numraster);
+
+                       /* add new working rt_raster but only if working raster already exists */
+                       if (i > 0 && !rt_raster_is_empty(iwr->bandarg[0].raster[0])) {
+                               for (j = 0; j < iwr->bandarg[i].numraster; j++) {
+                                       iwr->bandarg[i].raster[j] = rt_raster_clone(iwr->bandarg[0].raster[0], 0); /* shallow clone */
+                                       if (iwr->bandarg[i].raster[j] == NULL) {
+                                               elog(ERROR, "RASTER_union_transfn: Unable to create working raster");
+
+                                               rtpg_union_arg_destroy(iwr);
+                                               if (raster != NULL) {
+                                                       rt_raster_destroy(raster);
+                                                       PG_FREE_IF_COPY(pgraster, 1);
+                                               }
+
+                                               MemoryContextSwitchTo(oldcontext);
+                                               PG_RETURN_NULL();
+                                       }
+                               }
+                       }
                }
        }
        /* only raster, no additional args */
        /* only do this if raster isn't empty */
-       else if (nargs < 3) {
+       else {
                POSTGIS_RT_DEBUG(4, "no additional args, checking input raster");
+               nbnodata = 1;
                if (!rtpg_union_noarg(iwr, raster)) {
                        elog(ERROR, "RASTER_union_transfn: Unable to check and balance number of bands");
 
@@ -16597,12 +16671,12 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS)
                        itrset[1].raster = raster;
                        itrset[1].nband = iwr->bandarg[i].nband;
 
-                       /* no additional arguments in aggregate, allow use NODATA to replace missing bands */
-                       if (nargs < 3) {
+                       /* allow use NODATA to replace missing bands */
+                       if (nbnodata) {
                                itrset[0].nbnodata = 1;
                                itrset[1].nbnodata = 1;
                        }
-                       /* additional arguments in aggregate, missing bands are not ignored */
+                       /* missing bands are not ignored */
                        else {
                                itrset[0].nbnodata = 0;
                                itrset[1].nbnodata = 0;
index 17cb480d2dee6e29ca11c6146e0ea607270463c1..7a2e6a22f2e2ac7d31471e85aca8b142652d3ecf 100644 (file)
@@ -349,13 +349,33 @@ INSERT INTO raster_union_in
 
 INSERT INTO raster_union_out
        SELECT
-               'LAST',
+               'LAST-1',
                ST_Union(rast) AS rast
        FROM raster_union_in;
 
+INSERT INTO raster_union_out
+       SELECT
+               'LAST-2',
+               ST_Union(rast, 'last') AS rast
+       FROM raster_union_in;
+
+INSERT INTO raster_union_out
+       SELECT
+               'FIRST-2',
+               ST_Union(rast, 'first') AS rast
+       FROM raster_union_in;
+
+INSERT INTO raster_union_out
+       SELECT
+               'MEAN-2',
+               ST_Union(rast, 'mean') AS rast
+       FROM raster_union_in;
+
 SELECT
+       uniontype,
        (ST_Metadata(rast)).*
-FROM raster_union_out;
+FROM raster_union_out
+ORDER BY uniontype;
 
 SELECT
        uniontype,
index b9befe6bc6c93a6d20db7e0ccc17074ad5a0380e..719d4cd98faa963e656c75d406f63862082b1e8b 100644 (file)
@@ -585,55 +585,202 @@ SUM|3|2|200
 SUM|1|3|
 SUM|2|3|200
 SUM|3|3|200
--1|1|4|4|1|-1|0|0|0|3
-LAST|1|1|3
-LAST|2|1|3
-LAST|3|1|4
-LAST|4|1|4
-LAST|1|2|3
-LAST|2|2|3
-LAST|3|2|4
-LAST|4|2|4
-LAST|1|3|
-LAST|2|3|1
-LAST|3|3|2
-LAST|4|3|2
-LAST|1|4|
-LAST|2|4|
-LAST|3|4|2
-LAST|4|4|2
-LAST|1|1|300
-LAST|2|1|300
-LAST|3|1|400
-LAST|4|1|400
-LAST|1|2|300
-LAST|2|2|300
-LAST|3|2|400
-LAST|4|2|400
-LAST|1|3|
-LAST|2|3|100
-LAST|3|3|200
-LAST|4|3|200
-LAST|1|4|
-LAST|2|4|
-LAST|3|4|200
-LAST|4|4|200
-LAST|1|1|-1
-LAST|2|1|-1
-LAST|3|1|
-LAST|4|1|
-LAST|1|2|-1
-LAST|2|2|-1
-LAST|3|2|
-LAST|4|2|
-LAST|1|3|
-LAST|2|3|
-LAST|3|3|
-LAST|4|3|
-LAST|1|4|
-LAST|2|4|
-LAST|3|4|
-LAST|4|4|
+FIRST-2|-1|1|4|4|1|-1|0|0|0|3
+LAST-1|-1|1|4|4|1|-1|0|0|0|3
+LAST-2|-1|1|4|4|1|-1|0|0|0|3
+MEAN-2|-1|1|4|4|1|-1|0|0|0|3
+FIRST-2|1|1|3
+FIRST-2|2|1|3
+FIRST-2|3|1|4
+FIRST-2|4|1|4
+FIRST-2|1|2|3
+FIRST-2|2|2|1
+FIRST-2|3|2|1
+FIRST-2|4|2|4
+FIRST-2|1|3|
+FIRST-2|2|3|1
+FIRST-2|3|3|1
+FIRST-2|4|3|2
+FIRST-2|1|4|
+FIRST-2|2|4|
+FIRST-2|3|4|2
+FIRST-2|4|4|2
+LAST-1|1|1|3
+LAST-1|2|1|3
+LAST-1|3|1|4
+LAST-1|4|1|4
+LAST-1|1|2|3
+LAST-1|2|2|3
+LAST-1|3|2|4
+LAST-1|4|2|4
+LAST-1|1|3|
+LAST-1|2|3|1
+LAST-1|3|3|2
+LAST-1|4|3|2
+LAST-1|1|4|
+LAST-1|2|4|
+LAST-1|3|4|2
+LAST-1|4|4|2
+LAST-2|1|1|3
+LAST-2|2|1|3
+LAST-2|3|1|4
+LAST-2|4|1|4
+LAST-2|1|2|3
+LAST-2|2|2|3
+LAST-2|3|2|4
+LAST-2|4|2|4
+LAST-2|1|3|
+LAST-2|2|3|1
+LAST-2|3|3|2
+LAST-2|4|3|2
+LAST-2|1|4|
+LAST-2|2|4|
+LAST-2|3|4|2
+LAST-2|4|4|2
+MEAN-2|1|1|3
+MEAN-2|2|1|3
+MEAN-2|3|1|4
+MEAN-2|4|1|4
+MEAN-2|1|2|3
+MEAN-2|2|2|2
+MEAN-2|3|2|2
+MEAN-2|4|2|4
+MEAN-2|1|3|
+MEAN-2|2|3|1
+MEAN-2|3|3|1
+MEAN-2|4|3|2
+MEAN-2|1|4|
+MEAN-2|2|4|
+MEAN-2|3|4|2
+MEAN-2|4|4|2
+FIRST-2|1|1|300
+FIRST-2|2|1|300
+FIRST-2|3|1|400
+FIRST-2|4|1|400
+FIRST-2|1|2|300
+FIRST-2|2|2|100
+FIRST-2|3|2|100
+FIRST-2|4|2|400
+FIRST-2|1|3|
+FIRST-2|2|3|100
+FIRST-2|3|3|100
+FIRST-2|4|3|200
+FIRST-2|1|4|
+FIRST-2|2|4|
+FIRST-2|3|4|200
+FIRST-2|4|4|200
+LAST-1|1|1|300
+LAST-1|2|1|300
+LAST-1|3|1|400
+LAST-1|4|1|400
+LAST-1|1|2|300
+LAST-1|2|2|300
+LAST-1|3|2|400
+LAST-1|4|2|400
+LAST-1|1|3|
+LAST-1|2|3|100
+LAST-1|3|3|200
+LAST-1|4|3|200
+LAST-1|1|4|
+LAST-1|2|4|
+LAST-1|3|4|200
+LAST-1|4|4|200
+LAST-2|1|1|300
+LAST-2|2|1|300
+LAST-2|3|1|400
+LAST-2|4|1|400
+LAST-2|1|2|300
+LAST-2|2|2|300
+LAST-2|3|2|400
+LAST-2|4|2|400
+LAST-2|1|3|
+LAST-2|2|3|100
+LAST-2|3|3|200
+LAST-2|4|3|200
+LAST-2|1|4|
+LAST-2|2|4|
+LAST-2|3|4|200
+LAST-2|4|4|200
+MEAN-2|1|1|300
+MEAN-2|2|1|300
+MEAN-2|3|1|400
+MEAN-2|4|1|400
+MEAN-2|1|2|300
+MEAN-2|2|2|200
+MEAN-2|3|2|250
+MEAN-2|4|2|400
+MEAN-2|1|3|
+MEAN-2|2|3|100
+MEAN-2|3|3|150
+MEAN-2|4|3|200
+MEAN-2|1|4|
+MEAN-2|2|4|
+MEAN-2|3|4|200
+MEAN-2|4|4|200
+FIRST-2|1|1|-1
+FIRST-2|2|1|-1
+FIRST-2|3|1|
+FIRST-2|4|1|
+FIRST-2|1|2|-1
+FIRST-2|2|2|-1
+FIRST-2|3|2|
+FIRST-2|4|2|
+FIRST-2|1|3|
+FIRST-2|2|3|
+FIRST-2|3|3|
+FIRST-2|4|3|
+FIRST-2|1|4|
+FIRST-2|2|4|
+FIRST-2|3|4|
+FIRST-2|4|4|
+LAST-1|1|1|-1
+LAST-1|2|1|-1
+LAST-1|3|1|
+LAST-1|4|1|
+LAST-1|1|2|-1
+LAST-1|2|2|-1
+LAST-1|3|2|
+LAST-1|4|2|
+LAST-1|1|3|
+LAST-1|2|3|
+LAST-1|3|3|
+LAST-1|4|3|
+LAST-1|1|4|
+LAST-1|2|4|
+LAST-1|3|4|
+LAST-1|4|4|
+LAST-2|1|1|-1
+LAST-2|2|1|-1
+LAST-2|3|1|
+LAST-2|4|1|
+LAST-2|1|2|-1
+LAST-2|2|2|-1
+LAST-2|3|2|
+LAST-2|4|2|
+LAST-2|1|3|
+LAST-2|2|3|
+LAST-2|3|3|
+LAST-2|4|3|
+LAST-2|1|4|
+LAST-2|2|4|
+LAST-2|3|4|
+LAST-2|4|4|
+MEAN-2|1|1|-1
+MEAN-2|2|1|-1
+MEAN-2|3|1|
+MEAN-2|4|1|
+MEAN-2|1|2|-1
+MEAN-2|2|2|-1
+MEAN-2|3|2|
+MEAN-2|4|2|
+MEAN-2|1|3|
+MEAN-2|2|3|
+MEAN-2|3|3|
+MEAN-2|4|3|
+MEAN-2|1|4|
+MEAN-2|2|4|
+MEAN-2|3|4|
+MEAN-2|4|4|
 -2|4|6|9|1|-1|0|0|0|1
 LAST|1|1|5
 LAST|2|1|5