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
This commit is contained in:
Bborie Park 2012-10-16 19:55:50 +00:00
parent cff576de11
commit 0814092391
4 changed files with 549 additions and 9 deletions

View file

@ -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))

View file

@ -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

View file

@ -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;

View file

@ -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||||||||||||||