From ecfd1ae3731cb4437301cfdc89e37f59f63c7b5e Mon Sep 17 00:00:00 2001 From: Bborie Park Date: Tue, 23 Oct 2012 22:44:28 +0000 Subject: [PATCH] Added rt_band_get_pixel_line() and regression tests git-svn-id: http://svn.osgeo.org/postgis/trunk@10533 b70326c6-7e19-0410-871a-916f4a2858ee --- raster/rt_core/rt_api.c | 86 ++++++++++++++++++++++++++++++++++++++ raster/rt_core/rt_api.h | 27 ++++++++++++ raster/test/core/testapi.c | 46 ++++++++++++++++++++ 3 files changed, 159 insertions(+) diff --git a/raster/rt_core/rt_api.c b/raster/rt_core/rt_api.c index 70e84e632..2a7e04968 100644 --- a/raster/rt_core/rt_api.c +++ b/raster/rt_core/rt_api.c @@ -2254,6 +2254,92 @@ rt_band_set_pixel( return rtn; } +/** + * Get values of multiple pixels. Unlike rt_band_get_pixel, + * values in vals are of the band's pixel type so cannot be + * assumed to be double. Function uses memcpy. + * + * It is important to be careful when using this function as + * the number of values being fetched may exceed a pixel "row". + * Remember that the band values are stored in a stream (1-D array) + * regardless of what the raster's width and height might be. + * So, getting a number of values may cross multiple pixel "rows". + * + * @param band : the band to get pixel value from + * @param x : pixel column (0-based) + * @param y : pixel row (0-based) + * @param len : the number of pixels to get + * @param vals : the pixel values + * @param *nvals : the number of pixel values being returned + * + * @return values of multiple pixels + */ +int rt_band_get_pixel_line( + rt_band band, + int x, int y, + uint16_t len, + void **vals, uint16_t *nvals +) { + uint8_t *_vals = NULL; + rt_pixtype pixtype = PT_END; + int pixsize = 0; + uint8_t *data = NULL; + uint32_t offset = 0; + uint16_t _nvals = 0; + int maxlen = 0; + uint8_t *ptr = NULL; + + assert(NULL != band); + + if ( + x < 0 || x >= band->width || + y < 0 || y >= band->height + ) { + rtwarn("Attempting to get pixel values with out of range raster coordinates: (%d, %d)", x, y); + return -1; + } + + data = rt_band_get_data(band); + if (data == NULL) { + rterror("rt_band_get_pixel_line: Cannot get band data"); + return -1; + } + + /* +1 for the nodata value */ + offset = x + (y * band->width); + RASTER_DEBUGF(4, "offset = %d", offset); + + pixtype = band->pixtype; + pixsize = rt_pixtype_size(band->pixtype); + RASTER_DEBUGF(4, "pixsize = %d", pixsize); + + /* cap _nvals so that it doesn't overflow */ + _nvals = len; + maxlen = band->width * band->height; + + if ((maxlen - (int) (offset + _nvals)) < 0) { + _nvals = _nvals - (((int) (offset + _nvals)) - maxlen); + rtwarn("Limiting returning number values to %d", _nvals); + } + RASTER_DEBUGF(4, "_nvals = %d", _nvals); + + ptr = data + (offset * pixsize); + + _vals = rtalloc(_nvals * pixsize); + if (_vals == NULL) { + rterror("rt_band_get_pixel_line: Unable to allocate memory for pixel values"); + return -1; + } + + /* copy pixels */ + memcpy(_vals, ptr, _nvals * pixsize); + + *vals = _vals; + *nvals = _nvals; + + return 0; +} + /** * Get pixel value. If band's isnodata flag is TRUE, value returned * will be the band's NODATA value diff --git a/raster/rt_core/rt_api.h b/raster/rt_core/rt_api.h index 47ac36640..88101f97d 100644 --- a/raster/rt_core/rt_api.h +++ b/raster/rt_core/rt_api.h @@ -598,6 +598,33 @@ int rt_band_set_pixel( double val ); +/** + * Get values of multiple pixels. Unlike rt_band_get_pixel, + * values in vals are of the band's pixel type so cannot be + * assumed to be double. Function uses memcpy. + * + * It is important to be careful when using this function as + * the number of values being fetched may exceed a pixel "row". + * Remember that the band values are stored in a stream (1-D array) + * regardless of what the raster's width and height might be. + * So, getting a number of values may cross multiple pixel "rows". + * + * @param band : the band to get pixel value from + * @param x : pixel column (0-based) + * @param y : pixel row (0-based) + * @param len : the number of pixels to get + * @param vals : the pixel values + * @param *nvals : the number of pixel values being returned + * + * @return 0 if success, -1 otherwise + */ +int rt_band_get_pixel_line( + rt_band band, + int x, int y, + uint16_t len, + void **vals, uint16_t *nvals +); + /** * Get pixel value. If band's isnodata flag is TRUE, value returned * will be the band's NODATA value diff --git a/raster/test/core/testapi.c b/raster/test/core/testapi.c index 4c80c2470..8210b1da4 100644 --- a/raster/test/core/testapi.c +++ b/raster/test/core/testapi.c @@ -8121,6 +8121,48 @@ static void testRasterClone() { deepRelease(rast1); } +static void testGetPixelLine() { + rt_raster rast; + rt_band band; + int maxX = 5; + int maxY = 5; + int x = 0; + int y = 0; + void *vals = NULL; + uint16_t nvals = 0; + int err = 0; + + rast = rt_raster_new(maxX, maxY); + assert(rast); + + rt_raster_set_scale(rast, 1, -1); + + band = addBand(rast, PT_8BSI, 0, 0); + CHECK(band); + + for (y = 0; y < maxY; y++) { + for (x = 0; x < maxX; x++) + rt_band_set_pixel(band, x, y, x + (y * maxX)); + } + + err = rt_band_get_pixel_line(band, 0, 0, maxX, &vals, &nvals); + CHECK((err == 0)); + CHECK((nvals == maxX)); + CHECK((((int8_t *) vals)[3] == 3)); + rtdealloc(vals); + + err = rt_band_get_pixel_line(band, 4, 4, maxX, &vals, &nvals); + CHECK((err == 0)); + CHECK((nvals == 1)); + CHECK((((int8_t *) vals)[0] == 24)); + rtdealloc(vals); + + err = rt_band_get_pixel_line(band, maxX, maxY, maxX, &vals, &nvals); + CHECK((err != 0)); + + deepRelease(rast); +} + int main() { @@ -8443,6 +8485,10 @@ main() testRasterClone(); printf("OK\n"); + printf("Test rt_band_get_pixel_line... "); + testGetPixelLine(); + printf("OK\n"); + deepRelease(raster); return EXIT_SUCCESS; -- 2.40.0