From: Bborie Park Date: Tue, 16 Oct 2012 19:55:50 +0000 (+0000) Subject: Added 2-raster expression variant of ST_MapAlgebra() and regression X-Git-Tag: 2.1.0beta2~527 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=08140923911ffa9f48f7a36f012f696bca735b64;p=postgis Added 2-raster expression variant of ST_MapAlgebra() and regression tests. git-svn-id: http://svn.osgeo.org/postgis/trunk@10441 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/raster/rt_pg/rt_pg.c b/raster/rt_pg/rt_pg.c index 44670aefa..2c8c4efde 100644 --- a/raster/rt_pg/rt_pg.c +++ b/raster/rt_pg/rt_pg.c @@ -14146,13 +14146,12 @@ Datum RASTER_nMapAlgebra(PG_FUNCTION_ARGS) elog(NOTICE, "Function provided is VOLATILE. Unless required and for best performance, function should be IMMUTABLE or STABLE"); /* prep function call data */ -#if POSTGIS_PGSQL_VERSION > 90 +#if POSTGIS_PGSQL_VERSION > 90 InitFunctionCallInfoData(arg->callback.ufc_info, &(arg->callback.ufl_info), arg->callback.ufl_info.fn_nargs, InvalidOid, NULL, NULL); -#else +#else InitFunctionCallInfoData(arg->callback.ufc_info, &(arg->callback.ufl_info), arg->callback.ufl_info.fn_nargs, NULL, NULL); #endif memset(arg->callback.ufc_info.argnull, FALSE, arg->callback.ufl_info.fn_nargs); - /* userargs (7) */ if (!PG_ARGISNULL(7)) diff --git a/raster/rt_pg/rtpostgis.sql.in.c b/raster/rt_pg/rtpostgis.sql.in.c index fd57d56e8..820e15675 100644 --- a/raster/rt_pg/rtpostgis.sql.in.c +++ b/raster/rt_pg/rtpostgis.sql.in.c @@ -2625,6 +2625,10 @@ CREATE OR REPLACE FUNCTION st_mapalgebra( AS $$ SELECT _ST_MapAlgebra(ARRAY[ROW($1, $2), ROW($3, $4)]::rastbandarg[], $5, $6, $9, $10, $7, $8, VARIADIC $11) $$ LANGUAGE 'sql' STABLE; +----------------------------------------------------------------------- +-- n-Raster ST_MapAlgebra with expressions +----------------------------------------------------------------------- + CREATE OR REPLACE FUNCTION st_mapalgebra( rast raster, nband integer, pixeltype text, @@ -2643,18 +2647,22 @@ CREATE OR REPLACE FUNCTION st_mapalgebra( funcname := 'pg_temp.callbackfunc' || (round(random() * 1000000))::text; -- substitute keywords - expr := replace(expression, '[rast]', ''' || value[1][1][1] || '''); - expr := replace(expr, '[rast.val]', ''' || value[1][1][1] || '''); - expr := replace(expr, '[rast.x]', ''' || pos[1][1] || '''); - expr := replace(expr, '[rast.y]', ''' || pos[1][2] || '''); + IF expression IS NOT NULL THEN + expr := replace(expression, '[rast]', ''' || value[1][1][1] || '''); + expr := replace(expr, '[rast.val]', ''' || value[1][1][1] || '''); + expr := replace(expr, '[rast.x]', ''' || pos[1][1] || '''); + expr := replace(expr, '[rast.y]', ''' || pos[1][2] || '''); + ELSE + expr := NULL; + END IF; -- build callback function body funcbody := ' DECLARE val double precision; BEGIN'; --funcbody := funcbody || ' RAISE NOTICE ''value = %'', value;'; --funcbody := funcbody || ' RAISE NOTICE ''pos = %'', pos;'; - funcbody := funcbody || ' IF value[1][1][1] IS NULL THEN'; -- handle NODATA in callback function + funcbody := funcbody || ' IF value[1][1][1] IS NULL THEN'; IF nodataval IS NOT NULL THEN funcbody := funcbody || ' RETURN ' || nodataval::text || ';'; ELSE @@ -2663,7 +2671,11 @@ CREATE OR REPLACE FUNCTION st_mapalgebra( funcbody := funcbody || ' END IF;'; -- handle value processing in callback function - funcbody := funcbody || ' EXECUTE ''SELECT (' || expr || ')::double precision'' INTO val;'; + IF expr IS NOT NULL THEN + funcbody := funcbody || ' EXECUTE ''SELECT (' || expr || ')::double precision'' INTO val;'; + ELSE + funcbody := funcbody || ' val := NULL;'; + END IF; -- handle val is NULL IF nodataval IS NOT NULL THEN @@ -2704,6 +2716,138 @@ CREATE OR REPLACE FUNCTION st_mapalgebra( AS $$ SELECT st_mapalgebra($1, 1, $2, $3, $4) $$ LANGUAGE 'sql' VOLATILE; +CREATE OR REPLACE FUNCTION st_mapalgebra( + rast1 raster, band1 integer, + rast2 raster, band2 integer, + expression text, + pixeltype text DEFAULT NULL, extenttype text DEFAULT 'INTERSECTION', + nodata1expr text DEFAULT NULL, nodata2expr text DEFAULT NULL, + nodatanodataval double precision DEFAULT NULL +) + RETURNS raster + AS $$ + DECLARE + rtn raster; + funcname text; + funcbody text; + funccmd text; + expr text; + nd1expr text; + nd2expr text; + BEGIN + -- set name of callback function + funcname := 'pg_temp.callbackfunc' || (round(random() * 1000000))::text; + + -- substitute keywords + -- expression + IF expression IS NOT NULL THEN + expr := replace(expression, '[rast1]', ''' || value[1][1][1] || '''); + expr := replace(expr, '[rast1.val]', ''' || value[1][1][1] || '''); + expr := replace(expr, '[rast1.x]', ''' || pos[1][1] || '''); + expr := replace(expr, '[rast1.y]', ''' || pos[1][2] || '''); + + expr := replace(expr, '[rast2]', ''' || value[2][1][1] || '''); + expr := replace(expr, '[rast2.val]', ''' || value[2][1][1] || '''); + expr := replace(expr, '[rast2.x]', ''' || pos[2][1] || '''); + expr := replace(expr, '[rast2.y]', ''' || pos[2][2] || '''); + ELSE + expr := NULL; + END IF; + + -- nodata1expr + IF nodata1expr IS NOT NULL THEN + nd1expr := replace(nodata1expr, '[rast2]', ''' || value[2][1][1] || '''); + nd1expr := replace(nd1expr, '[rast2.val]', ''' || value[2][1][1] || '''); + nd1expr := replace(nd1expr, '[rast2.x]', ''' || pos[2][1] || '''); + nd1expr := replace(nd1expr, '[rast2.y]', ''' || pos[2][2] || '''); + END IF; + + -- nodata2expr + IF nodata2expr IS NOT NULL THEN + nd2expr := replace(nodata2expr, '[rast1]', ''' || value[1][1][1] || '''); + nd2expr := replace(nd2expr, '[rast1.val]', ''' || value[1][1][1] || '''); + nd2expr := replace(nd2expr, '[rast1.x]', ''' || pos[1][1] || '''); + nd2expr := replace(nd2expr, '[rast1.y]', ''' || pos[1][2] || '''); + END IF; + + -- build callback function body + funcbody := ' DECLARE val double precision; BEGIN'; + --funcbody := funcbody || ' RAISE NOTICE ''value = %'', value;'; + --funcbody := funcbody || ' RAISE NOTICE ''pos = %'', pos;'; + + -- handle both NODATA in callback function + funcbody := funcbody || ' IF value[1][1][1] IS NULL AND value[2][1][1] IS NULL THEN'; + IF nodatanodataval IS NOT NULL THEN + funcbody := funcbody || ' RETURN ' || nodatanodataval::text || ';'; + ELSE + funcbody := funcbody || ' RETURN NULL;'; + END IF; + funcbody := funcbody || ' END IF;'; + + -- handle first NODATA in callback function + funcbody := funcbody || ' IF value[1][1][1] IS NULL AND value[2][1][1] IS NOT NULL THEN'; + IF nodata1expr IS NOT NULL THEN + funcbody := funcbody || ' EXECUTE ''SELECT (' || nd1expr || ')::double precision'' INTO val;'; + funcbody := funcbody || ' RETURN val;'; + ELSE + funcbody := funcbody || ' RETURN NULL;'; + END IF; + funcbody := funcbody || ' END IF;'; + + -- handle second NODATA in callback function + funcbody := funcbody || ' IF value[1][1][1] IS NOT NULL AND value[2][1][1] IS NULL THEN'; + IF nodata2expr IS NOT NULL THEN + funcbody := funcbody || ' EXECUTE ''SELECT (' || nd2expr || ')::double precision'' INTO val;'; + funcbody := funcbody || ' RETURN val;'; + ELSE + funcbody := funcbody || ' RETURN NULL;'; + END IF; + funcbody := funcbody || ' END IF;'; + + -- handle value processing in callback function + IF expr IS NOT NULL THEN + funcbody := funcbody || ' EXECUTE ''SELECT (' || expr || ')::double precision'' INTO val;'; + ELSE + funcbody := funcbody || ' val := NULL;'; + END IF; + + -- finish callback function + funcbody := funcbody || ' RETURN val; END;'; + + funccmd := 'CREATE OR REPLACE FUNCTION ' || funcname + || '(value double precision[][][], pos integer[][], VARIADIC userargs text[] DEFAULT NULL)' + || ' RETURNS double precision AS ' + || quote_literal(funcbody) + || ' LANGUAGE ''plpgsql'' STABLE;'; + + --RAISE NOTICE 'funccmd = %', funccmd; + + -- create callback function + EXECUTE funccmd; + + -- call ST_MapAlgebra + rtn := ST_MapAlgebra(ARRAY[ROW($1, $2), ROW($3, $4)]::rastbandarg[], (funcname || '(double precision[][][], integer[][], text[])')::regprocedure, $6, $7); + + -- drop callback function + EXECUTE 'DROP FUNCTION IF EXISTS ' || funcname + || '(double precision[][][], integer[][], text[]);'; + + RETURN rtn; + END; + $$ LANGUAGE 'plpgsql' VOLATILE; + +CREATE OR REPLACE FUNCTION st_mapalgebra( + rast1 raster, + rast2 raster, + expression text, + pixeltype text DEFAULT NULL, extenttype text DEFAULT 'INTERSECTION', + nodata1expr text DEFAULT NULL, nodata2expr text DEFAULT NULL, + nodatanodataval double precision DEFAULT NULL +) + RETURNS raster + AS $$ SELECT st_mapalgebra($1, 1, $2, 1, $3, $4, $5, $6, $7, $8) $$ + LANGUAGE 'sql' VOLATILE; + ----------------------------------------------------------------------- -- ST_MapAlgebra callback functions -- Should be called with values for distancex and distancey diff --git a/raster/test/regress/rt_mapalgebra_expr.sql b/raster/test/regress/rt_mapalgebra_expr.sql index 41fa46190..b12b97537 100644 --- a/raster/test/regress/rt_mapalgebra_expr.sql +++ b/raster/test/regress/rt_mapalgebra_expr.sql @@ -162,3 +162,276 @@ DROP FUNCTION raster_polynomial(pixel FLOAT, VARIADIC args TEXT[]); DROP FUNCTION raster_nullage(pixel FLOAT, VARIADIC args TEXT[]); DROP FUNCTION raster_x_plus_arg(pixel FLOAT, pos INT[], VARIADIC args TEXT[]); DROP FUNCTION raster_y_plus_arg(pixel FLOAT, pos INT[], VARIADIC args TEXT[]); + +DROP TABLE IF EXISTS raster_mapalgebra; +CREATE TABLE raster_mapalgebra ( + rid integer, + rast raster +); +DROP TABLE IF EXISTS raster_mapalgebra_out; +CREATE TABLE raster_mapalgebra_out ( + rid1 integer, + rid2 integer, + extent varchar, + rast raster +); +CREATE OR REPLACE FUNCTION make_test_raster( + rid integer, + width integer DEFAULT 2, + height integer DEFAULT 2, + ul_x double precision DEFAULT 0, + ul_y double precision DEFAULT 0, + skew_x double precision DEFAULT 0, + skew_y double precision DEFAULT 0, + initvalue double precision DEFAULT 1, + nodataval double precision DEFAULT 0 +) + RETURNS void + AS $$ + DECLARE + x int; + y int; + rast raster; + BEGIN + rast := ST_MakeEmptyRaster(width, height, ul_x, ul_y, 1, 1, skew_x, skew_y, 0); + rast := ST_AddBand(rast, 1, '8BUI', initvalue, nodataval); + + + INSERT INTO raster_mapalgebra VALUES (rid, rast); + + RETURN; + END; + $$ LANGUAGE 'plpgsql'; +-- no skew +SELECT make_test_raster(0, 4, 4, -2, -2); +SELECT make_test_raster(1, 2, 2, 0, 0, 0, 0, 2); +SELECT make_test_raster(2, 2, 2, 1, -1, 0, 0, 3); +SELECT make_test_raster(3, 2, 2, 1, 1, 0, 0, 4); +SELECT make_test_raster(4, 2, 2, 2, 2, 0, 0, 5); + +-- skew +SELECT make_test_raster(10, 4, 4, -2, -2, 1, -1); +SELECT make_test_raster(11, 2, 2, 0, 0, 1, -1, 2); +SELECT make_test_raster(12, 2, 2, 1, -1, 1, -1, 3); +SELECT make_test_raster(13, 2, 2, 1, 1, 1, -1, 4); +SELECT make_test_raster(14, 2, 2, 2, 2, 1, -1, 5); + +DROP FUNCTION make_test_raster(integer, integer, integer, double precision, double precision, double precision, double precision, double precision, double precision); + +-- INTERSECTION +INSERT INTO raster_mapalgebra_out + (SELECT r1.rid, r2.rid, 'INTERSECTION', st_mapalgebra( + r1.rast, r2.rast, '[rast1.val]', '32BF', 'INTERSECTION' + ) + FROM raster_mapalgebra r1 + JOIN raster_mapalgebra r2 + ON r1.rid != r2.rid + WHERE r1.rid = 0 + AND r2.rid BETWEEN 1 AND 9 + ) UNION ALL ( + SELECT r1.rid, r2.rid, 'INTERSECTION', st_mapalgebra( + r1.rast, r2.rast, '[rast1.val]', '32BF', 'INTERSECTION' + ) + FROM raster_mapalgebra r1 + JOIN raster_mapalgebra r2 + ON r1.rid != r2.rid + WHERE r1.rid = 10 + AND r2.rid BETWEEN 11 AND 19) +; + +INSERT INTO raster_mapalgebra_out + SELECT NULL AS rid, rid, 'INTERSECTION', st_mapalgebra( + NULL::raster, rast, '[rast1.val]', '32BF', 'INTERSECTION' + ) + FROM raster_mapalgebra +; + +INSERT INTO raster_mapalgebra_out + SELECT rid, NULL AS rid, 'INTERSECTION', st_mapalgebra( + rast, NULL::raster, '[rast1.val]', '32BF', 'INTERSECTION' + ) + FROM raster_mapalgebra +; + +INSERT INTO raster_mapalgebra_out + SELECT NULL AS rid, NULL AS rid, 'INTERSECTION', st_mapalgebra( + NULL::raster, NULL::raster, '[rast1.val]', '32BF', 'INTERSECTION' + ) +; + +-- UNION +INSERT INTO raster_mapalgebra_out + (SELECT r1.rid, r2.rid, 'UNION', st_mapalgebra( + r1.rast, r2.rast, '(([rast1.val] + [rast2.val])/2.)::numeric', '32BF', 'UNION', '[rast2.val]', '[rast1.val]', NULL + ) + FROM raster_mapalgebra r1 + JOIN raster_mapalgebra r2 + ON r1.rid != r2.rid + WHERE r1.rid = 0 + AND r2.rid BETWEEN 1 AND 9 + ) UNION ALL ( + SELECT r1.rid, r2.rid, 'UNION', st_mapalgebra( + r1.rast, r2.rast, '(([rast1.val] + [rast2.val])/2.)::numeric', '32BF', 'UNION', '[rast2.val]', '[rast1.val]', NULL + ) + FROM raster_mapalgebra r1 + JOIN raster_mapalgebra r2 + ON r1.rid != r2.rid + WHERE r1.rid = 10 + AND r2.rid BETWEEN 11 AND 19) +; + +INSERT INTO raster_mapalgebra_out + (SELECT r1.rid, r2.rid, 'UNION', st_mapalgebra( + r1.rast, r2.rast, '(([rast1.val] + [rast2.val])/2.)::numeric', '32BF', 'UNION', '100', '200', NULL + ) + FROM raster_mapalgebra r1 + JOIN raster_mapalgebra r2 + ON r1.rid != r2.rid + WHERE r1.rid = 0 + AND r2.rid BETWEEN 1 AND 9 + ) UNION ALL ( + SELECT r1.rid, r2.rid, 'UNION', st_mapalgebra( + r1.rast, r2.rast, '(([rast1.val] + [rast2.val])/2.)::numeric', '32BF', 'UNION', '100', '200', NULL + ) + FROM raster_mapalgebra r1 + JOIN raster_mapalgebra r2 + ON r1.rid != r2.rid + WHERE r1.rid = 10 + AND r2.rid BETWEEN 11 AND 19) +; + +INSERT INTO raster_mapalgebra_out + SELECT NULL AS rid, rid, 'UNION', st_mapalgebra( + NULL::raster, rast, '(([rast1.val] + [rast2.val])/2.)::numeric', '32BF', 'UNION', '[rast2.val]', '[rast1.val]', NULL + ) + FROM raster_mapalgebra +; + +INSERT INTO raster_mapalgebra_out + SELECT rid, NULL AS rid, 'UNION', st_mapalgebra( + rast, NULL::raster, '(([rast1.val] + [rast2.val])/2.)::numeric', '32BF', 'UNION', '[rast2.val]', '[rast1.val]', NULL + ) + FROM raster_mapalgebra +; + +INSERT INTO raster_mapalgebra_out + SELECT NULL AS rid, NULL AS rid, 'UNION', st_mapalgebra( + NULL::raster, NULL::raster, '(([rast1.val] + [rast2.val])/2.)::numeric', '32BF', 'UNION', '[rast2.val]', '[rast1.val]', NULL + ) +; + +-- FIRST +INSERT INTO raster_mapalgebra_out + (SELECT r1.rid, r2.rid, 'FIRST', st_mapalgebra( + r1.rast, r2.rast, 'CASE WHEN [rast2.val] IS NOT NULL THEN NULL ELSE [rast1.val] END', '32BF', 'FIRST', NULL, '[rast1.val]', NULL + ) + FROM raster_mapalgebra r1 + JOIN raster_mapalgebra r2 + ON r1.rid != r2.rid + WHERE r1.rid = 0 + AND r2.rid BETWEEN 1 AND 9 + ) UNION ALL ( + SELECT r1.rid, r2.rid, 'FIRST', st_mapalgebra( + r1.rast, r2.rast, 'CASE WHEN [rast2.val] IS NOT NULL THEN NULL ELSE [rast1.val] END', '32BF', 'FIRST', NULL, '[rast1.val]', NULL + ) + FROM raster_mapalgebra r1 + JOIN raster_mapalgebra r2 + ON r1.rid != r2.rid + WHERE r1.rid = 10 + AND r2.rid BETWEEN 11 AND 19) +; + +INSERT INTO raster_mapalgebra_out + SELECT NULL AS rid, rid, 'FIRST', st_mapalgebra( + NULL::raster, rast, 'CASE WHEN [rast1.val] IS NOT NULL THEN NULL ELSE [rast2.val] END', '32BF', 'FIRST', '[rast2.val]', NULL, NULL + ) + FROM raster_mapalgebra +; + +INSERT INTO raster_mapalgebra_out + SELECT rid, NULL AS rid, 'FIRST', st_mapalgebra( + rast, NULL::raster, 'CASE WHEN [rast2.val] IS NOT NULL THEN NULL ELSE [rast1.val] END', '32BF', 'FIRST', NULL, '[rast1.val]', NULL + ) + FROM raster_mapalgebra +; + +INSERT INTO raster_mapalgebra_out + SELECT NULL AS rid, NULL AS rid, 'FIRST', st_mapalgebra( + NULL::raster, NULL::raster, 'CASE WHEN [rast2.val] IS NOT NULL THEN NULL ELSE [rast1.val] END', '32BF', 'FIRST', NULL, '[rast1.val]', NULL + ) +; + +-- SECOND +INSERT INTO raster_mapalgebra_out + (SELECT r1.rid, r2.rid, 'SECOND', st_mapalgebra( + r1.rast, r2.rast, 'CASE WHEN [rast1.val] IS NOT NULL THEN NULL ELSE [rast2.val] END', '32BF', 'SECOND', '[rast2.val]', NULL, NULL + ) + FROM raster_mapalgebra r1 + JOIN raster_mapalgebra r2 + ON r1.rid != r2.rid + WHERE r1.rid = 0 + AND r2.rid BETWEEN 1 AND 9 + ) UNION ALL ( + SELECT r1.rid, r2.rid, 'SECOND', st_mapalgebra( + r1.rast, r2.rast, 'CASE WHEN [rast1.val] IS NOT NULL THEN NULL ELSE [rast2.val] END', '32BF', 'SECOND', '[rast2.val]', NULL, NULL + ) + FROM raster_mapalgebra r1 + JOIN raster_mapalgebra r2 + ON r1.rid != r2.rid + WHERE r1.rid = 10 + AND r2.rid BETWEEN 11 AND 19) +; + +INSERT INTO raster_mapalgebra_out + SELECT NULL AS rid, rid, 'SECOND', st_mapalgebra( + NULL::raster, rast, 'CASE WHEN [rast1.val] IS NOT NULL THEN NULL ELSE [rast2.val] END', '32BF', 'SECOND', '[rast2.val]', NULL, NULL + ) + FROM raster_mapalgebra +; + +INSERT INTO raster_mapalgebra_out + SELECT rid, NULL AS rid, 'SECOND', st_mapalgebra( + rast, NULL::raster, 'CASE WHEN [rast1.val] IS NOT NULL THEN NULL ELSE [rast2.val] END', '32BF', 'SECOND', '[rast2.val]', NULL, NULL + ) + FROM raster_mapalgebra +; + +INSERT INTO raster_mapalgebra_out + SELECT NULL AS rid, NULL AS rid, 'SECOND', st_mapalgebra( + NULL::raster, NULL::raster, 'CASE WHEN [rast1.val] IS NOT NULL THEN NULL ELSE [rast2.val] END', '32BF', 'SECOND', '[rast2.val]', NULL, NULL + ) +; + +-- output +SELECT + rid1, + rid2, + extent, + round(upperleftx::numeric, 3) AS upperleftx, + round(upperlefty::numeric, 3) AS upperlefty, + width, + height, + round(scalex::numeric, 3) AS scalex, + round(scaley::numeric, 3) AS scaley, + round(skewx::numeric, 3) AS skewx, + round(skewy::numeric, 3) AS skewy, + srid, + numbands, + pixeltype, + round(nodatavalue::numeric, 3) AS nodatavalue, + round(firstvalue::numeric, 3) AS firstvalue, + round(lastvalue::numeric, 3) AS lastvalue +FROM ( + SELECT + rid1, + rid2, + extent, + (ST_Metadata(rast)).*, + (ST_BandMetadata(rast, 1)).*, + ST_Value(rast, 1, 1, 1) AS firstvalue, + ST_Value(rast, 1, ST_Width(rast), ST_Height(rast)) AS lastvalue + FROM raster_mapalgebra_out +) AS r; + +DROP TABLE IF EXISTS raster_mapalgebra; +DROP TABLE IF EXISTS raster_mapalgebra_out; diff --git a/raster/test/regress/rt_mapalgebra_expr_expected b/raster/test/regress/rt_mapalgebra_expr_expected index 9eb5fd363..9e7a50ab1 100644 --- a/raster/test/regress/rt_mapalgebra_expr_expected +++ b/raster/test/regress/rt_mapalgebra_expr_expected @@ -21,3 +21,127 @@ ERROR: division by zero T11.1|10|2 T11.2|10|2 T12|t|t|t|t +0|1|INTERSECTION|0.000|0.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|1.000|1.000 +0|2|INTERSECTION|1.000|-1.000|1|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|1.000|1.000 +0|3|INTERSECTION|1.000|1.000|1|1|1.000|1.000|0.000|0.000|0|1|32BF|0.000|1.000|1.000 +0|4|INTERSECTION|0.000|0.000|0|0|0.000|0.000|0.000|0.000|0|0|||| +10|11|INTERSECTION|0.000|0.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|1.000|1.000 +10|12|INTERSECTION|1.000|-1.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|1.000|1.000 +10|13|INTERSECTION|1.000|1.000|2|1|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|1.000|1.000 +10|14|INTERSECTION|0.000|0.000|0|0|0.000|0.000|0.000|0.000|0|0|||| +|0|INTERSECTION|-2.000|-2.000|4|4|1.000|1.000|0.000|0.000|0|1|32BF|0.000|| +|1|INTERSECTION|0.000|0.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|| +|2|INTERSECTION|1.000|-1.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|| +|3|INTERSECTION|1.000|1.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|| +|4|INTERSECTION|2.000|2.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|| +|10|INTERSECTION|-2.000|-2.000|4|4|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|| +|11|INTERSECTION|0.000|0.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|| +|12|INTERSECTION|1.000|-1.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|| +|13|INTERSECTION|1.000|1.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|| +|14|INTERSECTION|2.000|2.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|| +0||INTERSECTION|-2.000|-2.000|4|4|1.000|1.000|0.000|0.000|0|1|32BF|0.000|| +1||INTERSECTION|0.000|0.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|| +2||INTERSECTION|1.000|-1.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|| +3||INTERSECTION|1.000|1.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|| +4||INTERSECTION|2.000|2.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|| +10||INTERSECTION|-2.000|-2.000|4|4|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|| +11||INTERSECTION|0.000|0.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|| +12||INTERSECTION|1.000|-1.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|| +13||INTERSECTION|1.000|1.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|| +14||INTERSECTION|2.000|2.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|| +||INTERSECTION|||||||||||||| +0|1|UNION|-2.000|-2.000|4|4|1.000|1.000|0.000|0.000|0|1|32BF|0.000|1.000|1.500 +0|2|UNION|-2.000|-2.000|5|4|1.000|1.000|0.000|0.000|0|1|32BF|0.000|1.000| +0|3|UNION|-2.000|-2.000|5|5|1.000|1.000|0.000|0.000|0|1|32BF|0.000|1.000|4.000 +0|4|UNION|-2.000|-2.000|6|6|1.000|1.000|0.000|0.000|0|1|32BF|0.000|1.000|5.000 +10|11|UNION|-2.000|-2.000|4|4|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|1.000|1.000 +10|12|UNION|-2.000|-2.000|4|4|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|1.000|1.000 +10|13|UNION|-2.000|-2.000|4|5|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|1.000| +10|14|UNION|-2.000|-2.000|4|6|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|1.000| +0|1|UNION|-2.000|-2.000|4|4|1.000|1.000|0.000|0.000|0|1|32BF|0.000|200.000|1.500 +0|2|UNION|-2.000|-2.000|5|4|1.000|1.000|0.000|0.000|0|1|32BF|0.000|200.000| +0|3|UNION|-2.000|-2.000|5|5|1.000|1.000|0.000|0.000|0|1|32BF|0.000|200.000|100.000 +0|4|UNION|-2.000|-2.000|6|6|1.000|1.000|0.000|0.000|0|1|32BF|0.000|200.000|100.000 +10|11|UNION|-2.000|-2.000|4|4|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|200.000|200.000 +10|12|UNION|-2.000|-2.000|4|4|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|200.000|200.000 +10|13|UNION|-2.000|-2.000|4|5|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|200.000| +10|14|UNION|-2.000|-2.000|4|6|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|200.000| +|0|UNION|-2.000|-2.000|4|4|1.000|1.000|0.000|0.000|0|1|32BF|0.000|1.000|1.000 +|1|UNION|0.000|0.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|2.000|2.000 +|2|UNION|1.000|-1.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|3.000|3.000 +|3|UNION|1.000|1.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|4.000|4.000 +|4|UNION|2.000|2.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|5.000|5.000 +|10|UNION|-2.000|-2.000|4|4|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|1.000|1.000 +|11|UNION|0.000|0.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|2.000|2.000 +|12|UNION|1.000|-1.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|3.000|3.000 +|13|UNION|1.000|1.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|4.000|4.000 +|14|UNION|2.000|2.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|5.000|5.000 +0||UNION|-2.000|-2.000|4|4|1.000|1.000|0.000|0.000|0|1|32BF|0.000|1.000|1.000 +1||UNION|0.000|0.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|2.000|2.000 +2||UNION|1.000|-1.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|3.000|3.000 +3||UNION|1.000|1.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|4.000|4.000 +4||UNION|2.000|2.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|5.000|5.000 +10||UNION|-2.000|-2.000|4|4|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|1.000|1.000 +11||UNION|0.000|0.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|2.000|2.000 +12||UNION|1.000|-1.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|3.000|3.000 +13||UNION|1.000|1.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|4.000|4.000 +14||UNION|2.000|2.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|5.000|5.000 +||UNION|||||||||||||| +0|1|FIRST|-2.000|-2.000|4|4|1.000|1.000|0.000|0.000|0|1|32BF|0.000|1.000| +0|2|FIRST|-2.000|-2.000|4|4|1.000|1.000|0.000|0.000|0|1|32BF|0.000|1.000|1.000 +0|3|FIRST|-2.000|-2.000|4|4|1.000|1.000|0.000|0.000|0|1|32BF|0.000|1.000| +0|4|FIRST|-2.000|-2.000|4|4|1.000|1.000|0.000|0.000|0|1|32BF|0.000|1.000|1.000 +10|11|FIRST|-2.000|-2.000|4|4|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|1.000|1.000 +10|12|FIRST|-2.000|-2.000|4|4|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|1.000|1.000 +10|13|FIRST|-2.000|-2.000|4|4|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|1.000|1.000 +10|14|FIRST|-2.000|-2.000|4|4|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|1.000|1.000 +|0|FIRST|||||||||||||| +|1|FIRST|||||||||||||| +|2|FIRST|||||||||||||| +|3|FIRST|||||||||||||| +|4|FIRST|||||||||||||| +|10|FIRST|||||||||||||| +|11|FIRST|||||||||||||| +|12|FIRST|||||||||||||| +|13|FIRST|||||||||||||| +|14|FIRST|||||||||||||| +0||FIRST|-2.000|-2.000|4|4|1.000|1.000|0.000|0.000|0|1|32BF|0.000|1.000|1.000 +1||FIRST|0.000|0.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|2.000|2.000 +2||FIRST|1.000|-1.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|3.000|3.000 +3||FIRST|1.000|1.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|4.000|4.000 +4||FIRST|2.000|2.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|5.000|5.000 +10||FIRST|-2.000|-2.000|4|4|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|1.000|1.000 +11||FIRST|0.000|0.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|2.000|2.000 +12||FIRST|1.000|-1.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|3.000|3.000 +13||FIRST|1.000|1.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|4.000|4.000 +14||FIRST|2.000|2.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|5.000|5.000 +||FIRST|||||||||||||| +0|1|SECOND|0.000|0.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|| +0|2|SECOND|1.000|-1.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000||3.000 +0|3|SECOND|1.000|1.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000||4.000 +0|4|SECOND|2.000|2.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|5.000|5.000 +10|11|SECOND|0.000|0.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|| +10|12|SECOND|1.000|-1.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|| +10|13|SECOND|1.000|1.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000||4.000 +10|14|SECOND|2.000|2.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|5.000|5.000 +|0|SECOND|-2.000|-2.000|4|4|1.000|1.000|0.000|0.000|0|1|32BF|0.000|1.000|1.000 +|1|SECOND|0.000|0.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|2.000|2.000 +|2|SECOND|1.000|-1.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|3.000|3.000 +|3|SECOND|1.000|1.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|4.000|4.000 +|4|SECOND|2.000|2.000|2|2|1.000|1.000|0.000|0.000|0|1|32BF|0.000|5.000|5.000 +|10|SECOND|-2.000|-2.000|4|4|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|1.000|1.000 +|11|SECOND|0.000|0.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|2.000|2.000 +|12|SECOND|1.000|-1.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|3.000|3.000 +|13|SECOND|1.000|1.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|4.000|4.000 +|14|SECOND|2.000|2.000|2|2|1.000|1.000|1.000|-1.000|0|1|32BF|0.000|5.000|5.000 +0||SECOND|||||||||||||| +1||SECOND|||||||||||||| +2||SECOND|||||||||||||| +3||SECOND|||||||||||||| +4||SECOND|||||||||||||| +10||SECOND|||||||||||||| +11||SECOND|||||||||||||| +12||SECOND|||||||||||||| +13||SECOND|||||||||||||| +14||SECOND|||||||||||||| +||SECOND||||||||||||||