From 6cc3ebb2d4b7adacb5166f3de0b4c4e238b31f86 Mon Sep 17 00:00:00 2001 From: Bborie Park Date: Fri, 26 Oct 2012 00:28:10 +0000 Subject: [PATCH] Rewrite of ST_Clip(raster) to be C-based and updated regression test. Ticket is #2065 git-svn-id: http://svn.osgeo.org/postgis/trunk@10568 b70326c6-7e19-0410-871a-916f4a2858ee --- raster/rt_pg/rt_pg.c | 599 ++++++++++++++++++- raster/rt_pg/rtpostgis.sql.in.c | 127 ++-- raster/test/regress/rt_clip_expected | 124 ++-- raster/test/regress/rt_summarystats_expected | 1 + 4 files changed, 687 insertions(+), 164 deletions(-) diff --git a/raster/rt_pg/rt_pg.c b/raster/rt_pg/rt_pg.c index bca35f09b..a41abc30c 100644 --- a/raster/rt_pg/rt_pg.c +++ b/raster/rt_pg/rt_pg.c @@ -362,6 +362,9 @@ Datum RASTER_nMapAlgebra(PG_FUNCTION_ARGS); Datum RASTER_union_transfn(PG_FUNCTION_ARGS); Datum RASTER_union_finalfn(PG_FUNCTION_ARGS); +/* raster clip */ +Datum RASTER_clip(PG_FUNCTION_ARGS); + /* string replacement function taken from * http://ubuntuforums.org/showthread.php?s=aa6f015109fd7e4c7e30d2fd8b717497&t=141670&page=3 */ @@ -2600,7 +2603,7 @@ Datum RASTER_dumpValues(PG_FUNCTION_ARGS) arg1->nbands = palloc(sizeof(int) * arg1->numbands); if (arg1->nbands == NULL) { - elog(ERROR, "RASTER_dumpValues: Unable to allocate memory for pixel values"); + elog(ERROR, "RASTER_dumpValues: Unable to allocate memory for band indexes"); rtpg_dumpvalues_arg_destroy(arg1); rt_raster_destroy(raster); PG_FREE_IF_COPY(pgraster, 0); @@ -2626,7 +2629,7 @@ Datum RASTER_dumpValues(PG_FUNCTION_ARGS) if (j < arg1->numbands) { arg1->nbands = repalloc(arg1->nbands, sizeof(int) * j); if (arg1->nbands == NULL) { - elog(ERROR, "RASTER_dumpValues: Unable to reallocate memory for pixel values"); + elog(ERROR, "RASTER_dumpValues: Unable to reallocate memory for band indexes"); rtpg_dumpvalues_arg_destroy(arg1); rt_raster_destroy(raster); PG_FREE_IF_COPY(pgraster, 0); @@ -2655,7 +2658,7 @@ Datum RASTER_dumpValues(PG_FUNCTION_ARGS) arg1->nbands = palloc(sizeof(int) * arg1->numbands); if (arg1->nbands == NULL) { - elog(ERROR, "RASTER_dumpValues: Unable to allocate memory for pixel values"); + elog(ERROR, "RASTER_dumpValues: Unable to allocate memory for band indexes"); rtpg_dumpvalues_arg_destroy(arg1); rt_raster_destroy(raster); PG_FREE_IF_COPY(pgraster, 0); @@ -3138,17 +3141,6 @@ Datum RASTER_setPixelValuesArray(PG_FUNCTION_ARGS) case FLOAT8OID: pixval[i].value = DatumGetFloat8(elements[i]); break; - default: - elog(ERROR, "RASTER_setPixelValuesArray: Invalid data type for new values"); - - pfree(elements); - pfree(nulls); - pfree(pixval); - - rt_raster_destroy(raster); - pfree(pgraster); - PG_RETURN_NULL(); - break; } } @@ -3639,6 +3631,13 @@ Datum RASTER_setPixelValuesGeomval(PG_FUNCTION_ARGS) PG_RETURN_POINTER(pgraster); } + /* Get a 2D version of the geometry if necessary */ + if (lwgeom_ndims(arg->gv[arg->ngv].geom) > 2) { + LWGEOM *geom2d = lwgeom_force_2d(arg->gv[arg->ngv].geom); + lwgeom_free(arg->gv[arg->ngv].geom); + arg->gv[arg->ngv].geom = geom2d; + } + /* filter for types */ gtype = gserialized_get_type(gser); @@ -3679,6 +3678,9 @@ Datum RASTER_setPixelValuesGeomval(PG_FUNCTION_ARGS) PG_RETURN_NULL(); } + /* set SRID */ + rt_raster_set_srid(arg->gv[arg->ngv].mask, srid); + /* second element, value */ POSTGIS_RT_DEBUG(4, "Processing second element (val)"); tupv = GetAttributeByName(tup, "val", &isnull); @@ -3836,7 +3838,24 @@ Datum RASTER_setPixelValuesGeomval(PG_FUNCTION_ARGS) /* copy band from _raster to raster */ _band = rt_raster_get_band(_raster, 0); - _band = rt_raster_replace_band(raster, _band, nband -1); + if (_band == NULL) { + elog(ERROR, "RASTER_setPixelValuesGeomval: Unable to get band from working raster"); + rtpg_setvaluesgv_arg_destroy(arg); + rt_raster_destroy(_raster); + rt_raster_destroy(raster); + PG_FREE_IF_COPY(pgraster, 0); + PG_RETURN_NULL(); + } + + _band = rt_raster_replace_band(raster, _band, nband - 1); + if (_band == NULL) { + elog(ERROR, "RASTER_setPixelValuesGeomval: Unable to replace band in output raster"); + rtpg_setvaluesgv_arg_destroy(arg); + rt_raster_destroy(_raster); + rt_raster_destroy(raster); + PG_FREE_IF_COPY(pgraster, 0); + PG_RETURN_NULL(); + } rt_band_destroy(_band); rt_raster_destroy(_raster); @@ -4496,7 +4515,7 @@ Datum RASTER_nearestValue(PG_FUNCTION_ARGS) exclude_nodata_value = PG_GETARG_BOOL(3); /* SRIDs of raster and geometry must match */ - if (gserialized_get_srid(geom) != rt_raster_get_srid(raster)) { + if (clamp_srid(gserialized_get_srid(geom)) != clamp_srid(rt_raster_get_srid(raster))) { elog(NOTICE, "SRIDs of geometry and raster do not match"); rt_raster_destroy(raster); PG_FREE_IF_COPY(pgraster, 0); @@ -4525,6 +4544,13 @@ Datum RASTER_nearestValue(PG_FUNCTION_ARGS) PG_RETURN_NULL(); } + /* Get a 2D version of the geometry if necessary */ + if (lwgeom_ndims(lwgeom) > 2) { + LWGEOM *lwgeom2d = lwgeom_force_2d(lwgeom); + lwgeom_free(lwgeom); + lwgeom = lwgeom2d; + } + point = lwgeom_as_lwpoint(lwgeom); getPoint2d_p(point->point, 0, &p); @@ -16431,6 +16457,547 @@ Datum RASTER_union_finalfn(PG_FUNCTION_ARGS) PG_RETURN_POINTER(pgraster); } +/* ---------------------------------------------------------------- */ +/* Clip raster with geometry */ +/* ---------------------------------------------------------------- */ + +typedef struct rtpg_clip_band_t *rtpg_clip_band; +struct rtpg_clip_band_t { + int nband; /* band index */ + int hasnodata; /* is there a user-specified NODATA? */ + double nodataval; /* user-specified NODATA */ +}; + +typedef struct rtpg_clip_arg_t *rtpg_clip_arg; +struct rtpg_clip_arg_t { + rt_extenttype extenttype; + rt_raster raster; + rt_raster mask; + + int numbands; /* number of bandargs */ + rtpg_clip_band band; +}; + +static rtpg_clip_arg rtpg_clip_arg_init() { + rtpg_clip_arg arg = NULL; + + arg = palloc(sizeof(struct rtpg_clip_arg_t)); + if (arg == NULL) { + elog(ERROR, "rtpg_clip_arg_init: Unable to allocate memory for function arguments"); + return NULL; + } + + arg->extenttype = ET_INTERSECTION; + arg->raster = NULL; + arg->mask = NULL; + arg->numbands = 0; + arg->band = NULL; + + return arg; +} + +static void rtpg_clip_arg_destroy(rtpg_clip_arg arg) { + if (arg->band != NULL) + pfree(arg->band); + + if (arg->raster != NULL) + rt_raster_destroy(arg->raster); + if (arg->mask != NULL) + rt_raster_destroy(arg->mask); + + pfree(arg); +} + +static int rtpg_clip_callback( + rt_iterator_arg arg, void *userarg, + double *value, int *nodata +) { + *value = 0; + *nodata = 0; + + /* either is NODATA, output is NODATA */ + if (arg->nodata[0][0][0] || arg->nodata[1][0][0]) + *nodata = 1; + /* set to value */ + else + *value = arg->values[0][0][0]; + + return 1; +} + +PG_FUNCTION_INFO_V1(RASTER_clip); +Datum RASTER_clip(PG_FUNCTION_ARGS) +{ + rt_pgraster *pgraster = NULL; + LWGEOM *rastgeom = NULL; + double gt[6] = {0}; + int srid = SRID_UNKNOWN; + + rt_pgraster *pgrtn = NULL; + rt_raster rtn = NULL; + + GSERIALIZED *gser = NULL; + LWGEOM *geom = NULL; + unsigned char *wkb = NULL; + size_t wkb_len; + + ArrayType *array; + Oid etype; + Datum *e; + bool *nulls; + + int16 typlen; + bool typbyval; + char typalign; + + int i = 0; + int j = 0; + int k = 0; + rtpg_clip_arg arg = NULL; + LWGEOM *tmpgeom = NULL; + rt_iterator itrset; + + rt_raster _raster = NULL; + rt_band band = NULL; + rt_pixtype pixtype; + int hasnodata; + double nodataval; + int noerr = 0; + + POSTGIS_RT_DEBUG(3, "Starting..."); + + /* raster or geometry is NULL, return NULL */ + if (PG_ARGISNULL(0) || PG_ARGISNULL(2)) + PG_RETURN_NULL(); + + /* init arg */ + arg = rtpg_clip_arg_init(); + if (arg == NULL) { + elog(ERROR, "RASTER_clip: Unable to initialize argument structure"); + PG_RETURN_NULL(); + } + + /* raster (0) */ + pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + + /* Get raster object */ + arg->raster = rt_raster_deserialize(pgraster, FALSE); + if (arg->raster == NULL) { + elog(ERROR, "RASTER_clip: Could not deserialize raster"); + rtpg_clip_arg_destroy(arg); + PG_FREE_IF_COPY(pgraster, 0); + PG_RETURN_NULL(); + } + + /* raster is empty, return empty raster */ + if (rt_raster_is_empty(arg->raster)) { + elog(NOTICE, "Input raster is empty. Returning empty raster"); + + rtpg_clip_arg_destroy(arg); + PG_FREE_IF_COPY(pgraster, 0); + + rtn = rt_raster_new(0, 0); + if (rtn == NULL) { + elog(ERROR, "RASTER_clip: Unable to create empty raster"); + PG_RETURN_NULL(); + } + + pgrtn = rt_raster_serialize(rtn); + rt_raster_destroy(rtn); + if (NULL == pgrtn) + PG_RETURN_NULL(); + + SET_VARSIZE(pgrtn, pgrtn->size); + PG_RETURN_POINTER(pgrtn); + } + + /* metadata */ + rt_raster_get_geotransform_matrix(arg->raster, gt); + srid = clamp_srid(rt_raster_get_srid(arg->raster)); + + /* geometry (2) */ + gser = (GSERIALIZED *) PG_DETOAST_DATUM(PG_GETARG_DATUM(2)); + geom = lwgeom_from_gserialized(gser); + + /* Get a 2D version of the geometry if necessary */ + if (lwgeom_ndims(geom) > 2) { + LWGEOM *geom2d = lwgeom_force_2d(geom); + lwgeom_free(geom); + geom = geom2d; + } + + /* check that SRIDs match */ + if (srid != clamp_srid(gserialized_get_srid(gser))) { + elog(NOTICE, "Geometry provided does not have the same SRID as the raster. Returning NULL"); + + rtpg_clip_arg_destroy(arg); + PG_FREE_IF_COPY(pgraster, 0); + lwgeom_free(geom); + PG_FREE_IF_COPY(gser, 2); + + PG_RETURN_NULL(); + } + + /* crop (4) */ + if (!PG_ARGISNULL(4) && !PG_GETARG_BOOL(4)) + arg->extenttype = ET_FIRST; + + /* get intersection geometry of input raster and input geometry */ + rastgeom = lwpoly_as_lwgeom(rt_raster_get_convex_hull(arg->raster)); + if (rastgeom == NULL) { + elog(ERROR, "RASTER_clip: Unable to get convex hull of raster"); + + rtpg_clip_arg_destroy(arg); + PG_FREE_IF_COPY(pgraster, 0); + lwgeom_free(geom); + PG_FREE_IF_COPY(gser, 2); + + PG_RETURN_NULL(); + } + + tmpgeom = lwgeom_intersection(rastgeom, geom); + lwgeom_free(rastgeom); + lwgeom_free(geom); + PG_FREE_IF_COPY(gser, 2); + geom = tmpgeom; + + /* intersection is empty AND extent type is INTERSECTION, return empty */ + if (lwgeom_is_empty(geom) && arg->extenttype == ET_INTERSECTION) { + elog(NOTICE, "The input raster and input geometry do not intersect. Returning empty raster"); + + rtpg_clip_arg_destroy(arg); + PG_FREE_IF_COPY(pgraster, 0); + lwgeom_free(geom); + + rtn = rt_raster_new(0, 0); + if (rtn == NULL) { + elog(ERROR, "RASTER_clip: Unable to create empty raster"); + PG_RETURN_NULL(); + } + + pgrtn = rt_raster_serialize(rtn); + rt_raster_destroy(rtn); + if (NULL == pgrtn) + PG_RETURN_NULL(); + + SET_VARSIZE(pgrtn, pgrtn->size); + PG_RETURN_POINTER(pgrtn); + } + + /* nband (1) */ + if (!PG_ARGISNULL(1)) { + 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_clip: Invalid data type for band indexes"); + rtpg_clip_arg_destroy(arg); + PG_FREE_IF_COPY(pgraster, 0); + lwgeom_free(geom); + PG_RETURN_NULL(); + break; + } + + deconstruct_array( + array, etype, + typlen, typbyval, typalign, + &e, &nulls, &(arg->numbands) + ); + + arg->band = palloc(sizeof(struct rtpg_clip_band_t) * arg->numbands); + if (arg->band == NULL) { + elog(ERROR, "RASTER_clip: Unable to allocate memory for band arguments"); + rtpg_clip_arg_destroy(arg); + PG_FREE_IF_COPY(pgraster, 0); + lwgeom_free(geom); + PG_RETURN_NULL(); + } + + for (i = 0, j = 0; i < arg->numbands; i++) { + if (nulls[i]) continue; + + switch (etype) { + case INT2OID: + arg->band[j].nband = DatumGetInt16(e[i]) - 1; + break; + case INT4OID: + arg->band[j].nband = DatumGetInt32(e[i]) - 1; + break; + } + + j++; + } + + if (j < arg->numbands) { + arg->band = repalloc(arg->band, sizeof(struct rtpg_clip_band_t) * j); + if (arg->band == NULL) { + elog(ERROR, "RASTER_clip: Unable to reallocate memory for band arguments"); + rtpg_clip_arg_destroy(arg); + PG_FREE_IF_COPY(pgraster, 0); + lwgeom_free(geom); + PG_RETURN_NULL(); + } + + arg->numbands = j; + } + + /* validate band */ + for (i = 0; i < arg->numbands; i++) { + if (!rt_raster_has_band(arg->raster, arg->band[i].nband)) { + elog(NOTICE, "Band at index %d not found in raster", arg->band[i].nband + 1); + rtpg_clip_arg_destroy(arg); + PG_FREE_IF_COPY(pgraster, 0); + lwgeom_free(geom); + PG_RETURN_NULL(); + } + + arg->band[i].hasnodata = 0; + arg->band[i].nodataval = 0; + } + } + else { + arg->numbands = rt_raster_get_num_bands(arg->raster); + + /* raster may have no bands */ + if (arg->numbands) { + arg->band = palloc(sizeof(struct rtpg_clip_band_t) * arg->numbands); + if (arg->band == NULL) { + elog(ERROR, "RASTER_clip: Unable to allocate memory for band arguments"); + + + rtpg_clip_arg_destroy(arg); + PG_FREE_IF_COPY(pgraster, 0); + lwgeom_free(geom); + + PG_RETURN_NULL(); + } + + for (i = 0; i < arg->numbands; i++) { + arg->band[i].nband = i; + arg->band[i].hasnodata = 0; + arg->band[i].nodataval = 0; + } + } + } + + /* nodataval (3) */ + if (!PG_ARGISNULL(3)) { + array = PG_GETARG_ARRAYTYPE_P(3); + etype = ARR_ELEMTYPE(array); + get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign); + + switch (etype) { + case FLOAT4OID: + case FLOAT8OID: + break; + default: + elog(ERROR, "RASTER_clip: Invalid data type for NODATA values"); + rtpg_clip_arg_destroy(arg); + PG_FREE_IF_COPY(pgraster, 0); + lwgeom_free(geom); + PG_RETURN_NULL(); + break; + } + + deconstruct_array( + array, etype, + typlen, typbyval, typalign, + &e, &nulls, &k + ); + + /* it doesn't matter if there are more nodataval */ + for (i = 0, j = 0; i < arg->numbands; i++, j++) { + /* cap j to the last nodataval element */ + if (j >= k) + j = k - 1; + + if (nulls[j]) + continue; + + arg->band[i].hasnodata = 1; + switch (etype) { + case FLOAT4OID: + arg->band[i].nodataval = DatumGetFloat4(e[j]); + break; + case FLOAT8OID: + arg->band[i].nodataval = DatumGetFloat8(e[j]); + break; + } + } + } + + /* get wkb of geometry */ + POSTGIS_RT_DEBUG(3, "getting wkb of geometry"); + wkb = lwgeom_to_wkb(geom, WKB_SFSQL, &wkb_len); + lwgeom_free(geom); + + /* rasterize geometry */ + arg->mask = rt_raster_gdal_rasterize( + wkb, wkb_len, + NULL, + 0, NULL, + NULL, NULL, + NULL, NULL, + NULL, NULL, + &(gt[1]), &(gt[5]), + NULL, NULL, + &(gt[0]), &(gt[3]), + &(gt[2]), &(gt[4]), + NULL + ); + + pfree(wkb); + if (arg->mask == NULL) { + elog(ERROR, "RASTER_clip: Unable to rasterize intersection geometry"); + rtpg_clip_arg_destroy(arg); + PG_FREE_IF_COPY(pgraster, 0); + PG_RETURN_NULL(); + } + + /* set SRID */ + rt_raster_set_srid(arg->mask, srid); + + /* run iterator */ + + /* init itrset */ + itrset = palloc(sizeof(struct rt_iterator_t) * 2); + if (itrset == NULL) { + elog(ERROR, "RASTER_clip: Unable to allocate memory for iterator arguments"); + rtpg_clip_arg_destroy(arg); + PG_FREE_IF_COPY(pgraster, 0); + PG_RETURN_NULL(); + } + + /* one band at a time */ + for (i = 0; i < arg->numbands; i++) { + POSTGIS_RT_DEBUGF(4, "band arg %d (nband, hasnodata, nodataval) = (%d, %d, %f)", + i, arg->band[i].nband, arg->band[i].hasnodata, arg->band[i].nodataval); + + band = rt_raster_get_band(arg->raster, arg->band[i].nband); + + /* band metadata */ + pixtype = rt_band_get_pixtype(band); + + if (arg->band[i].hasnodata) { + hasnodata = 1; + nodataval = arg->band[i].nodataval; + } + else if (rt_band_get_hasnodata_flag(band)) { + hasnodata = 1; + rt_band_get_nodata(band, &nodataval); + } + else { + hasnodata = 0; + nodataval = rt_band_get_min_value(band); + } + + /* band is NODATA, create NODATA band and continue */ + if (rt_band_get_isnodata_flag(band)) { + /* create raster */ + if (rtn == NULL) { + rtn = rt_raster_from_two_rasters(arg->raster, arg->mask, arg->extenttype, &noerr, NULL); + if (!noerr) { + elog(ERROR, "RASTER_clip: Unable to create output raster"); + rtpg_clip_arg_destroy(arg); + PG_FREE_IF_COPY(pgraster, 0); + PG_RETURN_NULL(); + } + } + + /* create NODATA band */ + if (rt_raster_generate_new_band(rtn, pixtype, nodataval, hasnodata, nodataval, i) < 0) { + elog(ERROR, "RASTER_clip: Unable to add NODATA band to output raster"); + rt_raster_destroy(rtn); + rtpg_clip_arg_destroy(arg); + PG_FREE_IF_COPY(pgraster, 0); + PG_RETURN_NULL(); + } + + continue; + } + + /* raster */ + itrset[0].raster = arg->raster; + itrset[0].nband = arg->band[i].nband; + itrset[0].nbnodata = 1; + + /* mask */ + itrset[1].raster = arg->mask; + itrset[1].nband = 0; + itrset[1].nbnodata = 1; + + /* pass to iterator */ + _raster = rt_raster_iterator( + itrset, 2, + arg->extenttype, NULL, + pixtype, + hasnodata, nodataval, + 0, 0, + NULL, + rtpg_clip_callback, + &noerr + ); + + if (!noerr) { + elog(ERROR, "RASTER_clip: Unable to run raster iterator function"); + pfree(itrset); + rtpg_clip_arg_destroy(arg); + if (rtn != NULL) rt_raster_destroy(rtn); + PG_FREE_IF_COPY(pgraster, 0); + PG_RETURN_NULL(); + } + + /* new raster */ + if (rtn == NULL) + rtn = _raster; + /* copy band */ + else { + band = rt_raster_get_band(_raster, 0); + if (band == NULL) { + elog(ERROR, "RASTER_clip: Unable to get band from working raster"); + pfree(itrset); + rtpg_clip_arg_destroy(arg); + rt_raster_destroy(_raster); + rt_raster_destroy(rtn); + PG_FREE_IF_COPY(pgraster, 0); + PG_RETURN_NULL(); + } + + if (rt_raster_add_band(rtn, band, i) < 0) { + elog(ERROR, "RASTER_clip: Unable to add new band to output raster"); + pfree(itrset); + rtpg_clip_arg_destroy(arg); + rt_raster_destroy(_raster); + rt_raster_destroy(rtn); + PG_FREE_IF_COPY(pgraster, 0); + PG_RETURN_NULL(); + } + + rt_raster_destroy(_raster); + } + } + + pfree(itrset); + rtpg_clip_arg_destroy(arg); + PG_FREE_IF_COPY(pgraster, 0); + + pgrtn = rt_raster_serialize(rtn); + rt_raster_destroy(rtn); + + POSTGIS_RT_DEBUG(3, "Finished"); + + if (!pgrtn) + PG_RETURN_NULL(); + + SET_VARSIZE(pgrtn, pgrtn->size); + PG_RETURN_POINTER(pgrtn); +} + /* ---------------------------------------------------------------- */ /* Memory allocation / error reporting hooks */ /* ---------------------------------------------------------------- */ diff --git a/raster/rt_pg/rtpostgis.sql.in.c b/raster/rt_pg/rtpostgis.sql.in.c index c21196efa..68442d781 100644 --- a/raster/rt_pg/rtpostgis.sql.in.c +++ b/raster/rt_pg/rtpostgis.sql.in.c @@ -5442,108 +5442,63 @@ CREATE AGGREGATE st_union(raster, text) ( FINALFUNC = _st_union_finalfn ); -------------------------------------------------------------------- --- ST_Clip(rast raster, band int, geom geometry, nodata float8 DEFAULT null, crop boolean DEFAULT true) --- Clip the values of a raster to the shape of a polygon. --- --- rast - raster to be clipped --- band - limit the result to only one band --- geom - geometry defining the shape to clip the raster --- nodata - define (if there is none defined) or replace the raster nodata value with this value --- crop - limit the extent of the result to the extent of the geometry ----------------------------------------------------------------------- -- ST_Clip ----------------------------------------------------------------------- --- nodataval as array series --- Major variant -CREATE OR REPLACE FUNCTION st_clip(rast raster, band int, geom geometry, nodataval double precision[] DEFAULT NULL, crop boolean DEFAULT TRUE) +CREATE OR REPLACE FUNCTION st_clip( + rast raster, nband integer[], + geom geometry, + nodataval double precision[] DEFAULT NULL, crop boolean DEFAULT TRUE +) RETURNS raster - AS $$ - DECLARE - g geometry; - newrast raster; - geomrast raster; - numband int; - bandstart int; - bandend int; - newextent text; - newnodataval double precision; - newpixtype text; - bandi int; - BEGIN - IF rast IS NULL THEN - RETURN NULL; - END IF; - IF geom IS NULL THEN - RETURN rast; - END IF; - numband := ST_Numbands(rast); - IF band IS NULL THEN - bandstart := 1; - bandend := numband; - ELSEIF ST_HasNoBand(rast, band) THEN - RAISE NOTICE 'Raster do not have band %. Returning null', band; - RETURN NULL; - ELSE - bandstart := band; - bandend := band; - END IF; - - newpixtype := ST_BandPixelType(rast, bandstart); - newnodataval := coalesce(nodataval[1], ST_BandNodataValue(rast, bandstart), ST_MinPossibleValue(newpixtype)); - newextent := CASE WHEN crop THEN 'INTERSECTION' ELSE 'FIRST' END; - - -- Convert the geometry to a raster - g := ST_Intersection(geom, rast::geometry); - geomrast := ST_AsRaster(g, rast, ST_BandPixelType(rast, band), 1, newnodataval); - - -- Compute the first raster band - newrast := ST_MapAlgebraExpr(rast, bandstart, geomrast, 1, '[rast1.val]', newpixtype, newextent, newnodataval::text, newnodataval::text, newnodataval); - -- Set the newnodataval - newrast := ST_SetBandNodataValue(newrast, bandstart, newnodataval); - - FOR bandi IN bandstart+1..bandend LOOP - -- for each band we must determine the nodata value - newpixtype := ST_BandPixelType(rast, bandi); - newnodataval := coalesce(nodataval[bandi], nodataval[array_upper(nodataval, 1)], ST_BandNodataValue(rast, bandi), ST_MinPossibleValue(newpixtype)); - newrast := ST_AddBand(newrast, ST_MapAlgebraExpr(rast, bandi, geomrast, 1, '[rast1.val]', newpixtype, newextent, newnodataval::text, newnodataval::text, newnodataval)); - newrast := ST_SetBandNodataValue(newrast, bandi, newnodataval); - END LOOP; - - RETURN newrast; - END; - $$ LANGUAGE 'plpgsql' STABLE; + AS 'MODULE_PATHNAME', 'RASTER_clip' + LANGUAGE 'c' IMMUTABLE; --- Nodata values as integer series -CREATE OR REPLACE FUNCTION st_clip(rast raster, band int, geom geometry, nodataval double precision, crop boolean DEFAULT TRUE) +CREATE OR REPLACE FUNCTION st_clip( + rast raster, nband integer, + geom geometry, + nodataval double precision, crop boolean DEFAULT TRUE +) RETURNS raster AS - $$ SELECT ST_Clip($1, $2, $3, ARRAY[$4], $5) $$ - LANGUAGE 'sql' STABLE; + $$ SELECT ST_Clip($1, ARRAY[$2]::integer[], $3, ARRAY[$4]::double precision[], $5) $$ + LANGUAGE 'sql' IMMUTABLE; --- Variant defaulting nodataval to the one of the raster or the min possible value -CREATE OR REPLACE FUNCTION st_clip(rast raster, band int, geom geometry, crop boolean) +CREATE OR REPLACE FUNCTION st_clip( + rast raster, nband integer, + geom geometry, + crop boolean +) RETURNS raster AS - $$ SELECT ST_Clip($1, $2, $3, null::float8[], $4) $$ - LANGUAGE 'sql' STABLE; + $$ SELECT ST_Clip($1, ARRAY[$2]::integer[], $3, null::double precision[], $4) $$ + LANGUAGE 'sql' IMMUTABLE; --- Variant defaulting to all bands -CREATE OR REPLACE FUNCTION st_clip(rast raster, geom geometry, nodataval double precision[] DEFAULT NULL, crop boolean DEFAULT TRUE) +CREATE OR REPLACE FUNCTION st_clip( + rast raster, + geom geometry, + nodataval double precision[] DEFAULT NULL, crop boolean DEFAULT TRUE +) RETURNS raster AS $$ SELECT ST_Clip($1, NULL, $2, $3, $4) $$ - LANGUAGE 'sql' STABLE; + LANGUAGE 'sql' IMMUTABLE; --- Variant defaulting to all bands -CREATE OR REPLACE FUNCTION st_clip(rast raster, geom geometry, nodataval double precision, crop boolean DEFAULT TRUE) +CREATE OR REPLACE FUNCTION st_clip( + rast raster, + geom geometry, + nodataval double precision, crop boolean DEFAULT TRUE +) RETURNS raster AS - $$ SELECT ST_Clip($1, NULL, $2, ARRAY[$3], $4) $$ - LANGUAGE 'sql' STABLE; + $$ SELECT ST_Clip($1, NULL, $2, ARRAY[$3]::double precision[], $4) $$ + LANGUAGE 'sql' IMMUTABLE; --- Variant defaulting nodataval to the one of the raster or the min possible value and returning all bands -CREATE OR REPLACE FUNCTION st_clip(rast raster, geom geometry, crop boolean) +CREATE OR REPLACE FUNCTION st_clip( + rast raster, + geom geometry, + crop boolean +) RETURNS raster AS - $$ SELECT ST_Clip($1, NULL, $2, null::float8[], $3) $$ - LANGUAGE 'sql' STABLE; + $$ SELECT ST_Clip($1, NULL, $2, null::double precision[], $3) $$ + LANGUAGE 'sql' IMMUTABLE; ----------------------------------------------------------------------- -- ST_NearestValue diff --git a/raster/test/regress/rt_clip_expected b/raster/test/regress/rt_clip_expected index 676a8fff9..9d71b6851 100644 --- a/raster/test/regress/rt_clip_expected +++ b/raster/test/regress/rt_clip_expected @@ -8,12 +8,12 @@ 1|2|3|0.000|0.000|4|4|1.000|-1.000|0.000|0.000|0|3|8BUI|0.000 1|2|4|0.000|0.000|4|4|1.000|-1.000|0.000|0.000|0|3|8BUI|0.000 1|2|5|0.000|0.000|4|4|1.000|-1.000|0.000|0.000|0|3|8BUI|0.000 -2|1|1|0.000|0.000|0|0|0.000|0.000|0.000|0.000|0|0|| +2|1|1|0.000|0.000|0|0|1.000|-1.000|0.000|0.000|0|0|| 2|1|2|2.000|-1.000|2|2|1.000|-1.000|0.000|0.000|0|1|8BUI|0.000 2|1|3|1.000|-1.000|2|2|1.000|-1.000|0.000|0.000|0|1|8BUI|0.000 2|1|4|1.000|0.000|3|4|1.000|-1.000|0.000|0.000|0|1|8BUI|0.000 2|1|5|0.000|0.000|4|4|1.000|-1.000|0.000|0.000|0|1|8BUI|0.000 -2|2|1|0.000|0.000|0|0|0.000|0.000|0.000|0.000|0|0|| +2|2|1|0.000|0.000|0|0|1.000|-1.000|0.000|0.000|0|0|| 2|2|2|2.000|-1.000|2|2|1.000|-1.000|0.000|0.000|0|3|8BUI|0.000 2|2|3|1.000|-1.000|2|2|1.000|-1.000|0.000|0.000|0|3|8BUI|0.000 2|2|4|1.000|0.000|3|4|1.000|-1.000|0.000|0.000|0|3|8BUI|0.000 @@ -28,12 +28,12 @@ 3|2|3|0.000|0.000|4|4|1.000|-1.000|0.000|0.000|0|3|8BUI|255.000 3|2|4|0.000|0.000|4|4|1.000|-1.000|0.000|0.000|0|3|8BUI|255.000 3|2|5|0.000|0.000|4|4|1.000|-1.000|0.000|0.000|0|3|8BUI|255.000 -4|1|1|0.000|0.000|0|0|0.000|0.000|0.000|0.000|0|0|| +4|1|1|0.000|0.000|0|0|1.000|-1.000|0.000|0.000|0|0|| 4|1|2|2.000|-1.000|2|2|1.000|-1.000|0.000|0.000|0|1|8BUI|255.000 4|1|3|1.000|-1.000|2|2|1.000|-1.000|0.000|0.000|0|1|8BUI|255.000 4|1|4|1.000|0.000|3|4|1.000|-1.000|0.000|0.000|0|1|8BUI|255.000 4|1|5|0.000|0.000|4|4|1.000|-1.000|0.000|0.000|0|1|8BUI|255.000 -4|2|1|0.000|0.000|0|0|0.000|0.000|0.000|0.000|0|0|| +4|2|1|0.000|0.000|0|0|1.000|-1.000|0.000|0.000|0|0|| 4|2|2|2.000|-1.000|2|2|1.000|-1.000|0.000|0.000|0|3|8BUI|255.000 4|2|3|1.000|-1.000|2|2|1.000|-1.000|0.000|0.000|0|3|8BUI|255.000 4|2|4|1.000|0.000|3|4|1.000|-1.000|0.000|0.000|0|3|8BUI|255.000 @@ -302,22 +302,22 @@ 1|2|1|2|4|2||POLYGON((3 -1,4 -1,4 -2,3 -2,3 -1)) 1|2|1|2|4|3||POLYGON((3 -2,4 -2,4 -3,3 -3,3 -2)) 1|2|1|2|4|4||POLYGON((3 -3,4 -3,4 -4,3 -4,3 -3)) -1|2|1|3|1|1||POLYGON((0 0,1 0,1 -1,0 -1,0 0)) -1|2|1|3|1|2||POLYGON((0 -1,1 -1,1 -2,0 -2,0 -1)) -1|2|1|3|1|3||POLYGON((0 -2,1 -2,1 -3,0 -3,0 -2)) -1|2|1|3|1|4||POLYGON((0 -3,1 -3,1 -4,0 -4,0 -3)) -1|2|1|3|2|1||POLYGON((1 0,2 0,2 -1,1 -1,1 0)) -1|2|1|3|2|2||POLYGON((1 -1,2 -1,2 -2,1 -2,1 -1)) -1|2|1|3|2|3||POLYGON((1 -2,2 -2,2 -3,1 -3,1 -2)) -1|2|1|3|2|4||POLYGON((1 -3,2 -3,2 -4,1 -4,1 -3)) -1|2|1|3|3|1||POLYGON((2 0,3 0,3 -1,2 -1,2 0)) -1|2|1|3|3|2||POLYGON((2 -1,3 -1,3 -2,2 -2,2 -1)) -1|2|1|3|3|3||POLYGON((2 -2,3 -2,3 -3,2 -3,2 -2)) -1|2|1|3|3|4||POLYGON((2 -3,3 -3,3 -4,2 -4,2 -3)) -1|2|1|3|4|1||POLYGON((3 0,4 0,4 -1,3 -1,3 0)) -1|2|1|3|4|2||POLYGON((3 -1,4 -1,4 -2,3 -2,3 -1)) -1|2|1|3|4|3||POLYGON((3 -2,4 -2,4 -3,3 -3,3 -2)) -1|2|1|3|4|4||POLYGON((3 -3,4 -3,4 -4,3 -4,3 -3)) +1|2|1|3|1|1|0|POLYGON((0 0,1 0,1 -1,0 -1,0 0)) +1|2|1|3|1|2|0|POLYGON((0 -1,1 -1,1 -2,0 -2,0 -1)) +1|2|1|3|1|3|0|POLYGON((0 -2,1 -2,1 -3,0 -3,0 -2)) +1|2|1|3|1|4|0|POLYGON((0 -3,1 -3,1 -4,0 -4,0 -3)) +1|2|1|3|2|1|0|POLYGON((1 0,2 0,2 -1,1 -1,1 0)) +1|2|1|3|2|2|0|POLYGON((1 -1,2 -1,2 -2,1 -2,1 -1)) +1|2|1|3|2|3|0|POLYGON((1 -2,2 -2,2 -3,1 -3,1 -2)) +1|2|1|3|2|4|0|POLYGON((1 -3,2 -3,2 -4,1 -4,1 -3)) +1|2|1|3|3|1|0|POLYGON((2 0,3 0,3 -1,2 -1,2 0)) +1|2|1|3|3|2|0|POLYGON((2 -1,3 -1,3 -2,2 -2,2 -1)) +1|2|1|3|3|3|0|POLYGON((2 -2,3 -2,3 -3,2 -3,2 -2)) +1|2|1|3|3|4|0|POLYGON((2 -3,3 -3,3 -4,2 -4,2 -3)) +1|2|1|3|4|1|0|POLYGON((3 0,4 0,4 -1,3 -1,3 0)) +1|2|1|3|4|2|0|POLYGON((3 -1,4 -1,4 -2,3 -2,3 -1)) +1|2|1|3|4|3|0|POLYGON((3 -2,4 -2,4 -3,3 -3,3 -2)) +1|2|1|3|4|4|0|POLYGON((3 -3,4 -3,4 -4,3 -4,3 -3)) 1|2|2|1|1|1||POLYGON((0 0,1 0,1 -1,0 -1,0 0)) 1|2|2|1|1|2||POLYGON((0 -1,1 -1,1 -2,0 -2,0 -1)) 1|2|2|1|1|3||POLYGON((0 -2,1 -2,1 -3,0 -3,0 -2)) @@ -350,22 +350,22 @@ 1|2|2|2|4|2||POLYGON((3 -1,4 -1,4 -2,3 -2,3 -1)) 1|2|2|2|4|3||POLYGON((3 -2,4 -2,4 -3,3 -3,3 -2)) 1|2|2|2|4|4||POLYGON((3 -3,4 -3,4 -4,3 -4,3 -3)) -1|2|2|3|1|1||POLYGON((0 0,1 0,1 -1,0 -1,0 0)) -1|2|2|3|1|2||POLYGON((0 -1,1 -1,1 -2,0 -2,0 -1)) -1|2|2|3|1|3||POLYGON((0 -2,1 -2,1 -3,0 -3,0 -2)) -1|2|2|3|1|4||POLYGON((0 -3,1 -3,1 -4,0 -4,0 -3)) -1|2|2|3|2|1||POLYGON((1 0,2 0,2 -1,1 -1,1 0)) -1|2|2|3|2|2||POLYGON((1 -1,2 -1,2 -2,1 -2,1 -1)) -1|2|2|3|2|3||POLYGON((1 -2,2 -2,2 -3,1 -3,1 -2)) -1|2|2|3|2|4||POLYGON((1 -3,2 -3,2 -4,1 -4,1 -3)) -1|2|2|3|3|1||POLYGON((2 0,3 0,3 -1,2 -1,2 0)) +1|2|2|3|1|1|0|POLYGON((0 0,1 0,1 -1,0 -1,0 0)) +1|2|2|3|1|2|0|POLYGON((0 -1,1 -1,1 -2,0 -2,0 -1)) +1|2|2|3|1|3|0|POLYGON((0 -2,1 -2,1 -3,0 -3,0 -2)) +1|2|2|3|1|4|0|POLYGON((0 -3,1 -3,1 -4,0 -4,0 -3)) +1|2|2|3|2|1|0|POLYGON((1 0,2 0,2 -1,1 -1,1 0)) +1|2|2|3|2|2|0|POLYGON((1 -1,2 -1,2 -2,1 -2,1 -1)) +1|2|2|3|2|3|0|POLYGON((1 -2,2 -2,2 -3,1 -3,1 -2)) +1|2|2|3|2|4|0|POLYGON((1 -3,2 -3,2 -4,1 -4,1 -3)) +1|2|2|3|3|1|0|POLYGON((2 0,3 0,3 -1,2 -1,2 0)) 1|2|2|3|3|2|3|POLYGON((2 -1,3 -1,3 -2,2 -2,2 -1)) -1|2|2|3|3|3||POLYGON((2 -2,3 -2,3 -3,2 -3,2 -2)) -1|2|2|3|3|4||POLYGON((2 -3,3 -3,3 -4,2 -4,2 -3)) -1|2|2|3|4|1||POLYGON((3 0,4 0,4 -1,3 -1,3 0)) -1|2|2|3|4|2||POLYGON((3 -1,4 -1,4 -2,3 -2,3 -1)) -1|2|2|3|4|3||POLYGON((3 -2,4 -2,4 -3,3 -3,3 -2)) -1|2|2|3|4|4||POLYGON((3 -3,4 -3,4 -4,3 -4,3 -3)) +1|2|2|3|3|3|0|POLYGON((2 -2,3 -2,3 -3,2 -3,2 -2)) +1|2|2|3|3|4|0|POLYGON((2 -3,3 -3,3 -4,2 -4,2 -3)) +1|2|2|3|4|1|0|POLYGON((3 0,4 0,4 -1,3 -1,3 0)) +1|2|2|3|4|2|0|POLYGON((3 -1,4 -1,4 -2,3 -2,3 -1)) +1|2|2|3|4|3|0|POLYGON((3 -2,4 -2,4 -3,3 -3,3 -2)) +1|2|2|3|4|4|0|POLYGON((3 -3,4 -3,4 -4,3 -4,3 -3)) 1|2|3|1|1|1||POLYGON((0 0,1 0,1 -1,0 -1,0 0)) 1|2|3|1|1|2||POLYGON((0 -1,1 -1,1 -2,0 -2,0 -1)) 1|2|3|1|1|3||POLYGON((0 -2,1 -2,1 -3,0 -3,0 -2)) @@ -398,22 +398,22 @@ 1|2|3|2|4|2||POLYGON((3 -1,4 -1,4 -2,3 -2,3 -1)) 1|2|3|2|4|3||POLYGON((3 -2,4 -2,4 -3,3 -3,3 -2)) 1|2|3|2|4|4||POLYGON((3 -3,4 -3,4 -4,3 -4,3 -3)) -1|2|3|3|1|1||POLYGON((0 0,1 0,1 -1,0 -1,0 0)) -1|2|3|3|1|2||POLYGON((0 -1,1 -1,1 -2,0 -2,0 -1)) -1|2|3|3|1|3||POLYGON((0 -2,1 -2,1 -3,0 -3,0 -2)) -1|2|3|3|1|4||POLYGON((0 -3,1 -3,1 -4,0 -4,0 -3)) -1|2|3|3|2|1||POLYGON((1 0,2 0,2 -1,1 -1,1 0)) +1|2|3|3|1|1|0|POLYGON((0 0,1 0,1 -1,0 -1,0 0)) +1|2|3|3|1|2|0|POLYGON((0 -1,1 -1,1 -2,0 -2,0 -1)) +1|2|3|3|1|3|0|POLYGON((0 -2,1 -2,1 -3,0 -3,0 -2)) +1|2|3|3|1|4|0|POLYGON((0 -3,1 -3,1 -4,0 -4,0 -3)) +1|2|3|3|2|1|0|POLYGON((1 0,2 0,2 -1,1 -1,1 0)) 1|2|3|3|2|2|3|POLYGON((1 -1,2 -1,2 -2,1 -2,1 -1)) -1|2|3|3|2|3||POLYGON((1 -2,2 -2,2 -3,1 -3,1 -2)) -1|2|3|3|2|4||POLYGON((1 -3,2 -3,2 -4,1 -4,1 -3)) -1|2|3|3|3|1||POLYGON((2 0,3 0,3 -1,2 -1,2 0)) -1|2|3|3|3|2||POLYGON((2 -1,3 -1,3 -2,2 -2,2 -1)) -1|2|3|3|3|3||POLYGON((2 -2,3 -2,3 -3,2 -3,2 -2)) -1|2|3|3|3|4||POLYGON((2 -3,3 -3,3 -4,2 -4,2 -3)) -1|2|3|3|4|1||POLYGON((3 0,4 0,4 -1,3 -1,3 0)) -1|2|3|3|4|2||POLYGON((3 -1,4 -1,4 -2,3 -2,3 -1)) -1|2|3|3|4|3||POLYGON((3 -2,4 -2,4 -3,3 -3,3 -2)) -1|2|3|3|4|4||POLYGON((3 -3,4 -3,4 -4,3 -4,3 -3)) +1|2|3|3|2|3|0|POLYGON((1 -2,2 -2,2 -3,1 -3,1 -2)) +1|2|3|3|2|4|0|POLYGON((1 -3,2 -3,2 -4,1 -4,1 -3)) +1|2|3|3|3|1|0|POLYGON((2 0,3 0,3 -1,2 -1,2 0)) +1|2|3|3|3|2|0|POLYGON((2 -1,3 -1,3 -2,2 -2,2 -1)) +1|2|3|3|3|3|0|POLYGON((2 -2,3 -2,3 -3,2 -3,2 -2)) +1|2|3|3|3|4|0|POLYGON((2 -3,3 -3,3 -4,2 -4,2 -3)) +1|2|3|3|4|1|0|POLYGON((3 0,4 0,4 -1,3 -1,3 0)) +1|2|3|3|4|2|0|POLYGON((3 -1,4 -1,4 -2,3 -2,3 -1)) +1|2|3|3|4|3|0|POLYGON((3 -2,4 -2,4 -3,3 -3,3 -2)) +1|2|3|3|4|4|0|POLYGON((3 -3,4 -3,4 -4,3 -4,3 -3)) 1|2|4|1|1|1||POLYGON((0 0,1 0,1 -1,0 -1,0 0)) 1|2|4|1|1|2||POLYGON((0 -1,1 -1,1 -2,0 -2,0 -1)) 1|2|4|1|1|3||POLYGON((0 -2,1 -2,1 -3,0 -3,0 -2)) @@ -446,11 +446,11 @@ 1|2|4|2|4|2|2|POLYGON((3 -1,4 -1,4 -2,3 -2,3 -1)) 1|2|4|2|4|3|2|POLYGON((3 -2,4 -2,4 -3,3 -3,3 -2)) 1|2|4|2|4|4|2|POLYGON((3 -3,4 -3,4 -4,3 -4,3 -3)) -1|2|4|3|1|1||POLYGON((0 0,1 0,1 -1,0 -1,0 0)) -1|2|4|3|1|2||POLYGON((0 -1,1 -1,1 -2,0 -2,0 -1)) -1|2|4|3|1|3||POLYGON((0 -2,1 -2,1 -3,0 -3,0 -2)) -1|2|4|3|1|4||POLYGON((0 -3,1 -3,1 -4,0 -4,0 -3)) -1|2|4|3|2|1||POLYGON((1 0,2 0,2 -1,1 -1,1 0)) +1|2|4|3|1|1|0|POLYGON((0 0,1 0,1 -1,0 -1,0 0)) +1|2|4|3|1|2|0|POLYGON((0 -1,1 -1,1 -2,0 -2,0 -1)) +1|2|4|3|1|3|0|POLYGON((0 -2,1 -2,1 -3,0 -3,0 -2)) +1|2|4|3|1|4|0|POLYGON((0 -3,1 -3,1 -4,0 -4,0 -3)) +1|2|4|3|2|1|0|POLYGON((1 0,2 0,2 -1,1 -1,1 0)) 1|2|4|3|2|2|3|POLYGON((1 -1,2 -1,2 -2,1 -2,1 -1)) 1|2|4|3|2|3|3|POLYGON((1 -2,2 -2,2 -3,1 -3,1 -2)) 1|2|4|3|2|4|3|POLYGON((1 -3,2 -3,2 -4,1 -4,1 -3)) @@ -519,9 +519,9 @@ 2|2|2|2|2|1||POLYGON((3 -1,4 -1,4 -2,3 -2,3 -1)) 2|2|2|2|2|2||POLYGON((3 -2,4 -2,4 -3,3 -3,3 -2)) 2|2|2|3|1|1|3|POLYGON((2 -1,3 -1,3 -2,2 -2,2 -1)) -2|2|2|3|1|2||POLYGON((2 -2,3 -2,3 -3,2 -3,2 -2)) -2|2|2|3|2|1||POLYGON((3 -1,4 -1,4 -2,3 -2,3 -1)) -2|2|2|3|2|2||POLYGON((3 -2,4 -2,4 -3,3 -3,3 -2)) +2|2|2|3|1|2|0|POLYGON((2 -2,3 -2,3 -3,2 -3,2 -2)) +2|2|2|3|2|1|0|POLYGON((3 -1,4 -1,4 -2,3 -2,3 -1)) +2|2|2|3|2|2|0|POLYGON((3 -2,4 -2,4 -3,3 -3,3 -2)) 2|2|3|1|1|1|10|POLYGON((1 -1,2 -1,2 -2,1 -2,1 -1)) 2|2|3|1|1|2||POLYGON((1 -2,2 -2,2 -3,1 -3,1 -2)) 2|2|3|1|2|1||POLYGON((2 -1,3 -1,3 -2,2 -2,2 -1)) @@ -531,9 +531,9 @@ 2|2|3|2|2|1||POLYGON((2 -1,3 -1,3 -2,2 -2,2 -1)) 2|2|3|2|2|2||POLYGON((2 -2,3 -2,3 -3,2 -3,2 -2)) 2|2|3|3|1|1|3|POLYGON((1 -1,2 -1,2 -2,1 -2,1 -1)) -2|2|3|3|1|2||POLYGON((1 -2,2 -2,2 -3,1 -3,1 -2)) -2|2|3|3|2|1||POLYGON((2 -1,3 -1,3 -2,2 -2,2 -1)) -2|2|3|3|2|2||POLYGON((2 -2,3 -2,3 -3,2 -3,2 -2)) +2|2|3|3|1|2|0|POLYGON((1 -2,2 -2,2 -3,1 -3,1 -2)) +2|2|3|3|2|1|0|POLYGON((2 -1,3 -1,3 -2,2 -2,2 -1)) +2|2|3|3|2|2|0|POLYGON((2 -2,3 -2,3 -3,2 -3,2 -2)) 2|2|4|1|1|1||POLYGON((1 0,2 0,2 -1,1 -1,1 0)) 2|2|4|1|1|2|10|POLYGON((1 -1,2 -1,2 -2,1 -2,1 -1)) 2|2|4|1|1|3|10|POLYGON((1 -2,2 -2,2 -3,1 -3,1 -2)) @@ -558,7 +558,7 @@ 2|2|4|2|3|2|2|POLYGON((3 -1,4 -1,4 -2,3 -2,3 -1)) 2|2|4|2|3|3|2|POLYGON((3 -2,4 -2,4 -3,3 -3,3 -2)) 2|2|4|2|3|4|2|POLYGON((3 -3,4 -3,4 -4,3 -4,3 -3)) -2|2|4|3|1|1||POLYGON((1 0,2 0,2 -1,1 -1,1 0)) +2|2|4|3|1|1|0|POLYGON((1 0,2 0,2 -1,1 -1,1 0)) 2|2|4|3|1|2|3|POLYGON((1 -1,2 -1,2 -2,1 -2,1 -1)) 2|2|4|3|1|3|3|POLYGON((1 -2,2 -2,2 -3,1 -3,1 -2)) 2|2|4|3|1|4|3|POLYGON((1 -3,2 -3,2 -4,1 -4,1 -3)) diff --git a/raster/test/regress/rt_summarystats_expected b/raster/test/regress/rt_summarystats_expected index 120a530ba..f0f566941 100644 --- a/raster/test/regress/rt_summarystats_expected +++ b/raster/test/regress/rt_summarystats_expected @@ -6,6 +6,7 @@ -0.069|1.046 NOTICE: Invalid band index (must use 1-based). Returning NULL | +NOTICE: All pixels of band have the NODATA value (0,,,,,) NOTICE: Band is empty as width and/or height is 0 (0,,,,,) -- 2.40.0