]> granicus.if.org Git - postgis/commitdiff
Added parameters to ST_Tile(raster) to control padding of generated tiles.
authorBborie Park <bkpark at ucdavis.edu>
Fri, 14 Dec 2012 20:27:06 +0000 (20:27 +0000)
committerBborie Park <bkpark at ucdavis.edu>
Fri, 14 Dec 2012 20:27:06 +0000 (20:27 +0000)
ST_Tile(raster) no longer defaults to padding tiles. Ticket #2069

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

doc/reference_raster.xml
raster/rt_pg/rt_pg.c
raster/rt_pg/rtpostgis.sql.in.c
raster/rt_pg/rtpostgis_drop.sql.in.c
raster/test/regress/rt_tile.sql
raster/test/regress/rt_tile_expected

index 03285aa9aca2a3b3a517e830506a03168e32f38e..baae1e3487c7ad1e860062f807a4c84b8ced067a 100644 (file)
@@ -1633,6 +1633,8 @@ FROM (SELECT rid, ST_MetaData(rast) As md
                                                <paramdef><type>int[] </type> <parameter>nband</parameter></paramdef>
                                                <paramdef><type>integer </type> <parameter>width</parameter></paramdef>
                                                <paramdef><type>integer </type> <parameter>height</parameter></paramdef>
+                                               <paramdef choice="opt"><type>boolean </type> <parameter>padwithnodata=FALSE</parameter></paramdef>
+                                               <paramdef choice="opt"><type>double precision </type> <parameter>nodataval=NULL</parameter></paramdef>
                                        </funcprototype>
 
                                        <funcprototype>
@@ -1641,6 +1643,8 @@ FROM (SELECT rid, ST_MetaData(rast) As md
                                                <paramdef><type>integer </type> <parameter>nband</parameter></paramdef>
                                                <paramdef><type>integer </type> <parameter>width</parameter></paramdef>
                                                <paramdef><type>integer </type> <parameter>height</parameter></paramdef>
+                                               <paramdef choice="opt"><type>boolean </type> <parameter>padwithnodata=FALSE</parameter></paramdef>
+                                               <paramdef choice="opt"><type>double precision </type> <parameter>nodataval=NULL</parameter></paramdef>
                                        </funcprototype>
 
                                        <funcprototype>
@@ -1648,6 +1652,8 @@ FROM (SELECT rid, ST_MetaData(rast) As md
                                                <paramdef><type>raster </type> <parameter>rast</parameter></paramdef>
                                                <paramdef><type>integer </type> <parameter>width</parameter></paramdef>
                                                <paramdef><type>integer </type> <parameter>height</parameter></paramdef>
+                                               <paramdef choice="opt"><type>boolean </type> <parameter>padwithnodata=FALSE</parameter></paramdef>
+                                               <paramdef choice="opt"><type>double precision </type> <parameter>nodataval=NULL</parameter></paramdef>
                                        </funcprototype>
 
                                </funcsynopsis>
@@ -1660,6 +1666,10 @@ FROM (SELECT rid, ST_MetaData(rast) As md
                                        Returns a set of rasters resulting from the split of the input raster based upon the desired dimensions of the output rasters.
                                </para>
 
+                               <para>
+                                       If <varname>padwithnodata</varname> = FALSE, edge tiles on the right and bottom sides of the raster may have different dimensions than the rest of the tiles. If <varname>padwithnodata</varname> = TRUE, all tiles will have the same dimensions with the possibilty that edge tiles being padded with NODATA values.  If raster band(s) do not have NODATA value(s) specified, one can be specified by setting <varname>nodataval</varname>.
+                               </para>
+
                                <note>
                                        <para>
                                                If a specified band of the input raster is out-of-db, the corresponding band in the output rasters will also be out-of-db.
@@ -1688,7 +1698,7 @@ WITH foo AS (
 ), bar AS (
        SELECT ST_Union(rast) AS rast FROM foo
 ), baz AS (
-       SELECT ST_Tile(rast, 3, 3) AS rast FROM bar
+       SELECT ST_Tile(rast, 3, 3, TRUE) AS rast FROM bar
 )
 SELECT
        ST_DumpValues(rast)
index 968cce5c55368295290ccc25e9944d900ce3280b..97e6780855ba5169bc199f27d91447d523ac71ba 100644 (file)
@@ -5383,6 +5383,12 @@ Datum RASTER_tile(PG_FUNCTION_ARGS)
 
                int numbands;
                int *nbands;
+
+               struct {
+                       int pad;
+                       double hasnodata;
+                       double nodataval;
+               } pad;
        };
        struct tile_arg_t *arg1 = NULL;
        struct tile_arg_t *arg2 = NULL;
@@ -5578,6 +5584,25 @@ Datum RASTER_tile(PG_FUNCTION_ARGS)
                        }
                }
 
+               /* pad (4) and padnodata (5) */
+               if (!PG_ARGISNULL(4)) {
+                       arg1->pad.pad = PG_GETARG_BOOL(4) ? 1 : 0;
+
+                       if (arg1->pad.pad && !PG_ARGISNULL(5)) {
+                               arg1->pad.hasnodata = 1;
+                               arg1->pad.nodataval = PG_GETARG_FLOAT8(5);
+                       }
+                       else {
+                               arg1->pad.hasnodata = 0;
+                               arg1->pad.nodataval = 0;
+                       }
+               }
+               else {
+                       arg1->pad.pad = 0;
+                       arg1->pad.hasnodata = 0;
+                       arg1->pad.nodataval = 0;
+               }
+
                /* store some additional metadata */
                arg1->raster.srid = rt_raster_get_srid(arg1->raster.raster);
                arg1->raster.width = rt_raster_get_width(arg1->raster.raster);
@@ -5614,12 +5639,16 @@ Datum RASTER_tile(PG_FUNCTION_ARGS)
                rt_pixtype pixtype = PT_END;
                int hasnodata = 0;
                double nodataval = 0;
+               int width = 0;
+               int height = 0;
 
                int k = 0;
                int tx = 0;
                int ty = 0;
                int rx = 0;
                int ry = 0;
+               int ex = 0; /* edge tile on right */
+               int ey = 0; /* edge tile on bottom */
                double ulx = 0;
                double uly = 0;
                uint16_t len = 0;
@@ -5628,11 +5657,6 @@ Datum RASTER_tile(PG_FUNCTION_ARGS)
 
                POSTGIS_RT_DEBUGF(3, "call number %d", call_cntr);
 
-               /* create empty raster */
-               tile = rt_raster_new(arg2->tile.width, arg2->tile.height);
-               rt_raster_set_geotransform_matrix(tile, arg2->raster.gt);
-               rt_raster_set_srid(tile, arg2->raster.srid);
-
                /*
                        find offset based upon tile #
 
@@ -5644,10 +5668,40 @@ Datum RASTER_tile(PG_FUNCTION_ARGS)
                tx = call_cntr % arg2->tile.nx;
                POSTGIS_RT_DEBUGF(4, "tile (x, y) = (%d, %d)", tx, ty);
 
-               /* upper-left of tile */
+               /* edge tile? only important if padding is false */
+               if (!arg2->pad.pad) {
+                       if (ty + 1 == arg2->tile.ny)
+                               ey = 1;
+                       if (tx + 1 == arg2->tile.nx)
+                               ex = 1;
+               }
+
+               /* upper-left of tile in raster coordinates */
                rx = tx * arg2->tile.width;
                ry = ty * arg2->tile.height;
                POSTGIS_RT_DEBUGF(4, "raster coordinates = %d, %d", rx, ry);
+
+               /* determine tile width and height */
+               /* default to user-defined */
+               width = arg2->tile.width;
+               height = arg2->tile.height;
+
+               /* override user-defined if edge tile (only possible if padding is false */
+               if (ex || ey) {
+                       /* right edge */
+                       if (ex)
+                               width = arg2->raster.width - rx;
+                       /* bottom edge */
+                       if (ey)
+                               height = arg2->raster.height - ry;
+               }
+
+               /* create empty raster */
+               tile = rt_raster_new(width, height);
+               rt_raster_set_geotransform_matrix(tile, arg2->raster.gt);
+               rt_raster_set_srid(tile, arg2->raster.srid);
+
+               /* upper-left of tile in spatial coordinates */
                if (rt_raster_cell_to_geopoint(arg2->raster.raster, rx, ry, &ulx, &uly, arg2->raster.gt) != ES_NONE) {
                        elog(ERROR, "RASTER_tile: Unable to compute the coordinates of the upper-left corner of the output tile");
                        rt_raster_destroy(tile);
@@ -5656,14 +5710,14 @@ Datum RASTER_tile(PG_FUNCTION_ARGS)
                        pfree(arg2);
                        SRF_RETURN_DONE(funcctx);
                }
-               POSTGIS_RT_DEBUGF(4, "spatial coordinates = %f, %f", ulx, uly);
                rt_raster_set_offsets(tile, ulx, uly);
+               POSTGIS_RT_DEBUGF(4, "spatial coordinates = %f, %f", ulx, uly);
 
                /* compute length of pixel line to read */
                len = arg2->tile.width;
                if (rx + arg2->tile.width >= arg2->raster.width)
                        len = arg2->raster.width - rx;
-               POSTGIS_RT_DEBUGF(3, "len = %d", len);
+               POSTGIS_RT_DEBUGF(3, "read line len = %d", len);
 
                /* copy bands to tile */
                for (i = 0; i < arg2->numbands; i++) {
@@ -5683,6 +5737,10 @@ Datum RASTER_tile(PG_FUNCTION_ARGS)
                        hasnodata = rt_band_get_hasnodata_flag(_band);
                        if (hasnodata)
                                rt_band_get_nodata(_band, &nodataval);
+                       else if (arg2->pad.pad && arg2->pad.hasnodata) {
+                               hasnodata = 1;
+                               nodataval = arg2->pad.nodataval;
+                       }
                        else
                                nodataval = rt_band_get_min_value(_band);
 
index 396d0a4d60b6877c8874b7096f4c73b339971db3..dfd9cfdb189c968b1bd1f2f4962593e7376b05c1 100644 (file)
@@ -4365,7 +4365,8 @@ CREATE OR REPLACE FUNCTION st_setgeoreference(rast raster, georef text, format t
 CREATE OR REPLACE FUNCTION _st_tile(
        rast raster,
        width integer, height integer,
-       nband int[] DEFAULT NULL
+       nband integer[] DEFAULT NULL,
+       padwithnodata boolean DEFAULT FALSE, nodataval double precision DEFAULT NULL
 )
        RETURNS SETOF raster
        AS 'MODULE_PATHNAME','RASTER_tile'
@@ -4373,26 +4374,29 @@ CREATE OR REPLACE FUNCTION _st_tile(
 
 CREATE OR REPLACE FUNCTION st_tile(
        rast raster, nband integer[],
-       width integer, height integer
+       width integer, height integer,
+       padwithnodata boolean DEFAULT FALSE, nodataval double precision DEFAULT NULL
 )
        RETURNS SETOF raster
-       AS $$ SELECT _st_tile($1, $3, $4, $2) $$
+       AS $$ SELECT _st_tile($1, $3, $4, $2, $5, $6) $$
        LANGUAGE 'sql' IMMUTABLE;
 
 CREATE OR REPLACE FUNCTION st_tile(
        rast raster, nband integer,
-       width integer, height integer
+       width integer, height integer,
+       padwithnodata boolean DEFAULT FALSE, nodataval double precision DEFAULT NULL
 )
        RETURNS SETOF raster
-       AS $$ SELECT _st_tile($1, $3, $4, ARRAY[$2]::integer[]) $$
+       AS $$ SELECT _st_tile($1, $3, $4, ARRAY[$2]::integer[], $5, $6) $$
        LANGUAGE 'sql' IMMUTABLE;
 
 CREATE OR REPLACE FUNCTION st_tile(
        rast raster,
-       width integer, height integer
+       width integer, height integer,
+       padwithnodata boolean DEFAULT FALSE, nodataval double precision DEFAULT NULL
 )
        RETURNS SETOF raster
-       AS $$ SELECT _st_tile($1, $2, $3, NULL::integer[]) $$
+       AS $$ SELECT _st_tile($1, $2, $3, NULL::integer[], $4, $5) $$
        LANGUAGE 'sql' IMMUTABLE;
 
 -----------------------------------------------------------------------
index ac3d1301269c8b8a537885944b02b178818edc6f..e0cae36e16087fb399c3c50dfab6a21a4c9c8236 100644 (file)
@@ -474,3 +474,10 @@ DROP FUNCTION IF EXISTS _st_resample(raster, text, double precision, integer, do
 -- function signatures changed
 DROP FUNCTION IF EXISTS st_resample(raster, integer, double precision, double precision, double precision, double precision, double precision, double precision, text, double precision);
 DROP FUNCTION IF EXISTS st_resample(raster, integer, integer, integer, double precision, double precision, double precision, double precision, text, double precision);
+
+-- function signatures changed
+DROP FUNCTION IF EXISTS _st_tile(raster, integer, integer, int[]);
+DROP FUNCTION IF EXISTS st_tile(raster, integer[], integer, integer);
+DROP FUNCTION IF EXISTS st_tile(raster, integer, integer, integer);
+DROP FUNCTION IF EXISTS st_tile(raster, integer, integer);
+
index c8e4ec9f48823f466ec573e9ea762d9acb97a01b..f010c8e332fcf4dd8ae5c791b662f0b214fe85b3 100644 (file)
@@ -16,52 +16,129 @@ CREATE TABLE raster_tile AS
        SELECT ST_Union(rast) AS rast FROM foo;
 
 WITH foo AS (
-       SELECT ST_Tile(rast, 3, 3) AS rast FROM raster_tile
+       SELECT ST_Tile(rast, 3, 3, TRUE) AS rast FROM raster_tile
 )
 SELECT
        1, ST_DumpValues(rast)
 FROM foo;
 
 WITH foo AS (
-       SELECT ST_Tile(rast, ARRAY[1], 3, 3) AS rast FROM raster_tile
+       SELECT ST_Tile(rast, ARRAY[1], 3, 3, TRUE) AS rast FROM raster_tile
 )
 SELECT
        2, ST_DumpValues(rast)
 FROM foo;
 
 WITH foo AS (
-       SELECT ST_Tile(rast, ARRAY[2, 1], 3, 3) AS rast FROM raster_tile
+       SELECT ST_Tile(rast, ARRAY[2, 1], 3, 3, TRUE) AS rast FROM raster_tile
 )
 SELECT
        3, ST_DumpValues(rast)
 FROM foo;
 
 WITH foo AS (
-       SELECT ST_Tile(rast, 2, 3, 3) AS rast FROM raster_tile
+       SELECT ST_Tile(rast, 2, 3, 3, TRUE) AS rast FROM raster_tile
 )
 SELECT
        4, ST_DumpValues(rast)
 FROM foo;
 
 WITH foo AS (
-       SELECT ST_Tile(rast, 2, 2) AS rast FROM raster_tile
+       SELECT ST_Tile(rast, 2, 2, TRUE) AS rast FROM raster_tile
 )
 SELECT
        5, ST_DumpValues(rast)
 FROM foo;
 
 WITH foo AS (
-       SELECT ST_Tile(rast, 1, 1) AS rast FROM raster_tile
+       SELECT ST_Tile(rast, 1, 1, TRUE) AS rast FROM raster_tile
 )
 SELECT
        6, ST_DumpValues(rast)
 FROM foo;
 
 WITH foo AS (
-       SELECT ST_Tile(rast, 5, 5) AS rast FROM raster_tile
+       SELECT ST_Tile(rast, 5, 5, TRUE) AS rast FROM raster_tile
 )
 SELECT
        7, ST_DumpValues(rast)
 FROM foo;
 
+WITH foo AS (
+       SELECT ST_Tile(rast, 2, 3, TRUE) AS rast FROM raster_tile
+)
+SELECT
+       8, ST_DumpValues(rast)
+FROM foo;
+
+WITH foo AS (
+       SELECT ST_Tile(rast, 3, 2, TRUE) AS rast FROM raster_tile
+)
+SELECT
+       9, ST_DumpValues(rast)
+FROM foo;
+
+WITH foo AS (
+       SELECT ST_Tile(rast, 3, 3) AS rast FROM raster_tile
+)
+SELECT
+       11, ST_DumpValues(rast)
+FROM foo;
+
+WITH foo AS (
+       SELECT ST_Tile(rast, ARRAY[1], 3, 3) AS rast FROM raster_tile
+)
+SELECT
+       12, ST_DumpValues(rast)
+FROM foo;
+
+WITH foo AS (
+       SELECT ST_Tile(rast, ARRAY[2, 1], 3, 3) AS rast FROM raster_tile
+)
+SELECT
+       13, ST_DumpValues(rast)
+FROM foo;
+
+WITH foo AS (
+       SELECT ST_Tile(rast, 2, 3, 3) AS rast FROM raster_tile
+)
+SELECT
+       14, ST_DumpValues(rast)
+FROM foo;
+
+WITH foo AS (
+       SELECT ST_Tile(rast, 2, 2) AS rast FROM raster_tile
+)
+SELECT
+       15, ST_DumpValues(rast)
+FROM foo;
+
+WITH foo AS (
+       SELECT ST_Tile(rast, 1, 1) AS rast FROM raster_tile
+)
+SELECT
+       16, ST_DumpValues(rast)
+FROM foo;
+
+WITH foo AS (
+       SELECT ST_Tile(rast, 5, 5) AS rast FROM raster_tile
+)
+SELECT
+       17, ST_DumpValues(rast)
+FROM foo;
+
+WITH foo AS (
+       SELECT ST_Tile(rast, 2, 3) AS rast FROM raster_tile
+)
+SELECT
+       18, ST_DumpValues(rast)
+FROM foo;
+
+WITH foo AS (
+       SELECT ST_Tile(rast, 3, 2) AS rast FROM raster_tile
+)
+SELECT
+       19, ST_DumpValues(rast)
+FROM foo;
+
 DROP TABLE IF EXISTS raster_tile;
index 2c04bca53ca1d25314d7f6b4f9d345ea3c3afd84..bb2edfa9adde36c8d8a3c97d75df3f300c7d8378 100644 (file)
@@ -273,3 +273,397 @@ NOTICE:  table "raster_tile" does not exist, skipping
 7|(2,"{{40,40,40,50,50},{70,70,70,80,80},{70,70,70,80,80},{70,70,70,80,80},{NULL,NULL,NULL,NULL,NULL}}")
 7|(1,"{{5,6,6,6,NULL},{8,9,9,9,NULL},{8,9,9,9,NULL},{8,9,9,9,NULL},{NULL,NULL,NULL,NULL,NULL}}")
 7|(2,"{{50,60,60,60,NULL},{80,90,90,90,NULL},{80,90,90,90,NULL},{80,90,90,90,NULL},{NULL,NULL,NULL,NULL,NULL}}")
+8|(1,"{{1,1},{1,1},{1,1}}")
+8|(2,"{{10,10},{10,10},{10,10}}")
+8|(1,"{{1,2},{1,2},{1,2}}")
+8|(2,"{{10,20},{10,20},{10,20}}")
+8|(1,"{{2,2},{2,2},{2,2}}")
+8|(2,"{{20,20},{20,20},{20,20}}")
+8|(1,"{{3,3},{3,3},{3,3}}")
+8|(2,"{{30,30},{30,30},{30,30}}")
+8|(1,"{{3,NULL},{3,NULL},{3,NULL}}")
+8|(2,"{{30,NULL},{30,NULL},{30,NULL}}")
+8|(1,"{{4,4},{4,4},{4,4}}")
+8|(2,"{{40,40},{40,40},{40,40}}")
+8|(1,"{{4,5},{4,5},{4,5}}")
+8|(2,"{{40,50},{40,50},{40,50}}")
+8|(1,"{{5,5},{5,5},{5,5}}")
+8|(2,"{{50,50},{50,50},{50,50}}")
+8|(1,"{{6,6},{6,6},{6,6}}")
+8|(2,"{{60,60},{60,60},{60,60}}")
+8|(1,"{{6,NULL},{6,NULL},{6,NULL}}")
+8|(2,"{{60,NULL},{60,NULL},{60,NULL}}")
+8|(1,"{{7,7},{7,7},{7,7}}")
+8|(2,"{{70,70},{70,70},{70,70}}")
+8|(1,"{{7,8},{7,8},{7,8}}")
+8|(2,"{{70,80},{70,80},{70,80}}")
+8|(1,"{{8,8},{8,8},{8,8}}")
+8|(2,"{{80,80},{80,80},{80,80}}")
+8|(1,"{{9,9},{9,9},{9,9}}")
+8|(2,"{{90,90},{90,90},{90,90}}")
+8|(1,"{{9,NULL},{9,NULL},{9,NULL}}")
+8|(2,"{{90,NULL},{90,NULL},{90,NULL}}")
+9|(1,"{{1,1,1},{1,1,1}}")
+9|(2,"{{10,10,10},{10,10,10}}")
+9|(1,"{{2,2,2},{2,2,2}}")
+9|(2,"{{20,20,20},{20,20,20}}")
+9|(1,"{{3,3,3},{3,3,3}}")
+9|(2,"{{30,30,30},{30,30,30}}")
+9|(1,"{{1,1,1},{4,4,4}}")
+9|(2,"{{10,10,10},{40,40,40}}")
+9|(1,"{{2,2,2},{5,5,5}}")
+9|(2,"{{20,20,20},{50,50,50}}")
+9|(1,"{{3,3,3},{6,6,6}}")
+9|(2,"{{30,30,30},{60,60,60}}")
+9|(1,"{{4,4,4},{4,4,4}}")
+9|(2,"{{40,40,40},{40,40,40}}")
+9|(1,"{{5,5,5},{5,5,5}}")
+9|(2,"{{50,50,50},{50,50,50}}")
+9|(1,"{{6,6,6},{6,6,6}}")
+9|(2,"{{60,60,60},{60,60,60}}")
+9|(1,"{{7,7,7},{7,7,7}}")
+9|(2,"{{70,70,70},{70,70,70}}")
+9|(1,"{{8,8,8},{8,8,8}}")
+9|(2,"{{80,80,80},{80,80,80}}")
+9|(1,"{{9,9,9},{9,9,9}}")
+9|(2,"{{90,90,90},{90,90,90}}")
+9|(1,"{{7,7,7},{NULL,NULL,NULL}}")
+9|(2,"{{70,70,70},{NULL,NULL,NULL}}")
+9|(1,"{{8,8,8},{NULL,NULL,NULL}}")
+9|(2,"{{80,80,80},{NULL,NULL,NULL}}")
+9|(1,"{{9,9,9},{NULL,NULL,NULL}}")
+9|(2,"{{90,90,90},{NULL,NULL,NULL}}")
+11|(1,"{{1,1,1},{1,1,1},{1,1,1}}")
+11|(2,"{{10,10,10},{10,10,10},{10,10,10}}")
+11|(1,"{{2,2,2},{2,2,2},{2,2,2}}")
+11|(2,"{{20,20,20},{20,20,20},{20,20,20}}")
+11|(1,"{{3,3,3},{3,3,3},{3,3,3}}")
+11|(2,"{{30,30,30},{30,30,30},{30,30,30}}")
+11|(1,"{{4,4,4},{4,4,4},{4,4,4}}")
+11|(2,"{{40,40,40},{40,40,40},{40,40,40}}")
+11|(1,"{{5,5,5},{5,5,5},{5,5,5}}")
+11|(2,"{{50,50,50},{50,50,50},{50,50,50}}")
+11|(1,"{{6,6,6},{6,6,6},{6,6,6}}")
+11|(2,"{{60,60,60},{60,60,60},{60,60,60}}")
+11|(1,"{{7,7,7},{7,7,7},{7,7,7}}")
+11|(2,"{{70,70,70},{70,70,70},{70,70,70}}")
+11|(1,"{{8,8,8},{8,8,8},{8,8,8}}")
+11|(2,"{{80,80,80},{80,80,80},{80,80,80}}")
+11|(1,"{{9,9,9},{9,9,9},{9,9,9}}")
+11|(2,"{{90,90,90},{90,90,90},{90,90,90}}")
+12|(1,"{{1,1,1},{1,1,1},{1,1,1}}")
+12|(1,"{{2,2,2},{2,2,2},{2,2,2}}")
+12|(1,"{{3,3,3},{3,3,3},{3,3,3}}")
+12|(1,"{{4,4,4},{4,4,4},{4,4,4}}")
+12|(1,"{{5,5,5},{5,5,5},{5,5,5}}")
+12|(1,"{{6,6,6},{6,6,6},{6,6,6}}")
+12|(1,"{{7,7,7},{7,7,7},{7,7,7}}")
+12|(1,"{{8,8,8},{8,8,8},{8,8,8}}")
+12|(1,"{{9,9,9},{9,9,9},{9,9,9}}")
+13|(1,"{{10,10,10},{10,10,10},{10,10,10}}")
+13|(2,"{{1,1,1},{1,1,1},{1,1,1}}")
+13|(1,"{{20,20,20},{20,20,20},{20,20,20}}")
+13|(2,"{{2,2,2},{2,2,2},{2,2,2}}")
+13|(1,"{{30,30,30},{30,30,30},{30,30,30}}")
+13|(2,"{{3,3,3},{3,3,3},{3,3,3}}")
+13|(1,"{{40,40,40},{40,40,40},{40,40,40}}")
+13|(2,"{{4,4,4},{4,4,4},{4,4,4}}")
+13|(1,"{{50,50,50},{50,50,50},{50,50,50}}")
+13|(2,"{{5,5,5},{5,5,5},{5,5,5}}")
+13|(1,"{{60,60,60},{60,60,60},{60,60,60}}")
+13|(2,"{{6,6,6},{6,6,6},{6,6,6}}")
+13|(1,"{{70,70,70},{70,70,70},{70,70,70}}")
+13|(2,"{{7,7,7},{7,7,7},{7,7,7}}")
+13|(1,"{{80,80,80},{80,80,80},{80,80,80}}")
+13|(2,"{{8,8,8},{8,8,8},{8,8,8}}")
+13|(1,"{{90,90,90},{90,90,90},{90,90,90}}")
+13|(2,"{{9,9,9},{9,9,9},{9,9,9}}")
+14|(1,"{{10,10,10},{10,10,10},{10,10,10}}")
+14|(1,"{{20,20,20},{20,20,20},{20,20,20}}")
+14|(1,"{{30,30,30},{30,30,30},{30,30,30}}")
+14|(1,"{{40,40,40},{40,40,40},{40,40,40}}")
+14|(1,"{{50,50,50},{50,50,50},{50,50,50}}")
+14|(1,"{{60,60,60},{60,60,60},{60,60,60}}")
+14|(1,"{{70,70,70},{70,70,70},{70,70,70}}")
+14|(1,"{{80,80,80},{80,80,80},{80,80,80}}")
+14|(1,"{{90,90,90},{90,90,90},{90,90,90}}")
+15|(1,"{{1,1},{1,1}}")
+15|(2,"{{10,10},{10,10}}")
+15|(1,"{{1,2},{1,2}}")
+15|(2,"{{10,20},{10,20}}")
+15|(1,"{{2,2},{2,2}}")
+15|(2,"{{20,20},{20,20}}")
+15|(1,"{{3,3},{3,3}}")
+15|(2,"{{30,30},{30,30}}")
+15|(1,"{{3},{3}}")
+15|(2,"{{30},{30}}")
+15|(1,"{{1,1},{4,4}}")
+15|(2,"{{10,10},{40,40}}")
+15|(1,"{{1,2},{4,5}}")
+15|(2,"{{10,20},{40,50}}")
+15|(1,"{{2,2},{5,5}}")
+15|(2,"{{20,20},{50,50}}")
+15|(1,"{{3,3},{6,6}}")
+15|(2,"{{30,30},{60,60}}")
+15|(1,"{{3},{6}}")
+15|(2,"{{30},{60}}")
+15|(1,"{{4,4},{4,4}}")
+15|(2,"{{40,40},{40,40}}")
+15|(1,"{{4,5},{4,5}}")
+15|(2,"{{40,50},{40,50}}")
+15|(1,"{{5,5},{5,5}}")
+15|(2,"{{50,50},{50,50}}")
+15|(1,"{{6,6},{6,6}}")
+15|(2,"{{60,60},{60,60}}")
+15|(1,"{{6},{6}}")
+15|(2,"{{60},{60}}")
+15|(1,"{{7,7},{7,7}}")
+15|(2,"{{70,70},{70,70}}")
+15|(1,"{{7,8},{7,8}}")
+15|(2,"{{70,80},{70,80}}")
+15|(1,"{{8,8},{8,8}}")
+15|(2,"{{80,80},{80,80}}")
+15|(1,"{{9,9},{9,9}}")
+15|(2,"{{90,90},{90,90}}")
+15|(1,"{{9},{9}}")
+15|(2,"{{90},{90}}")
+15|(1,"{{7,7}}")
+15|(2,"{{70,70}}")
+15|(1,"{{7,8}}")
+15|(2,"{{70,80}}")
+15|(1,"{{8,8}}")
+15|(2,"{{80,80}}")
+15|(1,"{{9,9}}")
+15|(2,"{{90,90}}")
+15|(1,{{9}})
+15|(2,{{90}})
+16|(1,{{1}})
+16|(2,{{10}})
+16|(1,{{1}})
+16|(2,{{10}})
+16|(1,{{1}})
+16|(2,{{10}})
+16|(1,{{2}})
+16|(2,{{20}})
+16|(1,{{2}})
+16|(2,{{20}})
+16|(1,{{2}})
+16|(2,{{20}})
+16|(1,{{3}})
+16|(2,{{30}})
+16|(1,{{3}})
+16|(2,{{30}})
+16|(1,{{3}})
+16|(2,{{30}})
+16|(1,{{1}})
+16|(2,{{10}})
+16|(1,{{1}})
+16|(2,{{10}})
+16|(1,{{1}})
+16|(2,{{10}})
+16|(1,{{2}})
+16|(2,{{20}})
+16|(1,{{2}})
+16|(2,{{20}})
+16|(1,{{2}})
+16|(2,{{20}})
+16|(1,{{3}})
+16|(2,{{30}})
+16|(1,{{3}})
+16|(2,{{30}})
+16|(1,{{3}})
+16|(2,{{30}})
+16|(1,{{1}})
+16|(2,{{10}})
+16|(1,{{1}})
+16|(2,{{10}})
+16|(1,{{1}})
+16|(2,{{10}})
+16|(1,{{2}})
+16|(2,{{20}})
+16|(1,{{2}})
+16|(2,{{20}})
+16|(1,{{2}})
+16|(2,{{20}})
+16|(1,{{3}})
+16|(2,{{30}})
+16|(1,{{3}})
+16|(2,{{30}})
+16|(1,{{3}})
+16|(2,{{30}})
+16|(1,{{4}})
+16|(2,{{40}})
+16|(1,{{4}})
+16|(2,{{40}})
+16|(1,{{4}})
+16|(2,{{40}})
+16|(1,{{5}})
+16|(2,{{50}})
+16|(1,{{5}})
+16|(2,{{50}})
+16|(1,{{5}})
+16|(2,{{50}})
+16|(1,{{6}})
+16|(2,{{60}})
+16|(1,{{6}})
+16|(2,{{60}})
+16|(1,{{6}})
+16|(2,{{60}})
+16|(1,{{4}})
+16|(2,{{40}})
+16|(1,{{4}})
+16|(2,{{40}})
+16|(1,{{4}})
+16|(2,{{40}})
+16|(1,{{5}})
+16|(2,{{50}})
+16|(1,{{5}})
+16|(2,{{50}})
+16|(1,{{5}})
+16|(2,{{50}})
+16|(1,{{6}})
+16|(2,{{60}})
+16|(1,{{6}})
+16|(2,{{60}})
+16|(1,{{6}})
+16|(2,{{60}})
+16|(1,{{4}})
+16|(2,{{40}})
+16|(1,{{4}})
+16|(2,{{40}})
+16|(1,{{4}})
+16|(2,{{40}})
+16|(1,{{5}})
+16|(2,{{50}})
+16|(1,{{5}})
+16|(2,{{50}})
+16|(1,{{5}})
+16|(2,{{50}})
+16|(1,{{6}})
+16|(2,{{60}})
+16|(1,{{6}})
+16|(2,{{60}})
+16|(1,{{6}})
+16|(2,{{60}})
+16|(1,{{7}})
+16|(2,{{70}})
+16|(1,{{7}})
+16|(2,{{70}})
+16|(1,{{7}})
+16|(2,{{70}})
+16|(1,{{8}})
+16|(2,{{80}})
+16|(1,{{8}})
+16|(2,{{80}})
+16|(1,{{8}})
+16|(2,{{80}})
+16|(1,{{9}})
+16|(2,{{90}})
+16|(1,{{9}})
+16|(2,{{90}})
+16|(1,{{9}})
+16|(2,{{90}})
+16|(1,{{7}})
+16|(2,{{70}})
+16|(1,{{7}})
+16|(2,{{70}})
+16|(1,{{7}})
+16|(2,{{70}})
+16|(1,{{8}})
+16|(2,{{80}})
+16|(1,{{8}})
+16|(2,{{80}})
+16|(1,{{8}})
+16|(2,{{80}})
+16|(1,{{9}})
+16|(2,{{90}})
+16|(1,{{9}})
+16|(2,{{90}})
+16|(1,{{9}})
+16|(2,{{90}})
+16|(1,{{7}})
+16|(2,{{70}})
+16|(1,{{7}})
+16|(2,{{70}})
+16|(1,{{7}})
+16|(2,{{70}})
+16|(1,{{8}})
+16|(2,{{80}})
+16|(1,{{8}})
+16|(2,{{80}})
+16|(1,{{8}})
+16|(2,{{80}})
+16|(1,{{9}})
+16|(2,{{90}})
+16|(1,{{9}})
+16|(2,{{90}})
+16|(1,{{9}})
+16|(2,{{90}})
+17|(1,"{{1,1,1,2,2},{1,1,1,2,2},{1,1,1,2,2},{4,4,4,5,5},{4,4,4,5,5}}")
+17|(2,"{{10,10,10,20,20},{10,10,10,20,20},{10,10,10,20,20},{40,40,40,50,50},{40,40,40,50,50}}")
+17|(1,"{{2,3,3,3},{2,3,3,3},{2,3,3,3},{5,6,6,6},{5,6,6,6}}")
+17|(2,"{{20,30,30,30},{20,30,30,30},{20,30,30,30},{50,60,60,60},{50,60,60,60}}")
+17|(1,"{{4,4,4,5,5},{7,7,7,8,8},{7,7,7,8,8},{7,7,7,8,8}}")
+17|(2,"{{40,40,40,50,50},{70,70,70,80,80},{70,70,70,80,80},{70,70,70,80,80}}")
+17|(1,"{{5,6,6,6},{8,9,9,9},{8,9,9,9},{8,9,9,9}}")
+17|(2,"{{50,60,60,60},{80,90,90,90},{80,90,90,90},{80,90,90,90}}")
+18|(1,"{{1,1},{1,1},{1,1}}")
+18|(2,"{{10,10},{10,10},{10,10}}")
+18|(1,"{{1,2},{1,2},{1,2}}")
+18|(2,"{{10,20},{10,20},{10,20}}")
+18|(1,"{{2,2},{2,2},{2,2}}")
+18|(2,"{{20,20},{20,20},{20,20}}")
+18|(1,"{{3,3},{3,3},{3,3}}")
+18|(2,"{{30,30},{30,30},{30,30}}")
+18|(1,"{{3},{3},{3}}")
+18|(2,"{{30},{30},{30}}")
+18|(1,"{{4,4},{4,4},{4,4}}")
+18|(2,"{{40,40},{40,40},{40,40}}")
+18|(1,"{{4,5},{4,5},{4,5}}")
+18|(2,"{{40,50},{40,50},{40,50}}")
+18|(1,"{{5,5},{5,5},{5,5}}")
+18|(2,"{{50,50},{50,50},{50,50}}")
+18|(1,"{{6,6},{6,6},{6,6}}")
+18|(2,"{{60,60},{60,60},{60,60}}")
+18|(1,"{{6},{6},{6}}")
+18|(2,"{{60},{60},{60}}")
+18|(1,"{{7,7},{7,7},{7,7}}")
+18|(2,"{{70,70},{70,70},{70,70}}")
+18|(1,"{{7,8},{7,8},{7,8}}")
+18|(2,"{{70,80},{70,80},{70,80}}")
+18|(1,"{{8,8},{8,8},{8,8}}")
+18|(2,"{{80,80},{80,80},{80,80}}")
+18|(1,"{{9,9},{9,9},{9,9}}")
+18|(2,"{{90,90},{90,90},{90,90}}")
+18|(1,"{{9},{9},{9}}")
+18|(2,"{{90},{90},{90}}")
+19|(1,"{{1,1,1},{1,1,1}}")
+19|(2,"{{10,10,10},{10,10,10}}")
+19|(1,"{{2,2,2},{2,2,2}}")
+19|(2,"{{20,20,20},{20,20,20}}")
+19|(1,"{{3,3,3},{3,3,3}}")
+19|(2,"{{30,30,30},{30,30,30}}")
+19|(1,"{{1,1,1},{4,4,4}}")
+19|(2,"{{10,10,10},{40,40,40}}")
+19|(1,"{{2,2,2},{5,5,5}}")
+19|(2,"{{20,20,20},{50,50,50}}")
+19|(1,"{{3,3,3},{6,6,6}}")
+19|(2,"{{30,30,30},{60,60,60}}")
+19|(1,"{{4,4,4},{4,4,4}}")
+19|(2,"{{40,40,40},{40,40,40}}")
+19|(1,"{{5,5,5},{5,5,5}}")
+19|(2,"{{50,50,50},{50,50,50}}")
+19|(1,"{{6,6,6},{6,6,6}}")
+19|(2,"{{60,60,60},{60,60,60}}")
+19|(1,"{{7,7,7},{7,7,7}}")
+19|(2,"{{70,70,70},{70,70,70}}")
+19|(1,"{{8,8,8},{8,8,8}}")
+19|(2,"{{80,80,80},{80,80,80}}")
+19|(1,"{{9,9,9},{9,9,9}}")
+19|(2,"{{90,90,90},{90,90,90}}")
+19|(1,"{{7,7,7}}")
+19|(2,"{{70,70,70}}")
+19|(1,"{{8,8,8}}")
+19|(2,"{{80,80,80}}")
+19|(1,"{{9,9,9}}")
+19|(2,"{{90,90,90}}")