]> granicus.if.org Git - postgis/commitdiff
Addition of ST_Union(raster) function and regression tests
authorBborie Park <bkpark at ucdavis.edu>
Wed, 3 Oct 2012 20:53:22 +0000 (20:53 +0000)
committerBborie Park <bkpark at ucdavis.edu>
Wed, 3 Oct 2012 20:53:22 +0000 (20:53 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@10370 b70326c6-7e19-0410-871a-916f4a2858ee

raster/rt_pg/rt_pg.c
raster/test/regress/rt_union.sql
raster/test/regress/rt_union_expected

index 7351cd7fa5e590fc212d51ea08269adc8166893d..dffbc6f4eaa6e9850171a0cc64bba2536e50822e 100644 (file)
@@ -13764,6 +13764,7 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS)
        int noerr = 1;
        int isempty[2] = {0};
        int hasband[2] = {0};
+       int nargs = 0;
 
        int i = 0;
        int j = 0;
@@ -13826,12 +13827,14 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS)
        }
 
        /* process additional args if needed */
-       if (!skiparg) {
-               POSTGIS_RT_DEBUGF(4, "PG_NARGS() = %d", (int) PG_NARGS());
+       nargs = PG_NARGS();
+       POSTGIS_RT_DEBUGF(4, "nargs = %d", nargs);
+       if (!skiparg && 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 (PG_NARGS() > 2 && !PG_ARGISNULL(2)) {
+               if (nargs > 2 && !PG_ARGISNULL(2)) {
                        Oid calltype = get_fn_expr_argtype(fcinfo->flinfo, 2);
 
                        switch (calltype) {
@@ -14049,7 +14052,7 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS)
                }
 
                /* UNION type */
-               if (PG_NARGS() > 3 && !PG_ARGISNULL(3)) {
+               if (nargs > 3 && !PG_ARGISNULL(3)) {
                        utypename = text_to_cstring(PG_GETARG_TEXT_P(3));
                        utype = rtpg_uniontype_index_from_name(rtpg_strtoupper(utypename));
                        iwr->bandarg[0].uniontype = utype;
@@ -14060,7 +14063,7 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS)
 
                /* allocate space for pointers to rt_raster */
                for (i = 0; i < iwr->numband; i++) {
-                       iwr->bandarg[i].raster = (rt_raster *) rtalloc(sizeof(rt_raster) * iwr->bandarg[i].numraster);
+                       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)");
 
@@ -14077,6 +14080,136 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS)
                        memset(iwr->bandarg[i].raster, 0, sizeof(rt_raster) * iwr->bandarg[i].numraster);
                }
        }
+       /* only raster, no additional args */
+       /* only do this if raster isn't empty */
+       else if (nargs < 3) {
+               POSTGIS_RT_DEBUG(4, "no additional args, checking input raster");
+
+               do {
+                       int numbands;
+
+
+                       if (rt_raster_is_empty(raster))
+                               break;
+
+                       numbands = rt_raster_get_num_bands(raster);
+                       if (numbands == iwr->numband)
+                               break;
+
+                       /* incoming has fewer bands, add NODATA bands to incoming */
+                       /* TODO: have rt_raster_iterator() treat missing band as NODATA band? */
+                       if (numbands < iwr->numband) {
+                               POSTGIS_RT_DEBUG(4, "input raster has fewer bands, adding NODATA bands");
+                               for (i = numbands; i < iwr->numband; i++) {
+                                       if (rt_raster_generate_new_band(raster, PT_8BUI, 0, 1, 0, i) < 0) {
+                                               elog(ERROR, "RASTER_union_transfn: Unable to create NODATA band");
+
+                                               rtpg_union_arg_destroy(iwr);
+                                               if (raster != NULL) {
+                                                       rt_raster_destroy(raster);
+                                                       PG_FREE_IF_COPY(pgraster, 1);
+                                               }
+
+                                               MemoryContextSwitchTo(oldcontext);
+                                               PG_RETURN_NULL();
+                                       }
+                               }
+
+                               break;
+                       }
+
+                       /* more bands to process */
+                       POSTGIS_RT_DEBUG(4, "input raster has more bands, adding more bandargs");
+                       if (iwr->numband)
+                               iwr->bandarg = repalloc(iwr->bandarg, sizeof(struct rtpg_union_band_arg_t) * numbands);
+                       else
+                               iwr->bandarg = palloc(sizeof(struct rtpg_union_band_arg_t) * numbands);
+                       if (iwr->bandarg == NULL) {
+                               elog(ERROR, "RASTER_union_transfn: Unable to reallocate memory for band information");
+
+                               rtpg_union_arg_destroy(iwr);
+                               if (raster != NULL) {
+                                       rt_raster_destroy(raster);
+                                       PG_FREE_IF_COPY(pgraster, 1);
+                               }
+
+                               MemoryContextSwitchTo(oldcontext);
+                               PG_RETURN_NULL();
+                       }
+
+                       i = iwr->numband;
+                       iwr->numband = numbands;
+                       for (; i < iwr->numband; i++) {
+                               POSTGIS_RT_DEBUGF(4, "Adding bandarg for band at index %d", i);
+                               iwr->bandarg[i].uniontype = UT_LAST;
+                               iwr->bandarg[i].nband = i;
+                               iwr->bandarg[i].numraster = 1;
+
+                               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 rasters");
+
+                                       rtpg_union_arg_destroy(iwr);
+                                       if (raster != NULL) {
+                                               rt_raster_destroy(raster);
+                                               PG_FREE_IF_COPY(pgraster, 1);
+                                       }
+
+                                       MemoryContextSwitchTo(oldcontext);
+                                       PG_RETURN_NULL();
+                               }
+                               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 (!rt_raster_is_empty(iwr->bandarg[0].raster[0])) {
+                                       iwr->bandarg[i].raster[0] = rt_raster_clone(iwr->bandarg[0].raster[0], 0);
+                                       if (iwr->bandarg[i].raster[0] == 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();
+                                       }
+
+                                       /* create band of same type as input raster */
+                                       _band = rt_raster_get_band(raster, i);
+                                       pixtype = rt_band_get_pixtype(_band);
+                                       hasnodata = rt_band_get_hasnodata_flag(_band);
+                                       if (hasnodata)
+                                               nodataval = rt_band_get_nodata(_band);
+                                       /* shouldn't this be rt_band_get_min_val(_band) */
+                                       else
+                                               nodataval = 0;
+
+                                       if (rt_raster_generate_new_band(
+                                               iwr->bandarg[i].raster[0],
+                                               pixtype,
+                                               nodataval,
+                                               hasnodata, nodataval,
+                                               i
+                                       ) < 0) {
+                                               elog(ERROR, "RASTER_union_transfn: Unable to add new band to 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();
+                                       }
+                               }
+
+                       }
+               }
+               while (0);
+       }
 
        /* init itrset */
        itrset = palloc(sizeof(struct rt_iterator_t) * 2);
@@ -14125,6 +14258,7 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS)
                                hasnodata = rt_band_get_hasnodata_flag(_band);
                                if (hasnodata)
                                        nodataval = rt_band_get_nodata(_band);
+                               /* shouldn't this be rt_band_get_min_val(_band) */
                                else
                                        nodataval = 0;
                        }
@@ -14290,7 +14424,7 @@ Datum RASTER_union_finalfn(PG_FUNCTION_ARGS)
                else
                        status = rt_raster_copy_band(_rtn, _raster, 0, i);
 
-               POSTGIS_RT_DEBUG(3, "before destroy");
+               POSTGIS_RT_DEBUG(4, "destroying source rasters");
 
                /* destroy source rasters */
                if (iwr->bandarg[i].uniontype == UT_MEAN)
@@ -14302,7 +14436,6 @@ Datum RASTER_union_finalfn(PG_FUNCTION_ARGS)
                        rt_raster_destroy(iwr->bandarg[i].raster[j]);
                        iwr->bandarg[i].raster[j] = NULL;
                }
-               POSTGIS_RT_DEBUG(3, "after destroy");
 
                if (status < 0) {
                        elog(ERROR, "RASTER_union_finalfn: Unable to add band to final raster");
index 367718c1b925e6b87fa2400b7e5cb8acc18d0e85..339c81b6caf70f7c6a7c2a161d92c6fd2b079a6d 100644 (file)
@@ -310,5 +310,67 @@ FROM (
 ) foo
 ORDER BY uniontype, y, x;
 
+TRUNCATE raster_union_out;
+TRUNCATE raster_union_in;
+
+INSERT INTO raster_union_in
+       SELECT 50, NULL::raster AS rast UNION ALL
+       SELECT 51, NULL::raster AS rast UNION ALL
+       SELECT 52, ST_AddBand(ST_AddBand(ST_MakeEmptyRaster(2, 2, 0, 0, 1, -1, 0, 0, 0), 1, '8BUI', 1, 0), 2, '32BF', 100, -9999) AS rast UNION ALL
+       SELECT 53, ST_AddBand(ST_AddBand(ST_MakeEmptyRaster(2, 2, 1, -1, 1, -1, 0, 0, 0), 1, '8BUI', 2, 0), 2, '32BF', 200, -9999) AS rast UNION ALL
+       SELECT 54, NULL::raster AS rast UNION ALL
+       SELECT 55, ST_AddBand(ST_AddBand(ST_AddBand(ST_MakeEmptyRaster(2, 2, -1, 1, 1, -1, 0, 0, 0), 1, '8BUI', 3, 0), 2, '32BF', 300, -9999), 3, '8BSI', -1, -10) AS rast UNION ALL
+       SELECT 56, ST_AddBand(ST_AddBand(ST_MakeEmptyRaster(2, 2, 1, 1, 1, -1, 0, 0, 0), 1, '8BUI', 4, 0), 2, '32BF', 400, -9999) AS rast
+;
+
+INSERT INTO raster_union_out
+       SELECT
+               'LAST',
+               ST_Union(rast) AS rast
+       FROM raster_union_in;
+
+SELECT
+       (ST_Metadata(rast)).*
+FROM raster_union_out;
+
+SELECT
+       uniontype,
+       x,
+       y,
+       val
+FROM (
+       SELECT
+               uniontype,
+               (ST_PixelAsPoints(rast)).*
+       FROM raster_union_out
+) foo
+ORDER BY uniontype, y, x;
+
+SELECT
+       uniontype,
+       x,
+       y,
+       val
+FROM (
+       SELECT
+               uniontype,
+               (ST_PixelAsPoints(rast, 2)).*
+       FROM raster_union_out
+) foo
+ORDER BY uniontype, y, x;
+
+SELECT
+       uniontype,
+       x,
+       y,
+       val
+FROM (
+       SELECT
+               uniontype,
+               (ST_PixelAsPoints(rast, 3)).*
+       FROM raster_union_out
+) foo
+ORDER BY uniontype, y, x;
+
 DROP TABLE IF EXISTS raster_union_in;
 DROP TABLE IF EXISTS raster_union_out;
index 72f151440b2ac10988b5eb3b1f3fd170f444349e..f83b8235d9bd6aee549456ce984060a310bc9782 100644 (file)
@@ -513,3 +513,52 @@ 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|