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
*/
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);
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);
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);
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;
}
}
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);
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);
/* 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);
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);
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);
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 */
/* ---------------------------------------------------------------- */
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
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))
-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,,,,,)