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))
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,
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
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
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
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;
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||||||||||||||