From: Bborie Park Date: Wed, 3 Oct 2012 20:53:22 +0000 (+0000) Subject: Addition of ST_Union(raster) function and regression tests X-Git-Tag: 2.1.0beta2~588 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1fd8813cf3d709133a502c98ace85f5bfb5e44f2;p=postgis Addition of ST_Union(raster) function and regression tests git-svn-id: http://svn.osgeo.org/postgis/trunk@10370 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/raster/rt_pg/rt_pg.c b/raster/rt_pg/rt_pg.c index 7351cd7fa..dffbc6f4e 100644 --- a/raster/rt_pg/rt_pg.c +++ b/raster/rt_pg/rt_pg.c @@ -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"); diff --git a/raster/test/regress/rt_union.sql b/raster/test/regress/rt_union.sql index 367718c1b..339c81b6c 100644 --- a/raster/test/regress/rt_union.sql +++ b/raster/test/regress/rt_union.sql @@ -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; diff --git a/raster/test/regress/rt_union_expected b/raster/test/regress/rt_union_expected index 72f151440..f83b8235d 100644 --- a/raster/test/regress/rt_union_expected +++ b/raster/test/regress/rt_union_expected @@ -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|