]> granicus.if.org Git - postgis/commitdiff
Fix for ticket 1536. Added a nodataval[] parameter to ST_Intersection and removed...
authorPierre Racine <Pierre.Racine@sbf.ulaval.ca>
Wed, 29 Feb 2012 02:47:35 +0000 (02:47 +0000)
committerPierre Racine <Pierre.Racine@sbf.ulaval.ca>
Wed, 29 Feb 2012 02:47:35 +0000 (02:47 +0000)
Changed the ST_Clip trimraster parameter name to crop and set it to true by default.

Updated the doc.

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

doc/reference_raster.xml
raster/rt_pg/rtpostgis.sql.in.c
raster/test/regress/rt_clip.sql
raster/test/regress/rt_intersection.sql
raster/test/regress/rt_intersection_expected

index 125f2c4775895c6384d58d12de54edb952f659e6..90ad4873753b5387144812d11a22bde14378666c 100644 (file)
@@ -5099,8 +5099,8 @@ rid |        rastbox
                <refentry id="RT_ST_Clip">
                        <refnamediv>
                                <refname>ST_Clip</refname>
-                               <refpurpose>Returns the raster clipped by the input geometry.  If no band is specified all bands are returned. If trimraster setting is not specified, false is assumed meaning
-                               the output raster has the same extent as the input raster.</refpurpose>
+                               <refpurpose>Returns the raster clipped by the input geometry.  If no band is specified all bands are returned. If <varname>crop</varname> is not specified, true is assumed meaning
+                               the output raster is cropped.</refpurpose>
                        </refnamediv>
                
                        <refsynopsisdiv>
@@ -5109,41 +5109,15 @@ rid |        rastbox
                                        <funcdef>raster <function>ST_Clip</function></funcdef>
                                        <paramdef><type>raster </type> <parameter>rast</parameter></paramdef>
                                        <paramdef><type>geometry </type> <parameter>geom</parameter></paramdef>
-                                       <paramdef choice='opt'><type>double precision[] </type> <parameter>nodata=NULL</parameter></paramdef>
-                                       <paramdef choice='opt'><type>boolean </type> <parameter>trimraster=false</parameter></paramdef>
-                                 </funcprototype>
-                                 
-                                <funcprototype>
-                                       <funcdef>raster <function>ST_Clip</function></funcdef>
-                                       <paramdef><type>raster </type> <parameter>rast</parameter></paramdef>
-                                       <paramdef><type>integer </type> <parameter>band</parameter></paramdef>
-                                       <paramdef><type>geometry </type> <parameter>geom</parameter></paramdef>
-                                       <paramdef choice='opt'><type>double precision[] </type> <parameter>nodata=NULL</parameter></paramdef>
-                                       <paramdef choice='opt'><type>boolean </type> <parameter>trimraster=false</parameter></paramdef>
-                                 </funcprototype>
-                                 
-                                 <funcprototype>
-                                       <funcdef>raster <function>ST_Clip</function></funcdef>
-                                       <paramdef><type>raster </type> <parameter>rast</parameter></paramdef>
-                                       <paramdef><type>geometry </type> <parameter>geom</parameter></paramdef>
-                                       <paramdef><type>double precision </type> <parameter>nodata</parameter></paramdef>
-                                       <paramdef choice='opt'><type>boolean </type> <parameter>trimraster=false</parameter></paramdef>
-                                 </funcprototype>
-                                 
-                                <funcprototype>
-                                       <funcdef>raster <function>ST_Clip</function></funcdef>
-                                       <paramdef><type>raster </type> <parameter>rast</parameter></paramdef>
-                                       <paramdef><type>integer </type> <parameter>band</parameter></paramdef>
-                                       <paramdef><type>geometry </type> <parameter>geom</parameter></paramdef>
-                                       <paramdef choice='opt'><type>double precision </type> <parameter>nodata=NULL</parameter></paramdef>
-                                       <paramdef choice='opt'><type>boolean </type> <parameter>trimraster=false</parameter></paramdef>
+                                       <paramdef choice='opt'><type>double precision[] </type> <parameter>nodataval=NULL</parameter></paramdef>
+                                       <paramdef choice='opt'><type>boolean </type> <parameter>crop=true</parameter></paramdef>
                                  </funcprototype>
                                  
                                  <funcprototype>
                                        <funcdef>raster <function>ST_Clip</function></funcdef>
                                        <paramdef><type>raster </type> <parameter>rast</parameter></paramdef>
                                        <paramdef><type>geometry </type> <parameter>geom</parameter></paramdef>
-                                       <paramdef><type>boolean </type> <parameter>trimraster</parameter></paramdef>
+                                       <paramdef><type>boolean </type> <parameter>crop</parameter></paramdef>
                                  </funcprototype>
                                  
                                 <funcprototype>
@@ -5151,7 +5125,7 @@ rid |        rastbox
                                        <paramdef><type>raster </type> <parameter>rast</parameter></paramdef>
                                        <paramdef><type>integer </type> <parameter>band</parameter></paramdef>
                                        <paramdef><type>geometry </type> <parameter>geom</parameter></paramdef>
-                                       <paramdef><type>boolean </type> <parameter>trimraster</parameter></paramdef>
+                                       <paramdef><type>boolean </type> <parameter>crop</parameter></paramdef>
                                  </funcprototype>
                                </funcsynopsis>
                        </refsynopsisdiv>
@@ -5159,10 +5133,14 @@ rid |        rastbox
                        <refsection>
                                <title>Description</title>
                                
-                               <para>Returns a raster that is clipped by the input geometry <varname>geom</varname>.  If no band is specified all bands are returned.</para>
-                               <para>An array of nodata values replacing the nodata values of the input raster can be provided, one for each band. Some variants also accept a single value. If none are provided and the input raster do not have a nodata value defined, nodata values of the resulting raster are set to ST_MinPossibleValue(ST_BandPixelType(rast, band)). When the number of nodata value in the array is smaller than the number of band, the last one in the array is used for the remaining bands. If the number of nodata value is greater than the number of band, the extra nodata values are ignored.</para>
-                               <para>If trimraster setting is not specified, false is assumed meaning the output raster has the same extent as the input raster. If <varname>trimraster</varname> is set to true, the new raster has the same extent as the intersection of <varname>geom</varname>and <varname>rast</varname>.</para>
+                               <para>Returns a raster that is clipped by the input geometry <varname>geom</varname>. If no band is specified all bands are returned.</para>
+                               
+                               <para>Rasters resulting from ST_Clip must have a nodata value assigned for areas clipped, one for each band. If none are provided and the input raster do not have a nodata value defined, nodata values of the resulting raster are set to ST_MinPossibleValue(ST_BandPixelType(rast, band)). When the number of nodata value in the array is smaller than the number of band, the last one in the array is used for the remaining bands. If the number of nodata value is greater than the number of band, the extra nodata values are ignored. All variants accepting an array of nodata values also accept a single value which will be assigned to each band.</para>        
+
+                               <para>If <varname>crop</varname> is not specified, true is assumed meaning the output raster is cropped to the intersection of the <varname>geom</varname>and <varname>rast</varname> extents. If <varname>crop</varname> is set to false, the new raster gets the same extent as <varname>rast</varname>.</para>
+                               
                                <para>Availability: 2.0.0 </para>
+                               
                                <para>Examples here use Massachusetts aerial data available on MassGIS site <ulink url="http://www.mass.gov/mgis/colororthos2008.htm">MassGIS Aerial Orthos</ulink>. Coordinates are in Massachusetts State Plane Meters.</para>
                        </refsection>
                                
@@ -5174,12 +5152,12 @@ SELECT ST_Clip(rast, 1,
        ) from aerials.boston
 WHERE rid = 4;</programlisting>
 
-<programlisting>-- Demonstrate effect of trimraster on final dimensions of raster
--- Note how in trimmed final envelope is clipped to that of the clipper
--- if trimraster = true
-SELECT ST_XMax(ST_Envelope(ST_Clip(rast,1,clipper,true))) As xmax_w_trim,
+<programlisting>-- Demonstrate effect of crop on final dimensions of raster
+-- Note how final extent is clipped to that of the geometry
+-- if crop = true
+SELECT ST_XMax(ST_Envelope(ST_Clip(rast, 1, clipper, true))) As xmax_w_trim,
        ST_XMax(clipper) As xmax_clipper,
-       ST_XMax(ST_Envelope(ST_Clip(rast,1,clipper,false))) As xmax_wo_trim,
+       ST_XMax(ST_Envelope(ST_Clip(rast, 1, clipper, false))) As xmax_wo_trim,
        ST_XMax(ST_Envelope(rast)) As xmax_rast_orig
 FROM (SELECT rast, ST_Buffer(ST_Centroid(ST_Envelope(rast)),6) As clipper
        FROM aerials.boston
@@ -5222,7 +5200,8 @@ WHERE rid = 6) As foo;
 -- Only difference is we don't specify a specific band to clip
 -- so all bands are clipped
 SELECT ST_Clip(rast,
-               ST_Buffer(ST_Centroid(ST_Envelope(rast)),20)
+         ST_Buffer(ST_Centroid(ST_Envelope(rast)), 20), 
+         false
        ) from aerials.boston
 WHERE rid = 4;</programlisting>
 
@@ -5640,33 +5619,31 @@ FROM dummy_rast;
                                  </funcprototype>
                                  
                                  <funcprototype>
-                                       <funcdef>raster <function>ST_Intersection</function></funcdef>
+                                       <funcdef>setof geomval <function>ST_Intersection</function></funcdef>
                                        <paramdef><type>raster </type> <parameter>rast</parameter></paramdef>
                                        <paramdef><type>geometry </type> <parameter>geom</parameter></paramdef>
-                                       <paramdef choice='opt'><type>regprocedure </type> <parameter>otheruserfunc=NULL</parameter></paramdef>
                                  </funcprototype>
                                  
                                  <funcprototype>
-                                       <funcdef>raster <function>ST_Intersection</function></funcdef>
+                                       <funcdef>setof geomval <function>ST_Intersection</function></funcdef>
                                        <paramdef><type>raster </type> <parameter>rast</parameter></paramdef>
                                        <paramdef><type>integer </type> <parameter>band_num</parameter></paramdef>
                                        <paramdef><type>geometry </type> <parameter>geom</parameter></paramdef>
-                                       <paramdef choice='opt'><type>regprocedure </type> <parameter>otheruserfunc=NULL</parameter></paramdef>
                                  </funcprototype>
 
                                  <funcprototype>
                                        <funcdef>raster <function>ST_Intersection</function></funcdef>
                                        <paramdef><type>raster </type> <parameter>rast1</parameter></paramdef>
                                        <paramdef><type>raster </type> <parameter>rast2</parameter></paramdef>
-                                       <paramdef choice='opt'><type>text </type> <parameter>returnband='BOTH'</parameter></paramdef>
-                                       <paramdef choice='opt'><type>regprocedure </type> <parameter>otheruserfunc=NULL</parameter></paramdef>
+                                       <paramdef'><type>double precision[] </type> <parameter>nodataval</parameter></paramdef>
                                  </funcprototype>
 
                                  <funcprototype>
                                        <funcdef>raster <function>ST_Intersection</function></funcdef>
                                        <paramdef><type>raster </type> <parameter>rast1</parameter></paramdef>
                                        <paramdef><type>raster </type> <parameter>rast2</parameter></paramdef>
-                                       <paramdef choice='opt'><type>regprocedure </type> <parameter>otheruserfunc=NULL</parameter></paramdef>
+                                       <paramdef choice='opt'><type>text </type> <parameter>returnband='BOTH'</parameter></paramdef>
+                                       <paramdef choice='opt'><type>double precision[] </type> <parameter>nodataval=NULL</parameter></paramdef>
                                  </funcprototype>
 
                                  <funcprototype>
@@ -5675,7 +5652,7 @@ FROM dummy_rast;
                                        <paramdef><type>integer </type> <parameter>band_num1</parameter></paramdef>
                                        <paramdef><type>raster </type> <parameter>rast2</parameter></paramdef>
                                        <paramdef><type>integer </type> <parameter>band_num2</parameter></paramdef>
-                                       <paramdef><type>regprocedure </type> <parameter>otheruserfunc</parameter></paramdef>
+                                       <paramdef><type>double precision[] </type> <parameter>nodataval</parameter></paramdef>
                                  </funcprototype>
 
                                  <funcprototype>
@@ -5684,8 +5661,8 @@ FROM dummy_rast;
                                        <paramdef><type>integer </type> <parameter>band_num1</parameter></paramdef>
                                        <paramdef><type>raster </type> <parameter>rast2</parameter></paramdef>
                                        <paramdef><type>integer </type> <parameter>band_num2</parameter></paramdef>
-                                       <paramdef><type>text </type> <parameter>returnband</parameter></paramdef>
-                                       <paramdef choice='opt'><type>regprocedure </type> <parameter>otheruserfunc=NULL</parameter></paramdef>
+                                       <paramdef choice='opt'><type>text </type> <parameter>returnband='BOTH'</parameter></paramdef>
+                                       <paramdef choice='opt'><type>double precision[] </type> <parameter>nodataval=NULL</parameter></paramdef>
                                  </funcprototype>
 
                                </funcsynopsis>
@@ -5693,27 +5670,27 @@ FROM dummy_rast;
                
                        <refsection>
                                <title>Description</title>
-                               <para>Returns a raster or a set of geometry-pixelvalue pairs representing the shared portion of two rasters or the geometrical intersection of a vectorization of the raster and a geometry. The order in which the geometry or the raster are passed determine if the operation is performed in vector or raster world.</para>
+                               <para>Returns a raster or a set of geometry-pixelvalue pairs representing the shared portion of two rasters or the geometrical intersection of a vectorization of the raster and a geometry.</para>
                                
-                               <para>The first variant, returning a setof geomval, works in vector world. The raster is first vectorized (using ST_DumpAsPolygon) into a set of geomval rows and those rows are then intersected with the geometry using the ST_Intersection(geometry, geometry) PostGIS function. Geometries intersecting only with a nodata value area of a raster returns an empty geometry. They are normally excluded from the results by the proper usage of ST_Intersect in the WHERE clause.</para>
+                               <para>The first three variants, returning a setof geomval, works in vector space. The raster is first vectorized (using ST_DumpAsPolygon) into a set of geomval rows and those rows are then intersected with the geometry using the ST_Intersection(geometry, geometry) PostGIS function. Geometries intersecting only with a nodata value area of a raster returns an empty geometry. They are normally excluded from the results by the proper usage of ST_Intersect in the WHERE clause.</para>
                                
                                <para>You can access the geometry and the value parts of the resulting set of geomval by surrounding them with parenthesis and adding '.geom' or '.val' at the end of the expression. e.g. (ST_Intersection(rast, geom)).geom</para>
                                
-                               <para>The other variants, returning a raster, works in raster world. They are using the two rasters version of ST_MapAlgebraExpr to perform the intersection. In the variants taking a geometry, the geometry is rasterized (using ST_AsRaster) before being passed to ST_MapAlgebraExpr.</para>
+                               <para>The other variants, returning a raster, works in raster space. They are using the two rasters version of ST_MapAlgebraExpr to perform the intersection.</para>
                                
-                               <para>The extent of the resulting raster corresponds to the geometrical intersection of the two raster extents. The resulting raster includes the bands from the 'FIRST', 'SECOND' or 'BOTH' rasters following what is passed as the returnband parameter. Nodata value areas present in any band results in nodata value areas in every bands of the result. In other word, any pixel intersecting with a nodata value pixel in the other raster a nodata value pixel in the resulting band if it is returned.</para>
+                               <para>The extent of the resulting raster corresponds to the geometrical intersection of the two raster extents. The resulting raster includes 'BAND1', 'BAND2' or 'BOTH' bands, following what is passed as the <varname>returnband</varname> parameter. Nodata value areas present in any band results in nodata value areas in every bands of the result. In other words, any pixel intersecting with a nodata value pixel becomes a nodata value pixel in the result.</para>
                                
-                               <para>You can optionally produce a one band raster and control the values it contains by providing a custom function of type regprocedure accepting two double precision values. See <xref linkend="RT_ST_MapAlgebraFct2" /> for an example on how to do that.</para>
+                               <para>Rasters resulting from ST_Intersection must have a nodata value assigned for areas not intersecting. You can define or replace the nodata value for any resulting band by providing a <varname>nodataval[]</varname> array of one or two nodata values depending if you request 'BAND1', 'BAND2' or 'BOTH' bands. The first value in the array replace the nodata value in the first band and the second value replace the nodata value in the second band. If one input band do not have a nodata value defined and none are provided as an array, one is chosen using the ST_MinPossibleValue function. All variant accepting an array of nodata value can also accept a single value which will be assigned to each requested band.</para>        
                                
                                <para>In all variants, if no band number is specified band 1 is assumed.</para>        
                                
                                <note><para>To get more control on the resulting extent or on what to return when encountering a nodata value, use the two rasters version of <xref linkend="RT_ST_MapAlgebraExpr2" />.</para></note>
                                
-                               <note><para>The variants returning a raster and taking a geometry are very similar to ST_Clip with the exception that ST_Clip() works on multiple band rasters and never returns a band corresponding to the rasterized geometry. ST_Intersection(raster, geometry) works only on one band and may return a band corresponding to the rasterized geometry (when 'BOTH' or 'SECOND' are passed as the returnband parameter).</para></note>
+                               <note><para>To compute the intersection of a raster band with a geometry in raster space, use <xref linkend="RT_ST_Clip". ST_Clip works on multiple bands rasters and does not return a band corresponding to the rasterized geometry.</para></note>
                                
-                               <note><para>ST_Intersection() Should be used in conjunction with ST_Intersects and an index on the raster column or the geometry column.</para></note>
+                               <note><para>ST_Intersection should be used in conjunction with ST_Intersects and an index on the raster column and/or the geometry column.</para></note>
 
-                               <para>Enhanced: 2.0.0 - Intersection in the raster world was introduced. In earlier pre-2.0.0 versions, only intersection performed in vector world were supported.</para>
+                               <para>Enhanced: 2.0.0 - Intersection in the raster space was introduced. In earlier pre-2.0.0 versions, only intersection performed in vector space were supported.</para>
                                </refsection>
                                
                                <refsection>
@@ -6614,7 +6591,7 @@ SELECT ST_MapAlgebraFct(m1.rast, 1, m1.rast, 3,
                                        </varlistentry>
                                        <varlistentry>
                                                <term>pixeltype</term>
-                                               <listitem><para>The resulting pixel type of the output raster.  Must be one listed in <xref linkend='RT_ST_BandPixelType' /> or left out or set to NULL.  If not passed in or set to NULL, will default to the pixeltype of the <varname>rast</varname>. Results are truncated if they are larger than what is allowed for the pixeltype</para></listitem>
+                                               <listitem><para>The resulting pixel type of the output raster.  Must be one listed in <xref linkend='RT_ST_BandPixelType' /> or left out or set to NULL.  If not passed in or set to NULL, will default to the pixeltype of the <varname>rast</varname>. Results are truncated if they are larger than what is allowed for the pixeltype.</para></listitem>
                                        </varlistentry>
                                        <varlistentry>
                                                <term>ngbwidth</term>
index 244b5915b5a7f3648657635457fcbb56213d1999..b1adfd59f86db0d3d43359d7eb70c795d043c40f 100644 (file)
@@ -3155,7 +3155,6 @@ CREATE OR REPLACE FUNCTION st_intersects(geom geometry, rast raster, nband integ
 -----------------------------------------------------------------------
 -- ST_Intersection (geometry, raster in vector space)
 -----------------------------------------------------------------------
-
 CREATE OR REPLACE FUNCTION st_intersection(geomin geometry, rast raster, band integer DEFAULT 1)
        RETURNS SETOF geomval AS $$
        DECLARE
@@ -3191,46 +3190,54 @@ CREATE OR REPLACE FUNCTION st_intersection(geomin geometry, rast raster, band in
        $$
        LANGUAGE 'plpgsql' IMMUTABLE STRICT;
 
+CREATE OR REPLACE FUNCTION st_intersection(rast raster, band integer, geomin geometry)
+       RETURNS SETOF geomval AS
+       $$ SELECT st_intersection($3, $1, $2) $$
+       LANGUAGE 'sql' STABLE;
+
+CREATE OR REPLACE FUNCTION st_intersection(rast raster, geomin geometry)
+       RETURNS SETOF geomval AS
+       $$ SELECT st_intersection($2, $1, 1) $$
+       LANGUAGE 'sql' STABLE;
+
 -----------------------------------------------------------------------
 -- ST_Intersection (2-raster in raster space)
 -----------------------------------------------------------------------
-
 CREATE OR REPLACE FUNCTION st_intersection(
        rast1 raster, band1 int,
        rast2 raster, band2 int,
        returnband text DEFAULT 'BOTH',
-       otheruserfunc regprocedure DEFAULT NULL
+       nodataval double precision[] DEFAULT NULL
 )
        RETURNS raster
        AS $$
        DECLARE
                rtn raster;
                _returnband text;
+               newnodata1 float8;
+               newnodata2 float8;
        BEGIN
-               -- returnband
+               newnodata1 := coalesce(nodataval[1], ST_BandNodataValue(rast1, band1), ST_MinPossibleValue(ST_BandPixelType(rast1, band1)));
+               newnodata2 := coalesce(nodataval[2], ST_BandNodataValue(rast2, band2), ST_MinPossibleValue(ST_BandPixelType(rast2, band2)));
+               
                _returnband := upper(returnband);
-               IF _returnband NOT IN ('FIRST', 'SECOND', 'BOTH', 'OTHER') THEN
-                       RAISE EXCEPTION 'Unknown value provided for returnband: %', returnband;
-                       RETURN NULL;
-               END IF;
-
-               -- returnband is OTHER, otheruserfunc provided?
-               IF _returnband = 'OTHER' AND otheruserfunc IS NULL THEN
-                       RAISE EXCEPTION 'Function must be provided for otheruserfunc if return band is OTHER';
-                       RETURN NULL;
-               END IF;
 
                rtn := NULL;
                CASE
-                       WHEN _returnband = 'FIRST' THEN
-                               rtn := ST_MapAlgebraExpr(rast1, band1, rast2, band2, '[rast1.val]', ST_BandPixelType(rast1, band1), 'INTERSECTION');
-                       WHEN _returnband = 'SECOND' THEN
-                               rtn := ST_MapAlgebraExpr(rast1, band1, rast2, band2, '[rast2.val]', ST_BandPixelType(rast2, band2), 'INTERSECTION');
-                       WHEN _returnband = 'OTHER' THEN
-                               rtn := ST_MapAlgebraFct(rast1, band1, rast2, band2, otheruserfunc, NULL, 'INTERSECTION');
-                       ELSE -- BOTH
-                               rtn := ST_MapAlgebraExpr(rast1, band1, rast2, band2, '[rast1.val]', ST_BandPixelType(rast1, band1), 'INTERSECTION');
-                               rtn := ST_AddBand(rtn, ST_MapAlgebraExpr(rast1, band1, rast2, band2, '[rast2.val]', ST_BandPixelType(rast2, band2), 'INTERSECTION'));
+                       WHEN _returnband = 'BAND1' THEN
+                               rtn := ST_MapAlgebraExpr(rast1, band1, rast2, band2, '[rast1.val]', ST_BandPixelType(rast1, band1), 'INTERSECTION', newnodata1::text, newnodata1::text, newnodata1);
+                               rtn := ST_SetBandNodataValue(rtn, 1, newnodata1);
+                       WHEN _returnband = 'BAND2' THEN
+                               rtn := ST_MapAlgebraExpr(rast1, band1, rast2, band2, '[rast2.val]', ST_BandPixelType(rast2, band2), 'INTERSECTION', newnodata2::text, newnodata2::text, newnodata2);
+                               rtn := ST_SetBandNodataValue(rtn, 1, newnodata2);
+                       WHEN _returnband = 'BOTH' THEN
+                               rtn := ST_MapAlgebraExpr(rast1, band1, rast2, band2, '[rast1.val]', ST_BandPixelType(rast1, band1), 'INTERSECTION', newnodata1::text, newnodata1::text, newnodata1);
+                               rtn := ST_SetBandNodataValue(rtn, 1, newnodata1);
+                               rtn := ST_AddBand(rtn, ST_MapAlgebraExpr(rast1, band1, rast2, band2, '[rast2.val]', ST_BandPixelType(rast2, band2), 'INTERSECTION', newnodata2::text, newnodata2::text, newnodata2));
+                               rtn := ST_SetBandNodataValue(rtn, 2, newnodata2);
+                       ELSE
+                               RAISE EXCEPTION 'Unknown value provided for returnband: %', returnband;
+                               RETURN NULL;
                END CASE;
 
                RETURN rtn;
@@ -3240,17 +3247,37 @@ CREATE OR REPLACE FUNCTION st_intersection(
 CREATE OR REPLACE FUNCTION st_intersection(
        rast1 raster, band1 int,
        rast2 raster, band2 int,
-       otheruserfunc regprocedure
+       returnband text,
+       nodataval double precision
+)
+       RETURNS raster AS
+       $$ SELECT st_intersection($1, $2, $3, $4, $5, ARRAY[$6, $6]) $$
+       LANGUAGE 'sql' STABLE;
+
+CREATE OR REPLACE FUNCTION st_intersection(
+       rast1 raster, band1 int,
+       rast2 raster, band2 int,
+       nodataval double precision[]
 )
        RETURNS raster AS
-       $$ SELECT st_intersection($1, $2, $3, $4, 'OTHER', $5) $$
+       $$ SELECT st_intersection($1, $2, $3, $4, 'BOTH', $5) $$
        LANGUAGE 'sql' STABLE;
 
+CREATE OR REPLACE FUNCTION st_intersection(
+       rast1 raster, band1 int,
+       rast2 raster, band2 int,
+       nodataval double precision
+)
+       RETURNS raster AS
+       $$ SELECT st_intersection($1, $2, $3, $4, 'BOTH', ARRAY[$5, $5]) $$
+       LANGUAGE 'sql' STABLE;
+
+-- Variants without band number
 CREATE OR REPLACE FUNCTION st_intersection(
        rast1 raster,
        rast2 raster,
        returnband text DEFAULT 'BOTH',
-       otheruserfunc regprocedure DEFAULT NULL
+       nodataval double precision[] DEFAULT NULL
 )
        RETURNS raster AS
        $$ SELECT st_intersection($1, 1, $2, 1, $3, $4) $$
@@ -3259,44 +3286,29 @@ CREATE OR REPLACE FUNCTION st_intersection(
 CREATE OR REPLACE FUNCTION st_intersection(
        rast1 raster,
        rast2 raster,
-       otheruserfunc regprocedure
+       returnband text,
+       nodataval double precision
 )
        RETURNS raster AS
-       $$ SELECT st_intersection($1, 1, $2, 1, 'OTHER', $3) $$
+       $$ SELECT st_intersection($1, 1, $2, 1, $3, ARRAY[$4, $4]) $$
        LANGUAGE 'sql' STABLE;
 
------------------------------------------------------------------------
--- ST_Intersection (raster, geometry in raster space)
------------------------------------------------------------------------
-
 CREATE OR REPLACE FUNCTION st_intersection(
-       rast raster, band int,
-       geom geometry,
-       otheruserfunc regprocedure DEFAULT NULL
+       rast1 raster,
+       rast2 raster,
+       nodataval double precision[]
 )
-       RETURNS raster AS $$
-       DECLARE
-               rtn raster;
-       BEGIN
-               rtn := NULL;
-
-               IF $4 IS NULL THEN
-                       rtn := st_intersection($1, $2, ST_AsRaster($3, $1), 1, 'FIRST');
-               ELSE
-                       rtn := st_intersection($1, $2, ST_AsRaster($3, $1), 1, 'OTHER', $4);
-               END IF;
-
-               RETURN rtn;
-       END;
-       $$ LANGUAGE 'plpgsql' STABLE;
+       RETURNS raster AS
+       $$ SELECT st_intersection($1, 1, $2, 1, 'BOTH', $3) $$
+       LANGUAGE 'sql' STABLE;
 
 CREATE OR REPLACE FUNCTION st_intersection(
-       rast raster,
-       geom geometry,
-       otheruserfunc regprocedure DEFAULT NULL
+       rast1 raster,
+       rast2 raster,
+       nodataval double precision
 )
        RETURNS raster AS
-       $$ SELECT st_intersection($1, 1, $2, $3) $$
+       $$ SELECT st_intersection($1, 1, $2, 1, 'BOTH', ARRAY[$3, $3]) $$
        LANGUAGE 'sql' STABLE;
 
 -----------------------------------------------------------------------
@@ -3428,27 +3440,21 @@ CREATE AGGREGATE ST_Union(raster, integer, text) (
 );
 
 -------------------------------------------------------------------
--- ST_Clip(rast raster, band int, geom geometry, nodata float8 DEFAULT null, trimraster boolean DEFAULT false)
+-- 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
--- trimraster - limit the extent of the result to the extent of the geometry
--- Todo:
--- test point
--- test line
--- test polygon smaller than pixel
--- test and optimize raster totally included in polygon
-
+-- crop   - limit the extent of the result to the extent of the geometry
 -----------------------------------------------------------------------
 -- ST_Clip
 -----------------------------------------------------------------------
--- Nodata as array series
+-- nodataval as array series
 
 -- Major variant
-CREATE OR REPLACE FUNCTION st_clip(rast raster, band int, geom geometry, nodata float8[] DEFAULT NULL, trimraster boolean DEFAULT FALSE)
+CREATE OR REPLACE FUNCTION st_clip(rast raster, band int, geom geometry, nodataval double precision[] DEFAULT NULL, crop boolean DEFAULT TRUE)
        RETURNS raster
        AS $$
        DECLARE
@@ -3458,7 +3464,7 @@ CREATE OR REPLACE FUNCTION st_clip(rast raster, band int, geom geometry, nodata
                bandstart int;
                bandend int;
                newextent text;
-               newnodata float8;
+               newnodataval double precision;
                newpixtype text;
                bandi int;
        BEGIN
@@ -3481,57 +3487,55 @@ CREATE OR REPLACE FUNCTION st_clip(rast raster, band int, geom geometry, nodata
                END IF;
 
                newpixtype := ST_BandPixelType(rast, bandstart);
-               newnodata := coalesce(nodata[1], ST_BandNodataValue(rast, bandstart), ST_MinPossibleValue(newpixtype));
-               newextent := CASE WHEN trimraster THEN 'INTERSECTION' ELSE 'FIRST' END;
+               newnodataval := coalesce(nodataval[1], ST_BandNodataValue(rast, bandstart), ST_MinPossibleValue(newpixtype));
+               newextent := CASE WHEN crop THEN 'INTERSECTION' ELSE 'FIRST' END;
 
---RAISE NOTICE 'newextent=%', newextent;
                -- Convert the geometry to a raster
-               geomrast := ST_AsRaster(geom, rast, ST_BandPixelType(rast, band), 1, newnodata);
+               geomrast := ST_AsRaster(geom, rast, ST_BandPixelType(rast, band), 1, newnodataval);
 
                -- Compute the first raster band
-               newrast := ST_MapAlgebraExpr(rast, bandstart, geomrast, 1, '[rast1.val]', newpixtype, newextent, newnodata::text, newnodata::text, newnodata);
-               -- Set the newnodata
-               newrast := ST_SetBandNodataValue(newrast, bandstart, newnodata);
+               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
---RAISE NOTICE 'bandi=%', bandi;
                        -- for each band we must determine the nodata value
                        newpixtype := ST_BandPixelType(rast, bandi);
-                       newnodata := coalesce(nodata[bandi], nodata[array_upper(nodata, 1)], ST_BandNodataValue(rast, bandi), ST_MinPossibleValue(newpixtype));
-                       newrast := ST_AddBand(newrast, ST_MapAlgebraExpr(rast, bandi, geomrast, 1, '[rast1.val]', newpixtype, newextent, newnodata::text, newnodata::text, newnodata));
-                       newrast := ST_SetBandNodataValue(newrast, bandi, newnodata);
+                       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;
 
--- Variant defaulting to all bands
-CREATE OR REPLACE FUNCTION st_clip(rast raster, geom geometry, nodata float8[] DEFAULT NULL, trimraster boolean DEFAULT FALSE)
+-- Nodata values as integer series
+CREATE OR REPLACE FUNCTION st_clip(rast raster, band int, geom geometry, nodataval double precision, crop boolean DEFAULT TRUE)
        RETURNS raster AS
-       $$ SELECT ST_Clip($1, NULL, $2, $3, $4) $$
+       $$ SELECT ST_Clip($1, $2, $3, ARRAY[$4], $5) $$
        LANGUAGE 'SQL' STABLE;
 
--- Nodata values as integer series
-CREATE OR REPLACE FUNCTION st_clip(rast raster, band int, geom geometry, nodata float8 DEFAULT NULL, trimraster boolean DEFAULT FALSE)
+-- 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)
        RETURNS raster AS
-       $$ SELECT ST_Clip($1, $2, $3, ARRAY[$4], $5) $$
+       $$ SELECT ST_Clip($1, $2, $3, null::float8[], $4) $$
        LANGUAGE 'SQL' STABLE;
 
 -- Variant defaulting to all bands
-CREATE OR REPLACE FUNCTION st_clip(rast raster, geom geometry, nodata float8, trimraster boolean DEFAULT FALSE)
+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, ARRAY[$3], $4) $$
+       $$ SELECT ST_Clip($1, NULL, $2, $3, $4) $$
        LANGUAGE 'SQL' STABLE;
 
--- Variant defaulting nodata to the one of the raster or the min possible value
-CREATE OR REPLACE FUNCTION st_clip(rast raster, band int, geom geometry, trimraster boolean)
+-- Variant defaulting to all bands
+CREATE OR REPLACE FUNCTION st_clip(rast raster, geom geometry, nodataval double precision, crop boolean DEFAULT TRUE)
        RETURNS raster AS
-       $$ SELECT ST_Clip($1, $2, $3, null::float8[], $4) $$
+       $$ SELECT ST_Clip($1, NULL, $2, ARRAY[$3], $4) $$
        LANGUAGE 'SQL' STABLE;
 
--- Variant defaulting nodata 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, trimraster boolean)
+-- 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)
        RETURNS raster AS
        $$ SELECT ST_Clip($1, NULL, $2, null::float8[], $3) $$
        LANGUAGE 'SQL' STABLE;
index 4b412c72daf8bef76836a99d4f8627f1a1205926..418602354128ee2843605877cf008ae936c65149 100644 (file)
@@ -77,7 +77,7 @@ DROP FUNCTION make_test_raster(integer, integer, integer, double precision, doub
 
 -- Test 1 without trimming, without defining a nodata value
 INSERT INTO raster_clip_out
-SELECT 1, rid, gid, ST_Clip(rast, geom)
+SELECT 1, rid, gid, ST_Clip(rast, geom, false)
 FROM raster_clip, geom_clip;
 
 -- Test 2 with trimming, without defining a nodata value
@@ -85,9 +85,9 @@ INSERT INTO raster_clip_out
 SELECT 2, rid, gid, ST_Clip(rast, geom, true)
 FROM raster_clip, geom_clip;
 
--- Test 3 with trimming, defining a nodata value
+-- Test 3 without trimming, defining a nodata value
 INSERT INTO raster_clip_out
-SELECT 3, rid, gid, ST_Clip(rast, geom, ARRAY[255, 254, 253])
+SELECT 3, rid, gid, ST_Clip(rast, geom, ARRAY[255, 254, 253], false)
 FROM raster_clip, geom_clip;
 
 -- Test 4 with trimming, defining a nodata value
index bedd07bce8334285bcad925d5ec0726ec3c9bc4f..c82d9228eb5a8aad7cb23b8c645ef9c7ec4087a4 100644 (file)
@@ -76,7 +76,7 @@ INSERT INTO raster_intersection_out
 
 INSERT INTO raster_intersection_out
        (SELECT r1.rid, r2.rid, ST_Intersection(
-               r1.rast, r2.rast, 'FIRST'
+               r1.rast, r2.rast, 'BAND1'
        )
        FROM raster_intersection r1
        JOIN raster_intersection r2
@@ -85,7 +85,7 @@ INSERT INTO raster_intersection_out
                AND r2.rid BETWEEN 1 AND 9
        ) UNION ALL (
        SELECT r1.rid, r2.rid, ST_Intersection(
-               r1.rast, r2.rast, 'FIRST'
+               r1.rast, r2.rast, 'BAND1'
        )
        FROM raster_intersection r1
        JOIN raster_intersection r2
@@ -96,7 +96,7 @@ INSERT INTO raster_intersection_out
 
 INSERT INTO raster_intersection_out
        (SELECT r1.rid, r2.rid, ST_Intersection(
-               r1.rast, r2.rast, 'SECOND'
+               r1.rast, r2.rast, 'BAND2'
        )
        FROM raster_intersection r1
        JOIN raster_intersection r2
@@ -105,46 +105,7 @@ INSERT INTO raster_intersection_out
                AND r2.rid BETWEEN 1 AND 9
        ) UNION ALL (
        SELECT r1.rid, r2.rid, ST_Intersection(
-               r1.rast, r2.rast, 'SECOND'
-       )
-       FROM raster_intersection r1
-       JOIN raster_intersection r2
-               ON r1.rid != r2.rid
-       WHERE r1.rid = 10
-               AND r2.rid BETWEEN 11 AND 19)
-;
-
-CREATE OR REPLACE FUNCTION raster_intersection_other(
-       rast1 double precision,
-       rast2 double precision,
-       VARIADIC userargs text[]
-)
-       RETURNS double precision
-       AS $$
-       DECLARE
-       BEGIN
-               IF rast1 IS NOT NULL AND rast2 IS NOT NULL THEN
-                       RETURN sqrt(power(rast1, 2) + power(rast2, 2));
-               ELSE
-                       RETURN NULL;
-               END IF;
-
-               RETURN NULL;
-       END;
-       $$ LANGUAGE 'plpgsql' IMMUTABLE;
-
-INSERT INTO raster_intersection_out
-       (SELECT r1.rid, r2.rid, ST_Intersection(
-               r1.rast, r2.rast, 'raster_intersection_other(double precision, double precision, text[])'::regprocedure
-       )
-       FROM raster_intersection r1
-       JOIN raster_intersection r2
-               ON r1.rid != r2.rid
-       WHERE r1.rid = 0
-               AND r2.rid BETWEEN 1 AND 9
-       ) UNION ALL (
-       SELECT r1.rid, r2.rid, ST_Intersection(
-               r1.rast, r2.rast, 'raster_intersection_other(double precision, double precision, text[])'::regprocedure
+               r1.rast, r2.rast, 'BAND2'
        )
        FROM raster_intersection r1
        JOIN raster_intersection r2
@@ -182,6 +143,11 @@ FROM (
        FROM raster_intersection_out
 ) AS r;
 
+-- Display the pixels and the values of the resulting rasters
+SELECT rid1, rid2, band, (gvxy).x, (gvxy).y, (gvxy).val, ST_AsText((gvxy).geom) geom
+FROM (SELECT rid1, rid2, band, ST_PixelAsPolygons(rast, band) gvxy
+      FROM raster_intersection_out, generate_series(1, 2) band
+) foo;
+
 DROP TABLE IF EXISTS raster_intersection;
 DROP TABLE IF EXISTS raster_intersection_out;
-DROP FUNCTION raster_intersection_other(rast1 double precision, rast2 double precision, VARIADIC userargs text[])
index 6df979826d62e64d5173f8a2d0d4984e119c44a6..d5857da27ba95b2f141eac27213155c3303f7380 100644 (file)
 10|12|-1.900|-1.000|2|2|1.000|1.000|0.100|0.100|0|1|8BUI|t|0.000|3.000|3.000
 10|13|0.000|-1.800|2|2|1.000|1.000|0.100|0.100|0|1|8BUI|t|0.000|4.000|4.000
 10|14|||||||||||||||
-0|1|0.000|0.000|2|2|1.000|1.000|0.000|0.000|0|1|8BUI|t|0.000|2.000|2.000
-0|2|1.000|-1.000|1|2|1.000|1.000|0.000|0.000|0|1|8BUI|t|0.000|3.000|3.000
-0|3|1.000|1.000|1|1|1.000|1.000|0.000|0.000|0|1|8BUI|t|0.000|4.000|4.000
-0|4|0.000|0.000|0|0|0.000|0.000|0.000|0.000|0|0|||||
-10|11|-0.900|-0.900|3|3|1.000|1.000|0.100|0.100|0|1|8BUI|t|0.000|2.000|2.000
-10|12|-1.900|-1.000|2|2|1.000|1.000|0.100|0.100|0|1|8BUI|t|0.000|3.000|3.000
-10|13|0.000|-1.800|2|2|1.000|1.000|0.100|0.100|0|1|8BUI|t|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|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|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|2|1|1|1|3|POLYGON((1 -1,2 -1,2 0,1 0,1 -1))
+0|2|1|1|2|3|POLYGON((1 0,2 0,2 1,1 1,1 0))
+0|3|1|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|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|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|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|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|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|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|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|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|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|2|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|2|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|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|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|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))