*
* @param raster: the raster to get info from.
* @param nband: the band to polygonize. 0-based
+ * @param exclude_nodata_value: if non-zero, ignore nodata values
+ * to check for pixels with value
*
* @return A set of "geomval" values, one for each group of pixels
* sharing the same value for the provided band. The returned values are
rt_geomval
rt_raster_gdal_polygonize(
rt_raster raster, int nband,
+ int exclude_nodata_value,
int *pnElements
) {
CPLErr cplerr = CE_None;
#endif
uint32_t bandNums[1] = {nband};
+ int excludeNodataValues[1] = {exclude_nodata_value};
/* checks */
assert(NULL != raster);
return NULL;
}
- iBandHasNodataValue = rt_band_get_hasnodata_flag(band);
- if (iBandHasNodataValue) dBandNoData = rt_band_get_nodata(band);
+ if (exclude_nodata_value) {
+ iBandHasNodataValue = rt_band_get_hasnodata_flag(band);
+ if (iBandHasNodataValue) dBandNoData = rt_band_get_nodata(band);
+ }
/*****************************************************
* Convert raster to GDAL MEM dataset
*****************************************************/
- memdataset = rt_raster_to_gdal_mem(raster, NULL, bandNums, 1, &gdal_drv);
+ memdataset = rt_raster_to_gdal_mem(raster, NULL, bandNums, excludeNodataValues, 1, &gdal_drv);
if (NULL == memdataset) {
rterror("rt_raster_gdal_polygonize: Couldn't convert raster to GDAL MEM dataset");
return NULL;
RASTER_DEBUGF(3, "rt_raster_to_gdal: output format is %s", format);
/* load raster into a GDAL MEM raster */
- src_ds = rt_raster_to_gdal_mem(raster, srs, NULL, 0, &src_drv);
+ src_ds = rt_raster_to_gdal_mem(raster, srs, NULL, NULL, 0, &src_drv);
if (NULL == src_ds) {
rterror("rt_raster_to_gdal: Unable to convert raster to GDAL MEM format");
return 0;
* @param raster : raster to convert to GDAL MEM
* @param srs : the raster's coordinate system in OGC WKT
* @param bandNums : array of band numbers to extract from raster
- * and include in the GDAL dataset (0 based)
+ * and include in the GDAL dataset (0 based)
+ * @param excludeNodataValues: array of zero, nonzero where if non-zero,
+ * ignore nodata values for the band
* @param count : number of elements in bandNums
* @param rtn_drv : is set to the GDAL driver object
*
* @return GDAL dataset using GDAL MEM driver
*/
GDALDatasetH
-rt_raster_to_gdal_mem(rt_raster raster, const char *srs,
- uint32_t *bandNums, int count, GDALDriverH *rtn_drv) {
+rt_raster_to_gdal_mem(
+ rt_raster raster,
+ const char *srs,
+ uint32_t *bandNums,
+ int *excludeNodataValues,
+ int count,
+ GDALDriverH *rtn_drv
+) {
GDALDriverH drv = NULL;
GDALDatasetH ds = NULL;
double gt[6] = {0.0};
char *apszOptions[4];
double nodata = 0.0;
int allocBandNums = 0;
+ int allocNodataValues = 0;
int i;
int numBands;
for (i = 0; i < count; i++) bandNums[i] = i;
}
+ /* process exclude_nodata_values */
+ if (NULL == excludeNodataValues) {
+ excludeNodataValues = (int *) rtalloc(sizeof(int) * count);
+ if (NULL == excludeNodataValues) {
+ rterror("rt_raster_to_gdal_mem: Unable to allocate memory for NODATA flags");
+ GDALClose(ds);
+ return 0;
+ }
+ allocNodataValues = 1;
+ for (i = 0; i < count; i++) excludeNodataValues[i] = 1;
+ }
+
/* add band(s) */
for (i = 0; i < count; i++) {
rtband = rt_raster_get_band(raster, bandNums[i]);
if (NULL == rtband) {
rterror("rt_raster_to_gdal_mem: Unable to get requested band index %d", bandNums[i]);
if (allocBandNums) rtdealloc(bandNums);
+ if (allocNodataValues) rtdealloc(excludeNodataValues);
GDALClose(ds);
return 0;
}
if (GDALAddBand(ds, gdal_pt, NULL) == CE_Failure) {
rterror("rt_raster_to_gdal_mem: Could not add GDAL raster band");
if (allocBandNums) rtdealloc(bandNums);
+ if (allocNodataValues) rtdealloc(excludeNodataValues);
GDALClose(ds);
return 0;
}
if (GDALGetRasterCount(ds) != i + 1) {
rterror("rt_raster_to_gdal_mem: Error creating GDAL MEM raster band");
if (allocBandNums) rtdealloc(bandNums);
+ if (allocNodataValues) rtdealloc(excludeNodataValues);
GDALClose(ds);
return 0;
}
if (NULL == band) {
rterror("rt_raster_to_gdal_mem: Could not get GDAL band for additional processing");
if (allocBandNums) rtdealloc(bandNums);
+ if (allocNodataValues) rtdealloc(excludeNodataValues);
GDALClose(ds);
return 0;
}
if (NULL == values) {
rterror("rt_raster_to_gdal_mem: Could not allocate memory for GDAL band pixel values");
if (allocBandNums) rtdealloc(bandNums);
+ if (allocNodataValues) rtdealloc(excludeNodataValues);
GDALClose(ds);
return 0;
}
rterror("rt_raster_to_gdal_mem: Could not get pixel value to convert from 8BSI to 16BSI");
rtdealloc(values);
if (allocBandNums) rtdealloc(bandNums);
+ if (allocNodataValues) rtdealloc(excludeNodataValues);
GDALClose(ds);
return 0;
}
rterror("rt_raster_to_gdal_mem: Could not write converted 8BSI to 16BSI values to GDAL band");
rtdealloc(values);
if (allocBandNums) rtdealloc(bandNums);
+ if (allocNodataValues) rtdealloc(excludeNodataValues);
GDALClose(ds);
return 0;
}
}
/* Add nodata value for band */
- if (rt_band_get_hasnodata_flag(rtband) != FALSE) {
+ if (rt_band_get_hasnodata_flag(rtband) != FALSE && excludeNodataValues[i]) {
nodata = rt_band_get_nodata(rtband);
if (GDALSetRasterNoDataValue(band, nodata) != CE_None)
rtwarn("rt_raster_to_gdal_mem: Could not set nodata value for band");
GDALFlushCache(ds);
if (allocBandNums) rtdealloc(bandNums);
+ if (allocNodataValues) rtdealloc(excludeNodataValues);
return ds;
}
_dst_srs = rt_util_gdal_convert_sr(dst_srs, 0);
/* load raster into a GDAL MEM dataset */
- src_ds = rt_raster_to_gdal_mem(raster, _src_srs, NULL, 0, &src_drv);
+ src_ds = rt_raster_to_gdal_mem(raster, _src_srs, NULL, NULL, 0, &src_drv);
if (NULL == src_ds) {
rterror("rt_raster_gdal_warp: Unable to convert raster to GDAL MEM format");
/* Get pixel geographical shape */
Datum RASTER_getPixelPolygon(PG_FUNCTION_ARGS);
+Datum RASTER_getPixelPolygons(PG_FUNCTION_ARGS);
/* Get pixels of value */
Datum RASTER_pixelOfValue(PG_FUNCTION_ARGS);
rt_pgraster *pgraster = NULL;
rt_raster raster = NULL;
int nband;
+ bool exclude_nodata_value = TRUE;
int nElements;
POSTGIS_RT_DEBUG(2, "RASTER_dumpAsPolygons first call");
SRF_RETURN_DONE(funcctx);
}
- if (PG_NARGS() == 2)
+ if (!PG_ARGISNULL(1))
nband = PG_GETARG_UINT32(1);
else
nband = 1; /* By default, first band */
SRF_RETURN_DONE(funcctx);
}
+ if (!PG_ARGISNULL(2))
+ exclude_nodata_value = PG_GETARG_BOOL(2);
+
/* Polygonize raster */
/**
* Dump raster
*/
- geomval = rt_raster_gdal_polygonize(raster, nband - 1, &nElements);
+ geomval = rt_raster_gdal_polygonize(raster, nband - 1, exclude_nodata_value, &nElements);
rt_raster_destroy(raster);
PG_FREE_IF_COPY(pgraster, 0);
if (NULL == geomval) {
PG_RETURN_POINTER(gser);
}
+/**
+ * Return the geographical shape of all pixels
+ */
+PG_FUNCTION_INFO_V1(RASTER_getPixelPolygons);
+Datum RASTER_getPixelPolygons(PG_FUNCTION_ARGS)
+{
+ FuncCallContext *funcctx;
+ TupleDesc tupdesc;
+ rt_pixel pix = NULL;
+ rt_pixel pix2;
+ int call_cntr;
+ int max_calls;
+ int i = 0;
+
+ /* stuff done only on the first call of the function */
+ if (SRF_IS_FIRSTCALL()) {
+ MemoryContext oldcontext;
+ rt_pgraster *pgraster = NULL;
+ rt_raster raster = NULL;
+ rt_band band = NULL;
+ int hasnodata = FALSE;
+ double nodataval = 0;
+ int nband = 1;
+ int numbands;
+ bool noband = FALSE;
+ bool exclude_nodata_value = TRUE;
+ bool nocolumnx = FALSE;
+ bool norowy = FALSE;
+ int x = 0;
+ int y = 0;
+ int bounds[4] = {0};
+ int pixcount = 0;
+
+ LWPOLY *poly;
+
+ /* create a function context for cross-call persistence */
+ funcctx = SRF_FIRSTCALL_INIT();
+
+ /* switch to memory context appropriate for multiple function calls */
+ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+ if (PG_ARGISNULL(0)) {
+ MemoryContextSwitchTo(oldcontext);
+ SRF_RETURN_DONE(funcctx);
+ }
+ pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+
+ /* band */
+ if (PG_ARGISNULL(1))
+ noband = TRUE;
+ else {
+ nband = PG_GETARG_INT32(1);
+ noband = FALSE;
+ }
+
+ /* column */
+ if (PG_ARGISNULL(2))
+ nocolumnx = TRUE;
+ else {
+ bounds[0] = PG_GETARG_INT32(2);
+ bounds[1] = bounds[0];
+ }
+
+ /* row */
+ if (PG_ARGISNULL(3))
+ norowy = TRUE;
+ else {
+ bounds[2] = PG_GETARG_INT32(3);
+ bounds[3] = bounds[2];
+ }
+
+ /* exclude NODATA */
+ if (!PG_ARGISNULL(4))
+ exclude_nodata_value = PG_GETARG_BOOL(4);
+
+ raster = rt_raster_deserialize(pgraster, FALSE);
+ if (!raster) {
+ PG_FREE_IF_COPY(pgraster, 0);
+ ereport(ERROR, (
+ errcode(ERRCODE_OUT_OF_MEMORY),
+ errmsg("Could not deserialize raster")
+ ));
+ MemoryContextSwitchTo(oldcontext);
+ SRF_RETURN_DONE(funcctx);
+ }
+
+ /* band specified, load band and info */
+ if (!noband) {
+ POSTGIS_RT_DEBUGF(3, "band %d", nband);
+ numbands = rt_raster_get_num_bands(raster);
+
+ if (nband < 1 || nband > numbands) {
+ elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
+ rt_raster_destroy(raster);
+ PG_FREE_IF_COPY(pgraster, 0);
+ MemoryContextSwitchTo(oldcontext);
+ SRF_RETURN_DONE(funcctx);
+ }
+
+ band = rt_raster_get_band(raster, nband - 1);
+ if (!band) {
+ elog(NOTICE, "Could not find band at index %d. Returning NULL", nband);
+ rt_raster_destroy(raster);
+ PG_FREE_IF_COPY(pgraster, 0);
+ MemoryContextSwitchTo(oldcontext);
+ SRF_RETURN_DONE(funcctx);
+ }
+
+ hasnodata = rt_band_get_hasnodata_flag(band);
+ if (hasnodata)
+ nodataval = rt_band_get_nodata(band);
+ }
+
+ /* set bounds if columnx, rowy not set */
+ if (nocolumnx) {
+ bounds[0] = 1;
+ bounds[1] = rt_raster_get_width(raster);
+ }
+ if (norowy) {
+ bounds[2] = 1;
+ bounds[3] = rt_raster_get_height(raster);
+ }
+
+ /* rowy */
+ pixcount = 0;
+ for (y = bounds[2]; y <= bounds[3]; y++) {
+ /* columnx */
+ for (x = bounds[0]; x <= bounds[1]; x++) {
+ /* geometry */
+ poly = rt_raster_pixel_as_polygon(raster, x - 1, y - 1);
+ if (!poly) {
+ elog(ERROR, "RASTER_getPixelPolygons: Could not get pixel polygon");
+
+ for (i = 0; i < pixcount; i++)
+ lwgeom_free(pix[i].geom);
+ if (pixcount) pfree(pix);
+
+ if (!noband) rt_band_destroy(band);
+ rt_raster_destroy(raster);
+ PG_FREE_IF_COPY(pgraster, 0);
+
+ MemoryContextSwitchTo(oldcontext);
+ SRF_RETURN_DONE(funcctx);
+ }
+
+ if (!pixcount)
+ pix = palloc(sizeof(struct rt_pixel_t) * (pixcount + 1));
+ else
+ pix = repalloc(pix, sizeof(struct rt_pixel_t) * (pixcount + 1));
+ if (pix == NULL) {
+ elog(ERROR, "RASTER_getPixelPolygons: Could not allocate memory for storing pixel polygons");
+
+ lwpoly_free(poly);
+ if (!noband) rt_band_destroy(band);
+ rt_raster_destroy(raster);
+ PG_FREE_IF_COPY(pgraster, 0);
+
+ MemoryContextSwitchTo(oldcontext);
+ SRF_RETURN_DONE(funcctx);
+ }
+ pix[pixcount].geom = (LWGEOM *) poly;
+ POSTGIS_RT_DEBUGF(4, "poly @ %p", poly);
+ POSTGIS_RT_DEBUGF(4, "geom @ %p", pix[pixcount].geom);
+
+ /* x, y */
+ pix[pixcount].x = x;
+ pix[pixcount].y = y;
+
+ /* value, NODATA flag */
+ if (!noband) {
+ if (rt_band_get_pixel(band, x - 1, y - 1, &(pix[pixcount].value)) != 0) {
+ elog(ERROR, "RASTER_getPixelPolygons: Could not get pixel value");
+
+ for (i = 0; i < pixcount; i++)
+ lwgeom_free(pix[i].geom);
+ if (pixcount) pfree(pix);
+
+ if (!noband) rt_band_destroy(band);
+ rt_raster_destroy(raster);
+ PG_FREE_IF_COPY(pgraster, 0);
+
+ MemoryContextSwitchTo(oldcontext);
+ SRF_RETURN_DONE(funcctx);
+ }
+
+ if (
+ !exclude_nodata_value || (
+ exclude_nodata_value &&
+ (hasnodata != FALSE) && (
+ FLT_NEQ(pix[pixcount].value, nodataval) &&
+ (rt_band_clamped_value_is_nodata(band, pix[pixcount].value) != 1)
+ )
+ )
+ ) {
+ pix[pixcount].nodata = 0;
+ }
+ else
+ pix[pixcount].nodata = 1;
+ }
+ else
+ pix[pixcount].nodata = 1;
+
+ pixcount++;
+ }
+ }
+
+ if (!noband) rt_band_destroy(band);
+ rt_raster_destroy(raster);
+ PG_FREE_IF_COPY(pgraster, 0);
+
+ /* Store needed information */
+ funcctx->user_fctx = pix;
+
+ /* total number of tuples to be returned */
+ funcctx->max_calls = pixcount;
+
+ /* Build a tuple descriptor for our result type */
+ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
+ ereport(ERROR, (
+ errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("function returning record called in context that cannot accept type record")
+ ));
+ }
+
+ BlessTupleDesc(tupdesc);
+ funcctx->tuple_desc = tupdesc;
+
+ MemoryContextSwitchTo(oldcontext);
+ }
+
+ /* stuff done on every call of the function */
+ funcctx = SRF_PERCALL_SETUP();
+
+ call_cntr = funcctx->call_cntr;
+ max_calls = funcctx->max_calls;
+ tupdesc = funcctx->tuple_desc;
+ pix2 = funcctx->user_fctx;
+
+ /* do when there is more left to send */
+ if (call_cntr < max_calls) {
+ int values_length = 4;
+ Datum values[values_length];
+ bool nulls[values_length];
+ HeapTuple tuple;
+ Datum result;
+
+ GSERIALIZED *gser = NULL;
+ size_t gser_size = 0;
+
+ POSTGIS_RT_DEBUGF(3, "call number %d", call_cntr);
+
+ memset(nulls, FALSE, values_length);
+
+ /* convert LWGEOM to GSERIALIZED */
+ gser = gserialized_from_lwgeom(pix2[call_cntr].geom, 0, &gser_size);
+ lwgeom_free(pix2[call_cntr].geom);
+
+ values[0] = PointerGetDatum(gser);
+ if (pix2[call_cntr].nodata)
+ nulls[1] = TRUE;
+ else
+ values[1] = Float8GetDatum(pix2[call_cntr].value);
+ values[2] = Int32GetDatum(pix2[call_cntr].x);
+ values[3] = Int32GetDatum(pix2[call_cntr].y);
+
+ /* build a tuple */
+ tuple = heap_form_tuple(tupdesc, values, nulls);
+
+ /* make the tuple into a datum */
+ result = HeapTupleGetDatum(tuple);
+
+ SRF_RETURN_NEXT(funcctx, result);
+ }
+ /* do when there is no more left */
+ else {
+ pfree(pix2);
+ SRF_RETURN_DONE(funcctx);
+ }
+}
+
/**
* Get pixels of value
*/
10|13|0.000|-1.800|2|2|1.000|1.000|0.100|0.100|0|1|8BUI|0.000|4.000|4.000
10|14||||||||||||||
0|1|1|1|1|1|POLYGON((0 0,1 0,1 1,0 1,0 0))
-0|1|1|1|2|1|POLYGON((0 1,1 1,1 2,0 2,0 1))
-0|1|1|2|1|1|POLYGON((1 0,2 0,2 1,1 1,1 0))
-0|1|1|2|2|1|POLYGON((1 1,2 1,2 2,1 2,1 1))
-0|2|1|1|1|1|POLYGON((1 -1,2 -1,2 0,1 0,1 -1))
-0|2|1|1|2|1|POLYGON((1 0,2 0,2 1,1 1,1 0))
-0|3|1|1|1|1|POLYGON((1 1,2 1,2 2,1 2,1 1))
-10|11|1|1|1|1|POLYGON((-0.9 -0.9,0.1 -0.8,0.2 0.2,-0.8 0.1,-0.9 -0.9))
-10|11|1|1|2|1|POLYGON((-0.8 0.1,0.2 0.2,0.3 1.2,-0.7 1.1,-0.8 0.1))
-10|11|1|1|3|1|POLYGON((-0.7 1.1,0.3 1.2,0.4 2.2,-0.6 2.1,-0.7 1.1))
-10|11|1|2|1|1|POLYGON((0.1 -0.8,1.1 -0.7,1.2 0.3,0.2 0.2,0.1 -0.8))
-10|11|1|2|2|1|POLYGON((0.2 0.2,1.2 0.3,1.3 1.3,0.3 1.2,0.2 0.2))
-10|11|1|2|3|1|POLYGON((0.3 1.2,1.3 1.3,1.4 2.3,0.4 2.2,0.3 1.2))
-10|11|1|3|1|1|POLYGON((1.1 -0.7,2.1 -0.6,2.2 0.4,1.2 0.3,1.1 -0.7))
-10|11|1|3|2|1|POLYGON((1.2 0.3,2.2 0.4,2.3 1.4,1.3 1.3,1.2 0.3))
-10|11|1|3|3|1|POLYGON((1.3 1.3,2.3 1.4,2.4 2.4,1.4 2.3,1.3 1.3))
-10|12|1|1|1|1|POLYGON((-1.9 -1,-0.9 -0.9,-0.8 0.1,-1.8 0,-1.9 -1))
-10|12|1|1|2|1|POLYGON((-1.8 0,-0.8 0.1,-0.7 1.1,-1.7 1,-1.8 0))
-10|12|1|2|1|1|POLYGON((-0.9 -0.9,0.1 -0.8,0.2 0.2,-0.8 0.1,-0.9 -0.9))
-10|12|1|2|2|1|POLYGON((-0.8 0.1,0.2 0.2,0.3 1.2,-0.7 1.1,-0.8 0.1))
-10|13|1|1|1|1|POLYGON((0 -1.8,1 -1.7,1.1 -0.7,0.1 -0.8,0 -1.8))
-10|13|1|1|2|1|POLYGON((0.1 -0.8,1.1 -0.7,1.2 0.3,0.2 0.2,0.1 -0.8))
-10|13|1|2|1|1|POLYGON((1 -1.7,2 -1.6,2.1 -0.6,1.1 -0.7,1 -1.7))
-10|13|1|2|2|1|POLYGON((1.1 -0.7,2.1 -0.6,2.2 0.4,1.2 0.3,1.1 -0.7))
+0|1|1|1|1|2|POLYGON((0 0,1 0,1 1,0 1,0 0))
0|1|1|1|1|1|POLYGON((0 0,1 0,1 1,0 1,0 0))
+0|1|1|1|2|2|POLYGON((0 1,1 1,1 2,0 2,0 1))
+0|1|1|1|2|1|POLYGON((0 1,1 1,1 2,0 2,0 1))
0|1|1|1|2|1|POLYGON((0 1,1 1,1 2,0 2,0 1))
+0|1|1|2|1|2|POLYGON((1 0,2 0,2 1,1 1,1 0))
+0|1|1|2|1|1|POLYGON((1 0,2 0,2 1,1 1,1 0))
0|1|1|2|1|1|POLYGON((1 0,2 0,2 1,1 1,1 0))
0|1|1|2|2|1|POLYGON((1 1,2 1,2 2,1 2,1 1))
-0|2|1|1|1|1|POLYGON((1 -1,2 -1,2 0,1 0,1 -1))
-0|2|1|1|2|1|POLYGON((1 0,2 0,2 1,1 1,1 0))
-0|3|1|1|1|1|POLYGON((1 1,2 1,2 2,1 2,1 1))
-10|11|1|1|1|1|POLYGON((-0.9 -0.9,0.1 -0.8,0.2 0.2,-0.8 0.1,-0.9 -0.9))
-10|11|1|1|2|1|POLYGON((-0.8 0.1,0.2 0.2,0.3 1.2,-0.7 1.1,-0.8 0.1))
-10|11|1|1|3|1|POLYGON((-0.7 1.1,0.3 1.2,0.4 2.2,-0.6 2.1,-0.7 1.1))
-10|11|1|2|1|1|POLYGON((0.1 -0.8,1.1 -0.7,1.2 0.3,0.2 0.2,0.1 -0.8))
-10|11|1|2|2|1|POLYGON((0.2 0.2,1.2 0.3,1.3 1.3,0.3 1.2,0.2 0.2))
-10|11|1|2|3|1|POLYGON((0.3 1.2,1.3 1.3,1.4 2.3,0.4 2.2,0.3 1.2))
-10|11|1|3|1|1|POLYGON((1.1 -0.7,2.1 -0.6,2.2 0.4,1.2 0.3,1.1 -0.7))
-10|11|1|3|2|1|POLYGON((1.2 0.3,2.2 0.4,2.3 1.4,1.3 1.3,1.2 0.3))
-10|11|1|3|3|1|POLYGON((1.3 1.3,2.3 1.4,2.4 2.4,1.4 2.3,1.3 1.3))
-10|12|1|1|1|1|POLYGON((-1.9 -1,-0.9 -0.9,-0.8 0.1,-1.8 0,-1.9 -1))
-10|12|1|1|2|1|POLYGON((-1.8 0,-0.8 0.1,-0.7 1.1,-1.7 1,-1.8 0))
-10|12|1|2|1|1|POLYGON((-0.9 -0.9,0.1 -0.8,0.2 0.2,-0.8 0.1,-0.9 -0.9))
-10|12|1|2|2|1|POLYGON((-0.8 0.1,0.2 0.2,0.3 1.2,-0.7 1.1,-0.8 0.1))
-10|13|1|1|1|1|POLYGON((0 -1.8,1 -1.7,1.1 -0.7,0.1 -0.8,0 -1.8))
-10|13|1|1|2|1|POLYGON((0.1 -0.8,1.1 -0.7,1.2 0.3,0.2 0.2,0.1 -0.8))
-10|13|1|2|1|1|POLYGON((1 -1.7,2 -1.6,2.1 -0.6,1.1 -0.7,1 -1.7))
-10|13|1|2|2|1|POLYGON((1.1 -0.7,2.1 -0.6,2.2 0.4,1.2 0.3,1.1 -0.7))
-0|1|1|1|1|2|POLYGON((0 0,1 0,1 1,0 1,0 0))
-0|1|1|1|2|2|POLYGON((0 1,1 1,1 2,0 2,0 1))
-0|1|1|2|1|2|POLYGON((1 0,2 0,2 1,1 1,1 0))
0|1|1|2|2|2|POLYGON((1 1,2 1,2 2,1 2,1 1))
+0|1|1|2|2|1|POLYGON((1 1,2 1,2 2,1 2,1 1))
+0|1|2|1|1|2|POLYGON((0 0,1 0,1 1,0 1,0 0))
+0|1|2|1|2|2|POLYGON((0 1,1 1,1 2,0 2,0 1))
+0|1|2|2|1|2|POLYGON((1 0,2 0,2 1,1 1,1 0))
+0|1|2|2|2|2|POLYGON((1 1,2 1,2 2,1 2,1 1))
+0|2|1|1|1|1|POLYGON((1 -1,2 -1,2 0,1 0,1 -1))
0|2|1|1|1|3|POLYGON((1 -1,2 -1,2 0,1 0,1 -1))
+0|2|1|1|1|1|POLYGON((1 -1,2 -1,2 0,1 0,1 -1))
+0|2|1|1|2|1|POLYGON((1 0,2 0,2 1,1 1,1 0))
0|2|1|1|2|3|POLYGON((1 0,2 0,2 1,1 1,1 0))
+0|2|1|1|2|1|POLYGON((1 0,2 0,2 1,1 1,1 0))
+0|2|2|1|1|3|POLYGON((1 -1,2 -1,2 0,1 0,1 -1))
+0|2|2|1|2|3|POLYGON((1 0,2 0,2 1,1 1,1 0))
+0|3|1|1|1|1|POLYGON((1 1,2 1,2 2,1 2,1 1))
+0|3|1|1|1|1|POLYGON((1 1,2 1,2 2,1 2,1 1))
0|3|1|1|1|4|POLYGON((1 1,2 1,2 2,1 2,1 1))
+0|3|2|1|1|4|POLYGON((1 1,2 1,2 2,1 2,1 1))
10|11|1|1|1|2|POLYGON((-0.9 -0.9,0.1 -0.8,0.2 0.2,-0.8 0.1,-0.9 -0.9))
+10|11|1|1|1|1|POLYGON((-0.9 -0.9,0.1 -0.8,0.2 0.2,-0.8 0.1,-0.9 -0.9))
+10|11|1|1|1|1|POLYGON((-0.9 -0.9,0.1 -0.8,0.2 0.2,-0.8 0.1,-0.9 -0.9))
+10|11|1|1|2|1|POLYGON((-0.8 0.1,0.2 0.2,0.3 1.2,-0.7 1.1,-0.8 0.1))
+10|11|1|1|2|1|POLYGON((-0.8 0.1,0.2 0.2,0.3 1.2,-0.7 1.1,-0.8 0.1))
10|11|1|1|2|2|POLYGON((-0.8 0.1,0.2 0.2,0.3 1.2,-0.7 1.1,-0.8 0.1))
10|11|1|1|3|2|POLYGON((-0.7 1.1,0.3 1.2,0.4 2.2,-0.6 2.1,-0.7 1.1))
+10|11|1|1|3|1|POLYGON((-0.7 1.1,0.3 1.2,0.4 2.2,-0.6 2.1,-0.7 1.1))
+10|11|1|1|3|1|POLYGON((-0.7 1.1,0.3 1.2,0.4 2.2,-0.6 2.1,-0.7 1.1))
+10|11|1|2|1|1|POLYGON((0.1 -0.8,1.1 -0.7,1.2 0.3,0.2 0.2,0.1 -0.8))
+10|11|1|2|1|1|POLYGON((0.1 -0.8,1.1 -0.7,1.2 0.3,0.2 0.2,0.1 -0.8))
10|11|1|2|1|2|POLYGON((0.1 -0.8,1.1 -0.7,1.2 0.3,0.2 0.2,0.1 -0.8))
+10|11|1|2|2|1|POLYGON((0.2 0.2,1.2 0.3,1.3 1.3,0.3 1.2,0.2 0.2))
+10|11|1|2|2|1|POLYGON((0.2 0.2,1.2 0.3,1.3 1.3,0.3 1.2,0.2 0.2))
10|11|1|2|2|2|POLYGON((0.2 0.2,1.2 0.3,1.3 1.3,0.3 1.2,0.2 0.2))
+10|11|1|2|3|1|POLYGON((0.3 1.2,1.3 1.3,1.4 2.3,0.4 2.2,0.3 1.2))
10|11|1|2|3|2|POLYGON((0.3 1.2,1.3 1.3,1.4 2.3,0.4 2.2,0.3 1.2))
+10|11|1|2|3|1|POLYGON((0.3 1.2,1.3 1.3,1.4 2.3,0.4 2.2,0.3 1.2))
10|11|1|3|1|2|POLYGON((1.1 -0.7,2.1 -0.6,2.2 0.4,1.2 0.3,1.1 -0.7))
+10|11|1|3|1|1|POLYGON((1.1 -0.7,2.1 -0.6,2.2 0.4,1.2 0.3,1.1 -0.7))
+10|11|1|3|1|1|POLYGON((1.1 -0.7,2.1 -0.6,2.2 0.4,1.2 0.3,1.1 -0.7))
10|11|1|3|2|2|POLYGON((1.2 0.3,2.2 0.4,2.3 1.4,1.3 1.3,1.2 0.3))
+10|11|1|3|2|1|POLYGON((1.2 0.3,2.2 0.4,2.3 1.4,1.3 1.3,1.2 0.3))
+10|11|1|3|2|1|POLYGON((1.2 0.3,2.2 0.4,2.3 1.4,1.3 1.3,1.2 0.3))
10|11|1|3|3|2|POLYGON((1.3 1.3,2.3 1.4,2.4 2.4,1.4 2.3,1.3 1.3))
-10|12|1|1|1|3|POLYGON((-1.9 -1,-0.9 -0.9,-0.8 0.1,-1.8 0,-1.9 -1))
-10|12|1|1|2|3|POLYGON((-1.8 0,-0.8 0.1,-0.7 1.1,-1.7 1,-1.8 0))
-10|12|1|2|1|3|POLYGON((-0.9 -0.9,0.1 -0.8,0.2 0.2,-0.8 0.1,-0.9 -0.9))
-10|12|1|2|2|3|POLYGON((-0.8 0.1,0.2 0.2,0.3 1.2,-0.7 1.1,-0.8 0.1))
-10|13|1|1|1|4|POLYGON((0 -1.8,1 -1.7,1.1 -0.7,0.1 -0.8,0 -1.8))
-10|13|1|1|2|4|POLYGON((0.1 -0.8,1.1 -0.7,1.2 0.3,0.2 0.2,0.1 -0.8))
-10|13|1|2|1|4|POLYGON((1 -1.7,2 -1.6,2.1 -0.6,1.1 -0.7,1 -1.7))
-10|13|1|2|2|4|POLYGON((1.1 -0.7,2.1 -0.6,2.2 0.4,1.2 0.3,1.1 -0.7))
-0|1|2|1|1|2|POLYGON((0 0,1 0,1 1,0 1,0 0))
-0|1|2|1|2|2|POLYGON((0 1,1 1,1 2,0 2,0 1))
-0|1|2|2|1|2|POLYGON((1 0,2 0,2 1,1 1,1 0))
-0|1|2|2|2|2|POLYGON((1 1,2 1,2 2,1 2,1 1))
-0|2|2|1|1|3|POLYGON((1 -1,2 -1,2 0,1 0,1 -1))
-0|2|2|1|2|3|POLYGON((1 0,2 0,2 1,1 1,1 0))
-0|3|2|1|1|4|POLYGON((1 1,2 1,2 2,1 2,1 1))
+10|11|1|3|3|1|POLYGON((1.3 1.3,2.3 1.4,2.4 2.4,1.4 2.3,1.3 1.3))
+10|11|1|3|3|1|POLYGON((1.3 1.3,2.3 1.4,2.4 2.4,1.4 2.3,1.3 1.3))
10|11|2|1|1|2|POLYGON((-0.9 -0.9,0.1 -0.8,0.2 0.2,-0.8 0.1,-0.9 -0.9))
10|11|2|1|2|2|POLYGON((-0.8 0.1,0.2 0.2,0.3 1.2,-0.7 1.1,-0.8 0.1))
10|11|2|1|3|2|POLYGON((-0.7 1.1,0.3 1.2,0.4 2.2,-0.6 2.1,-0.7 1.1))
10|11|2|3|1|2|POLYGON((1.1 -0.7,2.1 -0.6,2.2 0.4,1.2 0.3,1.1 -0.7))
10|11|2|3|2|2|POLYGON((1.2 0.3,2.2 0.4,2.3 1.4,1.3 1.3,1.2 0.3))
10|11|2|3|3|2|POLYGON((1.3 1.3,2.3 1.4,2.4 2.4,1.4 2.3,1.3 1.3))
+10|12|1|1|1|1|POLYGON((-1.9 -1,-0.9 -0.9,-0.8 0.1,-1.8 0,-1.9 -1))
+10|12|1|1|1|1|POLYGON((-1.9 -1,-0.9 -0.9,-0.8 0.1,-1.8 0,-1.9 -1))
+10|12|1|1|1|3|POLYGON((-1.9 -1,-0.9 -0.9,-0.8 0.1,-1.8 0,-1.9 -1))
+10|12|1|1|2|1|POLYGON((-1.8 0,-0.8 0.1,-0.7 1.1,-1.7 1,-1.8 0))
+10|12|1|1|2|1|POLYGON((-1.8 0,-0.8 0.1,-0.7 1.1,-1.7 1,-1.8 0))
+10|12|1|1|2|3|POLYGON((-1.8 0,-0.8 0.1,-0.7 1.1,-1.7 1,-1.8 0))
+10|12|1|2|1|1|POLYGON((-0.9 -0.9,0.1 -0.8,0.2 0.2,-0.8 0.1,-0.9 -0.9))
+10|12|1|2|1|3|POLYGON((-0.9 -0.9,0.1 -0.8,0.2 0.2,-0.8 0.1,-0.9 -0.9))
+10|12|1|2|1|1|POLYGON((-0.9 -0.9,0.1 -0.8,0.2 0.2,-0.8 0.1,-0.9 -0.9))
+10|12|1|2|2|1|POLYGON((-0.8 0.1,0.2 0.2,0.3 1.2,-0.7 1.1,-0.8 0.1))
+10|12|1|2|2|3|POLYGON((-0.8 0.1,0.2 0.2,0.3 1.2,-0.7 1.1,-0.8 0.1))
+10|12|1|2|2|1|POLYGON((-0.8 0.1,0.2 0.2,0.3 1.2,-0.7 1.1,-0.8 0.1))
10|12|2|1|1|3|POLYGON((-1.9 -1,-0.9 -0.9,-0.8 0.1,-1.8 0,-1.9 -1))
10|12|2|1|2|3|POLYGON((-1.8 0,-0.8 0.1,-0.7 1.1,-1.7 1,-1.8 0))
10|12|2|2|1|3|POLYGON((-0.9 -0.9,0.1 -0.8,0.2 0.2,-0.8 0.1,-0.9 -0.9))
10|12|2|2|2|3|POLYGON((-0.8 0.1,0.2 0.2,0.3 1.2,-0.7 1.1,-0.8 0.1))
+10|13|1|1|1|1|POLYGON((0 -1.8,1 -1.7,1.1 -0.7,0.1 -0.8,0 -1.8))
+10|13|1|1|1|4|POLYGON((0 -1.8,1 -1.7,1.1 -0.7,0.1 -0.8,0 -1.8))
+10|13|1|1|1|1|POLYGON((0 -1.8,1 -1.7,1.1 -0.7,0.1 -0.8,0 -1.8))
+10|13|1|1|2|1|POLYGON((0.1 -0.8,1.1 -0.7,1.2 0.3,0.2 0.2,0.1 -0.8))
+10|13|1|1|2|4|POLYGON((0.1 -0.8,1.1 -0.7,1.2 0.3,0.2 0.2,0.1 -0.8))
+10|13|1|1|2|1|POLYGON((0.1 -0.8,1.1 -0.7,1.2 0.3,0.2 0.2,0.1 -0.8))
+10|13|1|2|1|1|POLYGON((1 -1.7,2 -1.6,2.1 -0.6,1.1 -0.7,1 -1.7))
+10|13|1|2|1|1|POLYGON((1 -1.7,2 -1.6,2.1 -0.6,1.1 -0.7,1 -1.7))
+10|13|1|2|1|4|POLYGON((1 -1.7,2 -1.6,2.1 -0.6,1.1 -0.7,1 -1.7))
+10|13|1|2|2|1|POLYGON((1.1 -0.7,2.1 -0.6,2.2 0.4,1.2 0.3,1.1 -0.7))
+10|13|1|2|2|1|POLYGON((1.1 -0.7,2.1 -0.6,2.2 0.4,1.2 0.3,1.1 -0.7))
+10|13|1|2|2|4|POLYGON((1.1 -0.7,2.1 -0.6,2.2 0.4,1.2 0.3,1.1 -0.7))
10|13|2|1|1|4|POLYGON((0 -1.8,1 -1.7,1.1 -0.7,0.1 -0.8,0 -1.8))
10|13|2|1|2|4|POLYGON((0.1 -0.8,1.1 -0.7,1.2 0.3,0.2 0.2,0.1 -0.8))
10|13|2|2|1|4|POLYGON((1 -1.7,2 -1.6,2.1 -0.6,1.1 -0.7,1 -1.7))
10|13|2|2|2|4|POLYGON((1.1 -0.7,2.1 -0.6,2.2 0.4,1.2 0.3,1.1 -0.7))
-0|1|2|1|1||POLYGON((0 0,1 0,1 1,0 1,0 0))
-0|1|2|1|2||POLYGON((0 1,1 1,1 2,0 2,0 1))
-0|1|2|2|1||POLYGON((1 0,2 0,2 1,1 1,1 0))
-0|1|2|2|2||POLYGON((1 1,2 1,2 2,1 2,1 1))
-0|2|2|1|1||POLYGON((1 -1,2 -1,2 0,1 0,1 -1))
-0|2|2|1|2||POLYGON((1 0,2 0,2 1,1 1,1 0))
-0|3|2|1|1||POLYGON((1 1,2 1,2 2,1 2,1 1))
-10|11|2|1|1||POLYGON((-0.9 -0.9,0.1 -0.8,0.2 0.2,-0.8 0.1,-0.9 -0.9))
-10|11|2|1|2||POLYGON((-0.8 0.1,0.2 0.2,0.3 1.2,-0.7 1.1,-0.8 0.1))
-10|11|2|1|3||POLYGON((-0.7 1.1,0.3 1.2,0.4 2.2,-0.6 2.1,-0.7 1.1))
-10|11|2|2|1||POLYGON((0.1 -0.8,1.1 -0.7,1.2 0.3,0.2 0.2,0.1 -0.8))
-10|11|2|2|2||POLYGON((0.2 0.2,1.2 0.3,1.3 1.3,0.3 1.2,0.2 0.2))
-10|11|2|2|3||POLYGON((0.3 1.2,1.3 1.3,1.4 2.3,0.4 2.2,0.3 1.2))
-10|11|2|3|1||POLYGON((1.1 -0.7,2.1 -0.6,2.2 0.4,1.2 0.3,1.1 -0.7))
-10|11|2|3|2||POLYGON((1.2 0.3,2.2 0.4,2.3 1.4,1.3 1.3,1.2 0.3))
-10|11|2|3|3||POLYGON((1.3 1.3,2.3 1.4,2.4 2.4,1.4 2.3,1.3 1.3))
-10|12|2|1|1||POLYGON((-1.9 -1,-0.9 -0.9,-0.8 0.1,-1.8 0,-1.9 -1))
-10|12|2|1|2||POLYGON((-1.8 0,-0.8 0.1,-0.7 1.1,-1.7 1,-1.8 0))
-10|12|2|2|1||POLYGON((-0.9 -0.9,0.1 -0.8,0.2 0.2,-0.8 0.1,-0.9 -0.9))
-10|12|2|2|2||POLYGON((-0.8 0.1,0.2 0.2,0.3 1.2,-0.7 1.1,-0.8 0.1))
-10|13|2|1|1||POLYGON((0 -1.8,1 -1.7,1.1 -0.7,0.1 -0.8,0 -1.8))
-10|13|2|1|2||POLYGON((0.1 -0.8,1.1 -0.7,1.2 0.3,0.2 0.2,0.1 -0.8))
-10|13|2|2|1||POLYGON((1 -1.7,2 -1.6,2.1 -0.6,1.1 -0.7,1 -1.7))
-10|13|2|2|2||POLYGON((1.1 -0.7,2.1 -0.6,2.2 0.4,1.2 0.3,1.1 -0.7))
-0|1|2|1|1||POLYGON((0 0,1 0,1 1,0 1,0 0))
-0|1|2|1|2||POLYGON((0 1,1 1,1 2,0 2,0 1))
-0|1|2|2|1||POLYGON((1 0,2 0,2 1,1 1,1 0))
-0|1|2|2|2||POLYGON((1 1,2 1,2 2,1 2,1 1))
-0|2|2|1|1||POLYGON((1 -1,2 -1,2 0,1 0,1 -1))
-0|2|2|1|2||POLYGON((1 0,2 0,2 1,1 1,1 0))
-0|3|2|1|1||POLYGON((1 1,2 1,2 2,1 2,1 1))
-10|11|2|1|1||POLYGON((-0.9 -0.9,0.1 -0.8,0.2 0.2,-0.8 0.1,-0.9 -0.9))
-10|11|2|1|2||POLYGON((-0.8 0.1,0.2 0.2,0.3 1.2,-0.7 1.1,-0.8 0.1))
-10|11|2|1|3||POLYGON((-0.7 1.1,0.3 1.2,0.4 2.2,-0.6 2.1,-0.7 1.1))
-10|11|2|2|1||POLYGON((0.1 -0.8,1.1 -0.7,1.2 0.3,0.2 0.2,0.1 -0.8))
-10|11|2|2|2||POLYGON((0.2 0.2,1.2 0.3,1.3 1.3,0.3 1.2,0.2 0.2))
-10|11|2|2|3||POLYGON((0.3 1.2,1.3 1.3,1.4 2.3,0.4 2.2,0.3 1.2))
-10|11|2|3|1||POLYGON((1.1 -0.7,2.1 -0.6,2.2 0.4,1.2 0.3,1.1 -0.7))
-10|11|2|3|2||POLYGON((1.2 0.3,2.2 0.4,2.3 1.4,1.3 1.3,1.2 0.3))
-10|11|2|3|3||POLYGON((1.3 1.3,2.3 1.4,2.4 2.4,1.4 2.3,1.3 1.3))
-10|12|2|1|1||POLYGON((-1.9 -1,-0.9 -0.9,-0.8 0.1,-1.8 0,-1.9 -1))
-10|12|2|1|2||POLYGON((-1.8 0,-0.8 0.1,-0.7 1.1,-1.7 1,-1.8 0))
-10|12|2|2|1||POLYGON((-0.9 -0.9,0.1 -0.8,0.2 0.2,-0.8 0.1,-0.9 -0.9))
-10|12|2|2|2||POLYGON((-0.8 0.1,0.2 0.2,0.3 1.2,-0.7 1.1,-0.8 0.1))
-10|13|2|1|1||POLYGON((0 -1.8,1 -1.7,1.1 -0.7,0.1 -0.8,0 -1.8))
-10|13|2|1|2||POLYGON((0.1 -0.8,1.1 -0.7,1.2 0.3,0.2 0.2,0.1 -0.8))
-10|13|2|2|1||POLYGON((1 -1.7,2 -1.6,2.1 -0.6,1.1 -0.7,1 -1.7))
-10|13|2|2|2||POLYGON((1.1 -0.7,2.1 -0.6,2.2 0.4,1.2 0.3,1.1 -0.7))