]> granicus.if.org Git - postgis/commitdiff
Rewrite of ST_Clip(raster) to be C-based and updated regression test.
authorBborie Park <bkpark at ucdavis.edu>
Fri, 26 Oct 2012 00:28:10 +0000 (00:28 +0000)
committerBborie Park <bkpark at ucdavis.edu>
Fri, 26 Oct 2012 00:28:10 +0000 (00:28 +0000)
Ticket is #2065

git-svn-id: http://svn.osgeo.org/postgis/trunk@10568 b70326c6-7e19-0410-871a-916f4a2858ee

raster/rt_pg/rt_pg.c
raster/rt_pg/rtpostgis.sql.in.c
raster/test/regress/rt_clip_expected
raster/test/regress/rt_summarystats_expected

index bca35f09b58c8bef99264d7d2417a1b9d9e70ecf..a41abc30c15eb7795f6ed9ebdbbf5a6825a63057 100644 (file)
@@ -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                       */
 /* ---------------------------------------------------------------- */
index c21196efa2f754ad2ec8c7cc35c8f76566ae8ef7..68442d78163354e52e158dfe4bf0ee4144204226 100644 (file)
@@ -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
index 676a8fff972fd0dddda1566f0406793c9de50a93..9d71b685185609223e64424675d5a80106d65d65 100644 (file)
@@ -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
 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
 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))
 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))
 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))
 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))
 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))
 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))
 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))
index 120a530bab7ce22aa0ca4858649772607b3196e4..f0f56694124f6841a3dab302d846d9370aa817ae 100644 (file)
@@ -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,,,,,)