Changes between Initial Version and Version 1 of UsersWikiExamplesPolygonOverlaps


Ignore:
Timestamp:
03/10/11 05:39:42 (14 years ago)
Author:
blaggner
Comment:

Legend:

Unmodified
Added
Removed
Modified
  • UsersWikiExamplesPolygonOverlaps

    v1 v1  
     1
     2== Finding and Editing Polygon Overlaps ==
     3
     4The function pgoverlap checks a polygon table for overlapping geometries, separating between sliver and non-sliver overlappings. It returns two tables - one table with non-overlapping geometries and adjusted sliver-overlapping polygons and one table with non-sliver overlappings which have to be handled manually afterwards.
     5
     6Preconditions for successful use of the function:[[BR]]
     7- gid column of data type integer or serial, unique, with btree index!! [[BR]]
     8- the_geom column of data type geometry and geometry type POLYGON, with gist index!! [[BR]]
     9- column of data type integer (name is variable) for subsequent joining of attributes with btree index!! [[BR]]
     10- geometries should be valid (otherwise number of exceptions rises)[[BR]]
     11
     12'''Caution:''' Do not call the functions twice at a time!! - Intermediate tables have fixed names and are locked during function processing (otherwise their content would be overwritten).
     13
     14'''Example:'''
     15
     16{{{
     17CREATE TABLE pgoverlap_bsp_input (gid serial PRIMARY KEY, a_id integer, the_geom geometry);
     18INSERT INTO pgoverlap_bsp_input (a_id, the_geom) VALUES
     19(1,ST_GeomFromText('POLYGON((3565961 5361731,3570432 5359825,3574390 5362977,3577469 5360631,3582526 5360192,3591616 5351909,3592715 5343113,3591835 5337395,3586265 5339448,3579008 5336882,3572045 5340254,3567500 5338788,3564421 5342013,3562296 5353301,3566327 5356527,3565961 5361731))',31467)),
     20(2,ST_GeomFromText('POLYGON((3587846 5359101,3587353 5362736,3592036 5366371,3598813 5365755,3601708 5361997,3592528 5358855,3587846 5359101))',31467)),
     21(3,ST_GeomFromText('POLYGON((3600429 5353669,3606823 5355001,3612240 5361751,3622453 5355801,3637461 5355179,3635951 5340171,3617036 5337240,3605225 5340260,3600429 5353669))',31467)),
     22(4,ST_GeomFromText('POLYGON((3580359 5328360,3588529 5330935,3597943 5323120,3606024 5322587,3612951 5315217,3608155 5306691,3603804 5305093,3596166 5306159,3591105 5310244,3584799 5310688,3576540 5317437,3580359 5328360))',31467)),
     23(5,ST_GeomFromText('POLYGON((3568123 5343184,3577776 5350721,3586922 5344624,3584890 5336664,3593104 5330312,3586499 5322014,3572187 5325232,3568123 5343184))',31467)),
     24(6,ST_GeomFromText('POLYGON((3594628 5349620,3601741 5358935,3617153 5357580,3621387 5348519,3617153 5339712,3610040 5334293,3616137 5322945,3607923 5311598,3600302 5314392,3596068 5319727,3600725 5329974,3596406 5339882,3594628 5349620))',31467)),
     25(7,ST_GeomFromText('POLYGON((3622319 5325401,3625029 5327433,3630194 5329466,3635191 5326502,3638747 5317610,3631719 5311598,3622150 5316594,3622319 5325401))',31467));
     26
     27SELECT _pgoverlap('public','pgoverlap_bsp_input','a_id','pgoverlap_bsp_output','pgoverlap_bsp_todo');
     28}}}
     29
     30'''Function:'''
     31
     32{{{
     33CREATE OR REPLACE FUNCTION _pgoverlap(schema_a varchar, table_a varchar, a_id varchar, table_result1 varchar, table_result2 varchar)
     34  RETURNS void AS
     35$BODY$
     36
     37/*
     38$Id: pgoverlap_wiki.sql 2011-03-09 15:19Z Birgit Laggner $
     39
     40pgoverlap - checks table for overlapping geometries seperating between sliver and non-sliver overlappings, returns table with non-overlapping geometries and adjusted sliver-overlapping polygons as well as table with non-sliver overlappings (for later treatment)
     41
     42schema_a:      database schema where table is located
     43table_a:       table name
     44a_id:          id column name in table
     45table_result1: name of 1st result table (non-overlapping polygons)
     46table_result2: name of 2nd result table (overlapping polygons)
     47
     48Preconditions for successful use of the function:
     49- gid column of data type integer or serial, unique, with btree index!!
     50- the_geom column of data type geometry and geometry type POLYGON, with gist index!!
     51- column of data type integer (name is variable) for subsequent joining of attributes, with btree index!!
     52- geometries should be valid (otherwise number of exceptions rises)
     53
     54Caution: Do not call the function twice at a time!! - Intermediate tables have fixed names and are locked during function processing (otherwise their content would be overwritten).
     55
     56Copyright (C) 2011 Johann Heinrich von Thünen-Institute (vTI) - Federal Research Institute for Rural Areas, Forestry and Fisheries, Institute of Rural Studies, Braunschweig, Germany (http://www.vti.bund.de)
     57Version 0.1
     58contact: birgit dot laggner at vti dot bund dot de
     59
     60This is free software; you can redistribute and/or modify it under
     61the terms of the GNU General Public Licence. This software is without any warrenty and you use it at your own risk.
     62*/
     63
     64DECLARE
     65
     66i integer;
     67sql_1 text;
     68
     69
     70BEGIN
     71
     72--find all overlappings with geometrytype Polygon:
     73
     74EXECUTE
     75'DROP TABLE IF EXISTS '||schema_a||'.pgoverlap_tmp1;';
     76
     77EXECUTE
     78'CREATE TABLE '||schema_a||'.pgoverlap_tmp1 (
     79gid serial,
     80a_'||a_id||' integer,
     81b_'||a_id||' integer,
     82a_geom geometry,
     83b_geom geometry,
     84i_geom geometry,
     85area numeric,
     86perimeter2 numeric,
     87perimeter2_uc numeric,
     88cmp numeric,
     89sliver character varying(1)
     90 );';
     91
     92RAISE NOTICE 'Find all overlappings with geometrytype Polygon. ';
     93
     94EXECUTE
     95'INSERT INTO '||schema_a||'.pgoverlap_tmp1 (
     96a_'||a_id||', b_'||a_id||', a_geom, b_geom, i_geom)
     97SELECT DISTINCT
     98sel.a_'||a_id||',
     99sel.b_'||a_id||',
     100sel.a_geom,
     101sel.b_geom,
     102sel.i_geom
     103FROM (
     104SELECT
     105a.'||a_id||' AS a_'||a_id||',
     106b.'||a_id||' AS b_'||a_id||',
     107a.the_geom AS a_geom,
     108b.the_geom AS b_geom,
     109(ST_Dump(ST_Intersection(a.the_geom,b.the_geom))).geom AS i_geom
     110FROM
     111'||schema_a||'.'||table_a||' a
     112LEFT JOIN
     113'||schema_a||'.'||table_a||' b
     114ON a.the_geom && b.the_geom
     115WHERE
     116a.gid < b.gid AND
     117ST_Intersects(a.the_geom, b.the_geom)) AS sel
     118WHERE
     119ST_GeometryType(sel.i_geom) NOT IN (
     120''ST_Point'',
     121''ST_LineString'',
     122''ST_MultiPoint'',
     123''ST_MultiLineString'',
     124''ST_Line'');';
     125
     126EXECUTE
     127'CREATE INDEX pgoverlap_tmp1_gid_btree
     128ON '||schema_a||'.pgoverlap_tmp1
     129USING btree(gid);';
     130
     131EXECUTE
     132'CREATE INDEX pgoverlap_tmp1_a_'||a_id||'_btree
     133ON '||schema_a||'.pgoverlap_tmp1
     134USING btree(a_'||a_id||');';
     135
     136EXECUTE
     137'CREATE INDEX pgoverlap_tmp1_b_'||a_id||'_btree
     138ON '||schema_a||'.pgoverlap_tmp1
     139USING btree(b_'||a_id||');';
     140
     141
     142--Check for sliver polygons
     143
     144RAISE NOTICE 'Check for sliver polygons. ';
     145
     146--1. Calculation of area and perimeter:
     147
     148EXECUTE
     149'UPDATE '||schema_a||'.pgoverlap_tmp1
     150SET area=ST_Area(i_geom),
     151    perimeter2=ST_Perimeter(i_geom)^2;';
     152
     153--2. Calculation of circle perimeter with area equal to area of the polygon:
     154EXECUTE
     155'UPDATE '||schema_a||'.pgoverlap_tmp1
     156SET perimeter2_uc=4*pi()*area;';
     157
     158
     159--3. Calculation of Compactness Index (cmp):
     160
     161EXECUTE
     162'UPDATE '||schema_a||'.pgoverlap_tmp1
     163SET cmp=perimeter2_uc/perimeter2;';
     164
     165--4. Decision: sliver polygon, true or false?:
     166
     167EXECUTE
     168'UPDATE '||schema_a||'.pgoverlap_tmp1 SET sliver=''t'' WHERE area < 10;';
     169
     170EXECUTE
     171'UPDATE '||schema_a||'.pgoverlap_tmp1 SET sliver=''t'' WHERE cmp < 0.13;';
     172
     173EXECUTE
     174'UPDATE '||schema_a||'.pgoverlap_tmp1 SET sliver=''f'' WHERE sliver IS NULL;';
     175/*
     176EXECUTE
     177'UPDATE '||schema_a||'.pgoverlap_tmp1 SET sliver=''f'' WHERE area > 150;';
     178*/
     179
     180--Create table for sliver polygons:
     181
     182EXECUTE
     183'DROP TABLE IF EXISTS '||schema_a||'.pgoverlap_tmp2;';
     184
     185EXECUTE
     186'CREATE TABLE '||schema_a||'.pgoverlap_tmp2 (
     187gid serial,
     188a_'||a_id||' integer,
     189a_geom geometry,
     190i_geom_union geometry,
     191the_geom geometry
     192);';
     193
     194RAISE NOTICE 'Processing sliver polygons. ';
     195
     196EXECUTE
     197'INSERT INTO '||schema_a||'.pgoverlap_tmp2
     198(a_'||a_id||', a_geom, i_geom_union)
     199SELECT a_'||a_id||', a_geom, CASE WHEN ST_Union(i_geom) IS NULL THEN ST_Collect(i_geom) ELSE ST_Union(i_geom) END
     200FROM '||schema_a||'.pgoverlap_tmp1
     201WHERE sliver=''t''
     202GROUP BY a_'||a_id||', a_geom;';
     203
     204i:=0;
     205
     206sql_1:='SELECT gid FROM '||schema_a||'.pgoverlap_tmp2 ORDER BY gid;';
     207
     208FOR i IN EXECUTE sql_1 LOOP
     209BEGIN
     210
     211EXECUTE
     212'UPDATE '||schema_a||'.pgoverlap_tmp2 SET the_geom=ST_Difference(a_geom, i_geom_union) WHERE gid='||i||';';
     213
     214EXCEPTION WHEN internal_error THEN
     215
     216EXECUTE
     217'UPDATE '||schema_a||'.pgoverlap_tmp2 SET the_geom=ST_Difference(ST_Buffer(a_geom,0.0), ST_Buffer(i_geom_union,0.0)) WHERE gid='||i||';';
     218
     219END;
     220END LOOP;
     221
     222EXECUTE
     223'CREATE INDEX pgoverlap_tmp2_a_'||a_id||'_btree
     224ON '||schema_a||'.pgoverlap_tmp2
     225USING btree(a_'||a_id||');';
     226
     227
     228--Create table with IDs of sliver polygons:
     229
     230RAISE NOTICE 'Creating table with IDs of sliver polygons. ';
     231
     232EXECUTE
     233'DROP TABLE IF EXISTS '||schema_a||'.pgoverlap_tmp3;';
     234
     235EXECUTE
     236'CREATE TABLE '||schema_a||'.pgoverlap_tmp3 (
     237'||a_id||' integer);';
     238
     239EXECUTE
     240'INSERT INTO '||schema_a||'.pgoverlap_tmp3 ('||a_id||')
     241SELECT DISTINCT a_'||a_id||'
     242FROM '||schema_a||'.pgoverlap_tmp2;';
     243
     244EXECUTE
     245'INSERT INTO '||schema_a||'.pgoverlap_tmp3 ('||a_id||')
     246SELECT DISTINCT a.b_'||a_id||'
     247FROM
     248'||schema_a||'.pgoverlap_tmp1 a
     249LEFT JOIN
     250'||schema_a||'.pgoverlap_tmp2 b
     251ON a.b_'||a_id||'=b.a_'||a_id||'
     252WHERE b.a_'||a_id||' IS NULL;';
     253
     254
     255--Insert non-sliver polygons into seperate table:
     256
     257BEGIN
     258EXECUTE
     259'SELECT DropGeometryTable('''||schema_a||''','''||table_result2||''');';
     260EXCEPTION WHEN undefined_table THEN
     261END;
     262
     263EXECUTE
     264'CREATE TABLE '||schema_a||'.'||table_result2||' (
     265 gid serial PRIMARY KEY,
     266 a_'||a_id||' integer,
     267 b_'||a_id||' integer
     268 );';
     269
     270EXECUTE
     271'SELECT AddGeometryColumn('''||schema_a||''', '''||table_result2||''',''a_geom'',(SELECT DISTINCT ST_SRID(the_geom) FROM '||schema_a||'.'||table_a||'),''POLYGON'',2);';
     272
     273EXECUTE
     274'SELECT AddGeometryColumn('''||schema_a||''', '''||table_result2||''',''b_geom'',(SELECT DISTINCT ST_SRID(the_geom) FROM '||schema_a||'.'||table_a||'),''POLYGON'',2);';
     275
     276EXECUTE
     277'SELECT AddGeometryColumn('''||schema_a||''', '''||table_result2||''',''i_geom'',(SELECT DISTINCT ST_SRID(the_geom) FROM '||schema_a||'.'||table_a||'),''POLYGON'',2);';
     278
     279RAISE NOTICE 'Inserting non-sliver polygons into seperate table. ';
     280
     281EXECUTE
     282'INSERT INTO '||schema_a||'.'||table_result2||' (
     283 a_'||a_id||',
     284 b_'||a_id||',
     285 a_geom,
     286 b_geom,
     287 i_geom)
     288SELECT
     289 a_'||a_id||',
     290 b_'||a_id||',
     291 a_geom,
     292 b_geom,
     293 i_geom
     294FROM '||schema_a||'.pgoverlap_tmp1
     295WHERE sliver=''f'';';
     296
     297
     298--create table with IDs of non-sliver polygons:
     299
     300RAISE NOTICE 'creating table with IDs of non-sliver polygons. ';
     301
     302EXECUTE
     303'DROP TABLE IF EXISTS '||schema_a||'.pgoverlap_tmp4;';
     304
     305EXECUTE
     306'CREATE TABLE '||schema_a||'.pgoverlap_tmp4 (
     307'||a_id||' integer);';
     308
     309EXECUTE
     310'INSERT INTO '||schema_a||'.pgoverlap_tmp4 ('||a_id||')
     311SELECT DISTINCT a_'||a_id||'
     312FROM '||schema_a||'.'||table_result2||';';
     313
     314EXECUTE
     315'INSERT INTO '||schema_a||'.pgoverlap_tmp4 ('||a_id||')
     316SELECT DISTINCT a.b_'||a_id||'
     317FROM
     318'||schema_a||'.'||table_result2||' a
     319LEFT JOIN
     320'||schema_a||'.'||table_result2||' b
     321ON a.b_'||a_id||'=b.a_'||a_id||'
     322WHERE b.a_'||a_id||' IS NULL;';
     323
     324
     325--Insert geometries without overlappings into new table:
     326
     327EXECUTE
     328'DROP TABLE IF EXISTS '||schema_a||'.pgoverlap_tmp5;';
     329
     330EXECUTE
     331'CREATE TABLE '||schema_a||'.pgoverlap_tmp5 (
     332 gid serial PRIMARY KEY,
     333 '||a_id||' integer,
     334 the_geom geometry
     335 );';
     336
     337EXECUTE
     338'INSERT INTO '||schema_a||'.pgoverlap_tmp5
     339 ('||a_id||', the_geom)
     340SELECT
     341 a.'||a_id||',
     342 a.the_geom
     343FROM
     344'||schema_a||'.'||table_a||' a
     345LEFT JOIN
     346'||schema_a||'.pgoverlap_tmp3 b
     347ON a.'||a_id||'=b.'||a_id||'
     348LEFT JOIN
     349'||schema_a||'.pgoverlap_tmp4 c
     350ON a.'||a_id||'=c.'||a_id||'
     351WHERE
     352b.'||a_id||' IS NULL AND
     353c.'||a_id||' IS NULL;';
     354
     355
     356--Create and merge result table:
     357
     358BEGIN
     359EXECUTE
     360'SELECT DropGeometryTable('''||schema_a||''','''||table_result1||''');';
     361EXCEPTION WHEN undefined_table THEN
     362END;
     363
     364EXECUTE
     365'CREATE TABLE '||schema_a||'.'||table_result1||' (
     366gid serial PRIMARY KEY,
     367'||a_id||' integer
     368);';
     369EXECUTE
     370'SELECT AddGeometryColumn('''||schema_a||''','''||table_result1||''',''the_geom'',(SELECT DISTINCT ST_SRID(the_geom) FROM '||schema_a||'.'||table_a||'),''POLYGON'',2);';
     371EXECUTE
     372'ALTER TABLE '||schema_a||'.'||table_result1||' DROP CONSTRAINT enforce_geotype_the_geom;';
     373
     374
     375--Insert Difference (sliver overlappings) into result table:
     376
     377EXECUTE
     378'INSERT INTO '||schema_a||'.'||table_result1||' (
     379'||a_id||',
     380the_geom
     381)
     382SELECT
     383a_'||a_id||',
     384(ST_Dump(the_geom)).geom
     385FROM
     386'||schema_a||'.pgoverlap_tmp2
     387WHERE ST_IsEmpty(the_geom)=''f'';';
     388
     389
     390--Insert unchanged polygons (sliver overlappings) into result table:
     391
     392EXECUTE
     393'INSERT INTO '||schema_a||'.'||table_result1||' (
     394'||a_id||',
     395the_geom
     396)
     397SELECT DISTINCT
     398a.b_'||a_id||',
     399a.b_geom
     400FROM
     401'||schema_a||'.pgoverlap_tmp1 a
     402LEFT JOIN
     403'||schema_a||'.pgoverlap_tmp2 b
     404ON a.b_'||a_id||'=b.a_'||a_id||'
     405WHERE
     406a.sliver=''t'' AND
     407b.a_'||a_id||' IS NULL;';
     408
     409
     410--Insert non-overlapping polygons into result table:
     411
     412EXECUTE
     413'INSERT INTO '||schema_a||'.'||table_result1||' (
     414'||a_id||',
     415the_geom
     416)
     417SELECT
     418'||a_id||',
     419the_geom
     420FROM '||schema_a||'.pgoverlap_tmp5;';
     421
     422
     423--Update geometries already processed as sliver overlappings which also have non-sliver overlappings:
     424
     425EXECUTE
     426'UPDATE '||schema_a||'.'||table_result2||' t SET a_geom=a.geom FROM (SELECT '||a_id||', CASE WHEN ST_Union(the_geom) IS NULL THEN ST_Collect(the_geom) ELSE ST_Union(the_geom) END AS geom FROM '||schema_a||'.'||table_result1||' GROUP BY '||a_id||') a WHERE t.a_'||a_id||'=a.'||a_id||';';
     427
     428EXECUTE
     429'UPDATE '||schema_a||'.'||table_result2||' t SET b_geom=a.geom FROM (SELECT '||a_id||', CASE WHEN ST_Union(the_geom) IS NULL THEN ST_Collect(the_geom) ELSE ST_Union(the_geom) END AS geom FROM '||schema_a||'.'||table_result1||' GROUP BY '||a_id||') a WHERE t.b_'||a_id||'=a.'||a_id||';';
     430
     431EXECUTE
     432'DELETE FROM '||schema_a||'.'||table_result1||' WHERE '||a_id||' IN (SELECT '||a_id||' FROM '||schema_a||'.pgoverlap_tmp4);';
     433
     434--Remove tmp tables:
     435
     436EXECUTE
     437'DROP TABLE '||schema_a||'.pgoverlap_tmp1;';
     438EXECUTE
     439'DROP TABLE '||schema_a||'.pgoverlap_tmp2;';
     440EXECUTE
     441'DROP TABLE '||schema_a||'.pgoverlap_tmp3;';
     442EXECUTE
     443'DROP TABLE '||schema_a||'.pgoverlap_tmp4;';
     444EXECUTE
     445'DROP TABLE '||schema_a||'.pgoverlap_tmp5;';
     446
     447
     448END;
     449$BODY$
     450  LANGUAGE 'plpgsql' VOLATILE
     451  COST 100;
     452ALTER FUNCTION public._pgoverlap(varchar, varchar, varchar, varchar, varchar) OWNER TO postgres;
     453}}}