From 41ca87ef019df598f449859e94799ee984c8f35b Mon Sep 17 00:00:00 2001 From: Bborie Park Date: Mon, 16 May 2011 19:11:21 +0000 Subject: [PATCH] Addition of ST_Band functionality. - added function rt_raster_from_band to rt_core/rt_api.c and rt_api.h - added test case to test/core/testapi.c - added function RASTER_band to rt_pg/rt_pg.c - added SQL functions for ST_Band to rt_pg/rtpostgis.sql.in.c - added regression tests in test/regress Associated ticket is #339 and attached patch st_band.3.patch git-svn-id: http://svn.osgeo.org/postgis/trunk@7147 b70326c6-7e19-0410-871a-916f4a2858ee --- raster/rt_core/rt_api.c | 51 ++++++ raster/rt_core/rt_api.h | 15 ++ raster/rt_pg/rt_pg.c | 128 ++++++++++++++ raster/rt_pg/rtpostgis.sql.in.c | 28 +++ raster/test/core/testapi.c | 20 +++ raster/test/regress/Makefile.in | 1 + raster/test/regress/rt_band.sql | 256 +++++++++++++++++++++++++++ raster/test/regress/rt_band_expected | 20 +++ 8 files changed, 519 insertions(+) create mode 100644 raster/test/regress/rt_band.sql create mode 100644 raster/test/regress/rt_band_expected diff --git a/raster/rt_core/rt_api.c b/raster/rt_core/rt_api.c index 2c06efee6..dd5d58309 100644 --- a/raster/rt_core/rt_api.c +++ b/raster/rt_core/rt_api.c @@ -3850,3 +3850,54 @@ int32_t rt_raster_copy_band(rt_raster torast, return rt_raster_add_band(torast, newband, toindex); } +/** + * Construct a new rt_raster from an existing rt_raster and an array + * of band numbers + * + * @param raster : the source raster + * @param bandNums : array of band numbers to extract from source raster + * and add to the new raster (0 based) + * @param count : number of elements in bandNums + * + * @return a new rt_raster or 0 on error + */ +rt_raster +rt_raster_from_band(rt_raster raster, uint32_t *bandNums, int count) { + rt_raster rast = NULL; + int i = 0; + int idx; + int32_t flag; + + assert(NULL != raster); + assert(NULL != bandNums); + + RASTER_DEBUGF(3, "rt_raster_from_band: source raster has %d bands", + rt_raster_get_num_bands(raster)); + + /* create new raster */ + rast = rt_raster_new(raster->width, raster->height); + if (!rast) { + rterror("rt_raster_from_band: Out of memory allocating new raster\n"); + return 0; + } + + /* copy bands */ + for (i = 0; i < count; i++) { + idx = bandNums[i]; + flag = rt_raster_copy_band(rast, raster, idx, i); + + if (flag < 0) { + rterror("rt_raster_from_band: Unable to copy band\n"); + rt_raster_destroy(rast); + return 0; + } + + RASTER_DEBUGF(3, "rt_raster_from_band: band created at index %d", + flag); + } + + RASTER_DEBUGF(3, "rt_raster_from_band: new raster has %d bands", + rt_raster_get_num_bands(rast)); + return rast; +} + diff --git a/raster/rt_core/rt_api.h b/raster/rt_core/rt_api.h index 0f33e882c..9308b999e 100644 --- a/raster/rt_core/rt_api.h +++ b/raster/rt_core/rt_api.h @@ -757,6 +757,21 @@ int rt_raster_has_no_band(rt_raster raster, int nband); int32_t rt_raster_copy_band(rt_raster torast, rt_raster fromrast, int fromindex, int toindex); +/** + * Construct a new rt_raster from an existing rt_raster and an array + * of band numbers + * + * @param raster : the source raster + * @param bandNums : array of band numbers to extract from source raster + * and add to the new raster (0 based) + * @param count : number of elements in bandNums + * + * @return a new rt_raster or 0 on error + */ +rt_raster rt_raster_from_band(rt_raster raster, uint32_t *bandNums, + int count); + + /*- utilities -------------------------------------------------------*/ /* diff --git a/raster/rt_pg/rt_pg.c b/raster/rt_pg/rt_pg.c index 581a9ad46..8eeea487a 100644 --- a/raster/rt_pg/rt_pg.c +++ b/raster/rt_pg/rt_pg.c @@ -49,6 +49,10 @@ #include "rt_api.h" #include "../raster_config.h" +#include /* for get_typlenbyvalalign */ +#include /* for ArrayType */ +#include /* for INT2OID, INT4OID, FLOAT4OID, FLOAT8OID and TEXTOID */ + #define POSTGIS_RASTER_WARN_ON_TRUNCATION /* @@ -180,6 +184,9 @@ Datum RASTER_copyband(PG_FUNCTION_ARGS); /* Raster analysis */ Datum RASTER_mapAlgebra(PG_FUNCTION_ARGS); +/* create new raster from existing raster's bands */ +Datum RASTER_band(PG_FUNCTION_ARGS); + /* Replace function taken from * http://ubuntuforums.org/showthread.php?s=aa6f015109fd7e4c7e30d2fd8b717497&t=141670&page=3 @@ -2617,6 +2624,127 @@ Datum RASTER_mapAlgebra(PG_FUNCTION_ARGS) PG_RETURN_POINTER(pgraster); } +/** + * Return new raster from selected bands of existing raster through ST_Band. + * second argument is an array of band numbers (1 based) + */ +PG_FUNCTION_INFO_V1(RASTER_band); +Datum RASTER_band(PG_FUNCTION_ARGS) +{ + rt_pgraster *pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + rt_pgraster *pgrast; + rt_raster raster; + rt_raster rast; + + bool skip = FALSE; + ArrayType *array; + Oid etype; + Datum *e; + bool *nulls; + int16 typlen; + bool typbyval; + char typalign; + int ndims = 1; + int *dims; + int *lbs; + + uint32_t *bandNums; + uint32 idx = 0; + int n; + int i = 0; + int j = 0; + + raster = rt_raster_deserialize(pgraster); + if (!raster) { + elog(ERROR, "RASTER_band: Could not deserialize raster"); + PG_RETURN_NULL(); + } + + /* process bandNums */ + if (PG_ARGISNULL(1)) { + elog(NOTICE, "Band number(s) not provided. Returning original raster"); + skip = TRUE; + } + do { + if (skip) break; + + array = PG_GETARG_ARRAYTYPE_P(1); + etype = ARR_ELEMTYPE(array); + get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign); + + switch (etype) { + case INT2OID: + case INT4OID: + break; + default: + elog(ERROR, "RASTER_band: Invalid data type for band number(s)"); + rt_raster_destroy(raster); + PG_RETURN_NULL(); + break; + } + + ndims = ARR_NDIM(array); + dims = ARR_DIMS(array); + lbs = ARR_LBOUND(array); + + deconstruct_array(array, etype, typlen, typbyval, typalign, &e, + &nulls, &n); + + bandNums = (uint32_t *) palloc(sizeof(uint32_t) * n); + for (i = 0, j = 0; i < n; i++) { + if (nulls[i]) continue; + + switch (etype) { + case INT2OID: + idx = (uint32_t) DatumGetInt16(e[i]); + break; + case INT4OID: + idx = (uint32_t) DatumGetInt32(e[i]); + break; + } + + POSTGIS_RT_DEBUGF(3, "band idx (before): %d", idx); + if (idx > pgraster->numBands || idx < 1) { + elog(NOTICE, "Invalid band index (must use 1-based). Returning original raster"); + pfree(bandNums); + skip = TRUE; + } + if (skip) break; + + bandNums[j] = idx - 1; + POSTGIS_RT_DEBUGF(3, "bandNums[%d] = %d", j, bandNums[j]); + j++; + } + + if (skip || j < 1) { + pfree(bandNums); + skip = TRUE; + } + } + while (0); + + if (!skip) { + rast = rt_raster_from_band(raster, bandNums, j); + pfree(bandNums); + rt_raster_destroy(raster); + if (!rast) { + elog(ERROR, "RASTER_band: Could not create new raster"); + PG_RETURN_NULL(); + } + + pgrast = rt_raster_serialize(rast); + } + else { + pgrast = pgraster; + } + + if (!pgrast) + PG_RETURN_NULL(); + + SET_VARSIZE(pgrast, pgrast->size); + PG_RETURN_POINTER(pgrast); +} + /* ---------------------------------------------------------------- */ /* Memory allocation / error reporting hooks */ /* ---------------------------------------------------------------- */ diff --git a/raster/rt_pg/rtpostgis.sql.in.c b/raster/rt_pg/rtpostgis.sql.in.c index 109f6762d..5b8fd3210 100644 --- a/raster/rt_pg/rtpostgis.sql.in.c +++ b/raster/rt_pg/rtpostgis.sql.in.c @@ -228,6 +228,34 @@ CREATE OR REPLACE FUNCTION st_addband(torast raster, fromrast raster) AS 'select st_addband($1, $2, 1, NULL)' LANGUAGE 'SQL' IMMUTABLE STRICT; +----------------------------------------------------------------------- +-- Constructor ST_Band +----------------------------------------------------------------------- +CREATE OR REPLACE FUNCTION st_band(rast raster, nbands int[]) + RETURNS RASTER + AS 'MODULE_PATHNAME', 'RASTER_band' + LANGUAGE 'C' IMMUTABLE STRICT; + +CREATE OR REPLACE FUNCTION st_band(rast raster, nband int) + RETURNS RASTER + AS $$ SELECT st_band($1, ARRAY[$2]) $$ + LANGUAGE 'SQL' IMMUTABLE STRICT; + +CREATE OR REPLACE FUNCTION st_band(rast raster, nbands text) + RETURNS RASTER + AS $$ SELECT st_band($1, regexp_split_to_array(regexp_replace($2, '[[:space:]]', '', 'g'), ',')::int[]) $$ + LANGUAGE 'SQL' IMMUTABLE STRICT; + +CREATE OR REPLACE FUNCTION st_band(rast raster, nbands text, delimiter char) + RETURNS RASTER + AS $$ SELECT st_band($1, regexp_split_to_array(regexp_replace($2, '[[:space:]]', '', 'g'), $3)::int[]) $$ + LANGUAGE 'SQL' IMMUTABLE STRICT; + +CREATE OR REPLACE FUNCTION st_band(rast raster) + RETURNS RASTER + AS $$ SELECT st_band($1, ARRAY[1]) $$ + LANGUAGE 'SQL' IMMUTABLE STRICT; + ----------------------------------------------------------------------- -- MapAlgebra ----------------------------------------------------------------------- diff --git a/raster/test/core/testapi.c b/raster/test/core/testapi.c index 6c629db67..352dceb52 100644 --- a/raster/test/core/testapi.c +++ b/raster/test/core/testapi.c @@ -972,6 +972,21 @@ static void testBandHasNoData(rt_band band) CHECK_EQUALS(flag, 1); } +static void testRasterFromBand(rt_raster raster) { + uint32_t bandNums[] = {1,3}; + int lenBandNums = 2; + rt_raster rast; + + rast = rt_raster_from_band(raster, bandNums, lenBandNums); + assert(rast); + + CHECK(rast); + CHECK(!rt_raster_is_empty(rast)); + CHECK(!rt_raster_has_no_band(rast, 1)); + + rt_raster_destroy(rast); +} + int main() { @@ -1278,6 +1293,11 @@ main() printf("Testing band hasnodata flag\n"); testBandHasNoData(band_64BF); + printf("Testing rt_raster_from_band\n"); + testRasterFromBand(raster); + printf("Successfully tested rt_raster_from_band\n"); + + deepRelease(raster); return EXIT_SUCCESS; diff --git a/raster/test/regress/Makefile.in b/raster/test/regress/Makefile.in index 55cb78cc4..3cb356767 100644 --- a/raster/test/regress/Makefile.in +++ b/raster/test/regress/Makefile.in @@ -41,6 +41,7 @@ TEST_FUNC = \ create_rt_box2d_test.sql \ rt_box2d.sql \ rt_addband.sql \ + rt_band.sql \ $(NULL) TEST_PROPS = \ diff --git a/raster/test/regress/rt_band.sql b/raster/test/regress/rt_band.sql new file mode 100644 index 000000000..3f4825a26 --- /dev/null +++ b/raster/test/regress/rt_band.sql @@ -0,0 +1,256 @@ +SELECT ST_Value(ST_Band(ST_AddBand(ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0, -1), 1, '64BF', 123.4567, NULL), ARRAY[1]), 3, 3); +SELECT ST_Value(ST_Band(ST_AddBand(ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0, -1), 1, '64BF', 1234.567, NULL), 1), 3, 3); +SELECT ST_Value(ST_Band(ST_AddBand(ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0, -1), 1, '64BF', 1234.567, NULL)), 3, 3); +SELECT ST_Value( + ST_Band( + ST_AddBand( + ST_AddBand( + ST_AddBand( + ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0,-1) + , 1, '64BF', 1234.5678, NULL + ) + , '64BF', 987.654321, NULL + ) + , '64BF', 9876.54321, NULL + ), + ARRAY[1] + ), +3, 3); +SELECT ST_Value( + ST_Band( + ST_AddBand( + ST_AddBand( + ST_AddBand( + ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0,-1) + , 1, '64BF', 1234.5678, NULL + ) + , '64BF', 987.654321, NULL + ) + , '64BF', 9876.54321, NULL + ), + ARRAY[2] + ), +3, 3); +SELECT ST_Value( + ST_Band( + ST_AddBand( + ST_AddBand( + ST_AddBand( + ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0,-1) + , 1, '64BF', 1234.5678, NULL + ) + , '64BF', 987.654321, NULL + ) + , '64BF', 9876.54321, NULL + ), + ARRAY[3] + ), +3, 3); +SELECT ST_Value( + ST_Band( + ST_AddBand( + ST_AddBand( + ST_AddBand( + ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0,-1) + , 1, '64BF', 1234.5678, NULL + ) + , '64BF', 987.654321, NULL + ) + , '64BF', 9876.54321, NULL + ), + 1 + ), +3, 3); +SELECT ST_Value( + ST_Band( + ST_AddBand( + ST_AddBand( + ST_AddBand( + ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0,-1) + , 1, '64BF', 1234.5678, NULL + ) + , '64BF', 987.654321, NULL + ) + , '64BF', 9876.54321, NULL + ), + 2 + ), +3, 3); +SELECT ST_Value( + ST_Band( + ST_AddBand( + ST_AddBand( + ST_AddBand( + ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0,-1) + , 1, '64BF', 1234.5678, NULL + ) + , '64BF', 987.654321, NULL + ) + , '64BF', 9876.54321, NULL + ), + 3 + ), +3, 3); +SELECT ST_Value( + ST_Band( + ST_AddBand( + ST_AddBand( + ST_AddBand( + ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0,-1) + , 1, '64BF', 1234.5678, NULL + ) + , '64BF', 987.654321, NULL + ) + , '64BF', 9876.54321, NULL + ) + ), +3, 3); +SELECT ST_Value( + ST_Band( + ST_AddBand( + ST_AddBand( + ST_AddBand( + ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0,-1) + , 1, '64BF', 1234.5678, NULL + ) + , '64BF', 987.654321, NULL + ) + , '64BF', 9876.54321, NULL + ), + ARRAY[1,3] + ), +1, 3, 3); +SELECT ST_Value( + ST_Band( + ST_AddBand( + ST_AddBand( + ST_AddBand( + ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0,-1) + , 1, '64BF', 1234.5678, NULL + ) + , '64BF', 987.654321, NULL + ) + , '64BF', 9876.54321, NULL + ), + ARRAY[1,3] + ), +2, 3, 3); +SELECT ST_Value( + ST_Band( + ST_AddBand( + ST_AddBand( + ST_AddBand( + ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0,-1) + , 1, '64BF', 1234.5678, NULL + ) + , '64BF', 987.654321, NULL + ) + , '64BF', 9876.54321, NULL + ), + ARRAY[2,3] + ), +1, 3, 3); +SELECT ST_Value( + ST_Band( + ST_AddBand( + ST_AddBand( + ST_AddBand( + ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0,-1) + , 1, '64BF', 1234.5678, NULL + ) + , '64BF', 987.654321, NULL + ) + , '64BF', 9876.54321, NULL + ), + ARRAY[1,1] + ), +2, 3, 3); +SELECT ST_NumBands( + ST_Band( + ST_AddBand( + ST_AddBand( + ST_AddBand( + ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0,-1) + , 1, '64BF', 1234.5678, NULL + ) + , '64BF', 987.654321, NULL + ) + , '64BF', 9876.54321, NULL + ), + ARRAY[1,1,3,3] + ) +); +SELECT ST_NumBands( + ST_Band( + ST_AddBand( + ST_AddBand( + ST_AddBand( + ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0,-1) + , 1, '64BF', 1234.5678, NULL + ) + , '64BF', 987.654321, NULL + ) + , '64BF', 9876.54321, NULL + ), + ARRAY[1,1,3] + ) +); +SELECT ST_NumBands( + ST_Band( + ST_AddBand( + ST_AddBand( + ST_AddBand( + ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0,-1) + , 1, '64BF', 1234.5678, NULL + ) + , '64BF', 987.654321, NULL + ) + , '64BF', 9876.54321, NULL + ), + ARRAY[1,2] + ) +); +SELECT ST_NumBands( + ST_Band( + ST_AddBand( + ST_AddBand( + ST_AddBand( + ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0,-1) + , 1, '64BF', 1234.5678, NULL + ) + , '64BF', 987.654321, NULL + ) + , '64BF', 9876.54321, NULL + ), + ARRAY[3] + ) +); +SELECT ST_NumBands( + ST_Band( + ST_AddBand( + ST_AddBand( + ST_AddBand( + ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0,-1) + , 1, '64BF', 1234.5678, NULL + ) + , '64BF', 987.654321, NULL + ) + , '64BF', 9876.54321, NULL + ), + 2 + ) +); +SELECT ST_NumBands( + ST_Band( + ST_AddBand( + ST_AddBand( + ST_AddBand( + ST_MakeEmptyRaster(200, 200, 10, 10, 2, 2, 0, 0,-1) + , 1, '64BF', 1234.5678, NULL + ) + , '64BF', 987.654321, NULL + ) + , '64BF', 9876.54321, NULL + ) + ) +); diff --git a/raster/test/regress/rt_band_expected b/raster/test/regress/rt_band_expected new file mode 100644 index 000000000..ed11fccf2 --- /dev/null +++ b/raster/test/regress/rt_band_expected @@ -0,0 +1,20 @@ +123.4567 +1234.567 +1234.567 +1234.5678 +987.654321 +9876.54321 +1234.5678 +987.654321 +9876.54321 +1234.5678 +1234.5678 +9876.54321 +987.654321 +1234.5678 +4 +3 +2 +1 +1 +1 -- 2.50.1