From da689f9e424dcd2c38aece17ae40b55255a28c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20La=C5=BEa?= Date: Tue, 24 Nov 2020 09:33:06 +0100 Subject: [PATCH] Fix landcover generalization. (#1042) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR brings few modification which make it possible to generalize landcover on larger areas. Tested on Europe. - Use ST_SnapToGrid to avoid ERROR:  GEOSUnaryUnion: TopologyException: found non-noded intersection between LINESTRING. - Cluster only landcover subclasses: wood and forest. - Use less generalized tables as a starting point for next step generalization. --- layers/landcover/generalized.sql | 580 +++++++++++++++++-------------- 1 file changed, 326 insertions(+), 254 deletions(-) diff --git a/layers/landcover/generalized.sql b/layers/landcover/generalized.sql index 373da46..536b0b8 100644 --- a/layers/landcover/generalized.sql +++ b/layers/landcover/generalized.sql @@ -5,27 +5,332 @@ DROP TABLE IF EXISTS osm_landcover_gen_z10; DROP TABLE IF EXISTS osm_landcover_gen_z11; DROP TABLE IF EXISTS osm_landcover_gen_z12; DROP TABLE IF EXISTS osm_landcover_gen_z13; +DROP TABLE IF EXISTS simplify_vw_z7 CASCADE; +DROP TABLE IF EXISTS simplify_vw_z8 CASCADE; +DROP TABLE IF EXISTS simplify_vw_z9 CASCADE; +DROP TABLE IF EXISTS simplify_vw_z10 CASCADE; +DROP TABLE IF EXISTS simplify_vw_z11 CASCADE; +DROP TABLE IF EXISTS simplify_vw_z12 CASCADE; +DROP TABLE IF EXISTS simplify_vw_z13 CASCADE; --- etldoc: osm_landcover_polygon -> osm_landcover_gen_z7 -CREATE TABLE osm_landcover_gen_z7 AS +-- etldoc: osm_landcover_polygon -> osm_landcover_gen_z13 +CREATE TABLE simplify_vw_z13 AS ( - WITH simplify_vw_z7 AS - ( - SELECT subclass, - ST_MakeValid( - ST_SimplifyVW(geometry, zres(7)*zres(7))) AS geometry + SELECT subclass, + ST_MakeValid( + ST_SnapToGrid( + ST_SimplifyVW(geometry, power(zres(13),2)), + 0.001)) AS geometry FROM osm_landcover_polygon - WHERE ST_Area(geometry) > power(zres(5),2) - ) + WHERE ST_Area(geometry) > power(zres(10),2) +); +CREATE INDEX ON simplify_vw_z13 USING GIST (geometry); -SELECT subclass, +CREATE TABLE osm_landcover_gen_z13 AS +( +SELECT subclass, + ST_MakeValid( + (ST_dump( + ST_Union(geometry))).geom) AS geometry + FROM ( + SELECT subclass, + ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry + FROM simplify_vw_z13 + WHERE ST_NPoints(geometry) < 50 + AND subclass IN ('wood', 'forest')) union_geom50 + GROUP BY subclass, + cid + UNION ALL + SELECT subclass, ST_MakeValid((ST_dump(ST_Union(geometry))).geom) AS geometry + FROM ( + SELECT subclass, + ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry + FROM simplify_vw_z13 + WHERE ST_NPoints(geometry) >= 50 + AND ST_NPoints(geometry) < 300 + AND subclass IN ('wood', 'forest')) union_geom300 + GROUP BY subclass, + cid + UNION ALL + SELECT subclass, + geometry + FROM simplify_vw_z13 + WHERE (ST_NPoints(geometry) >= 300 AND subclass IN ('wood', 'forest')) + OR (subclass NOT IN ('wood', 'forest')) + ); + +CREATE INDEX ON osm_landcover_gen_z13 USING GIST (geometry); + + +-- etldoc: osm_landcover_polygon -> osm_landcover_gen_z12 +CREATE TABLE simplify_vw_z12 AS +( + SELECT subclass, + ST_MakeValid( + ST_SnapToGrid( + ST_SimplifyVW(geometry, power(zres(12),2)), + 0.001)) AS geometry + FROM simplify_vw_z13 + WHERE ST_Area(geometry) > power(zres(9),2) +); +CREATE INDEX ON simplify_vw_z12 USING GIST (geometry); + +CREATE TABLE osm_landcover_gen_z12 AS +( +SELECT subclass, + ST_MakeValid( + (ST_dump( + ST_Union(geometry))).geom) AS geometry + FROM ( + SELECT subclass, + ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry + FROM simplify_vw_z12 + WHERE ST_NPoints(geometry) < 50 + AND subclass IN ('wood', 'forest')) union_geom50 + GROUP BY subclass, + cid + UNION ALL + SELECT subclass, ST_MakeValid((ST_dump(ST_Union(geometry))).geom) AS geometry + FROM ( + SELECT subclass, + ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry + FROM simplify_vw_z12 + WHERE ST_NPoints(geometry) >= 50 + AND ST_NPoints(geometry) < 300 + AND subclass IN ('wood', 'forest')) union_geom300 + GROUP BY subclass, + cid + UNION ALL + SELECT subclass, + geometry + FROM simplify_vw_z12 + WHERE (ST_NPoints(geometry) >= 300 AND subclass IN ('wood', 'forest')) + OR (subclass NOT IN ('wood', 'forest')) + ); + +CREATE INDEX ON osm_landcover_gen_z12 USING GIST (geometry); + + +-- etldoc: osm_landcover_polygon -> osm_landcover_gen_z11 +CREATE TABLE simplify_vw_z11 AS +( + SELECT subclass, + ST_MakeValid( + ST_SnapToGrid( + ST_SimplifyVW(geometry, power(zres(11),2)), + 0.001)) AS geometry + FROM simplify_vw_z12 + WHERE ST_Area(geometry) > power(zres(8),2) +); +CREATE INDEX ON simplify_vw_z11 USING GIST (geometry); + +CREATE TABLE osm_landcover_gen_z11 AS +( +SELECT subclass, + ST_MakeValid( + (ST_dump( + ST_Union(geometry))).geom) AS geometry + FROM ( + SELECT subclass, + ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry + FROM simplify_vw_z11 + WHERE ST_NPoints(geometry) < 50 + AND subclass IN ('wood', 'forest')) union_geom50 + GROUP BY subclass, + cid + UNION ALL + SELECT subclass, ST_MakeValid((ST_dump(ST_Union(geometry))).geom) AS geometry + FROM ( + SELECT subclass, + ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry + FROM simplify_vw_z11 + WHERE ST_NPoints(geometry) >= 50 + AND ST_NPoints(geometry) < 300 + AND subclass IN ('wood', 'forest')) union_geom300 + GROUP BY subclass, + cid + UNION ALL + SELECT subclass, + geometry + FROM simplify_vw_z11 + WHERE (ST_NPoints(geometry) >= 300 AND subclass IN ('wood', 'forest')) + OR (subclass NOT IN ('wood', 'forest')) + ); + +CREATE INDEX ON osm_landcover_gen_z11 USING GIST (geometry); + + +-- etldoc: osm_landcover_polygon -> osm_landcover_gen_z10 +CREATE TABLE simplify_vw_z10 AS +( + SELECT subclass, + ST_MakeValid( + ST_SnapToGrid( + ST_SimplifyVW(geometry, power(zres(10),2)), + 0.001)) AS geometry + FROM simplify_vw_z11 + WHERE ST_Area(geometry) > power(zres(8),2) +); +CREATE INDEX ON simplify_vw_z10 USING GIST (geometry); + +CREATE TABLE osm_landcover_gen_z10 AS +( +SELECT subclass, + ST_MakeValid( + (ST_dump( + ST_Union(geometry))).geom) AS geometry + FROM ( + SELECT subclass, + ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry + FROM simplify_vw_z10 + WHERE ST_NPoints(geometry) < 50 + AND subclass IN ('wood', 'forest')) union_geom50 + GROUP BY subclass, + cid + UNION ALL + SELECT subclass, ST_MakeValid((ST_dump(ST_Union(geometry))).geom) AS geometry + FROM ( + SELECT subclass, + ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry + FROM simplify_vw_z10 + WHERE ST_NPoints(geometry) >= 50 + AND ST_NPoints(geometry) < 300 + AND subclass IN ('wood', 'forest')) union_geom300 + GROUP BY subclass, + cid + UNION ALL + SELECT subclass, + geometry + FROM simplify_vw_z10 + WHERE (ST_NPoints(geometry) >= 300 AND subclass IN ('wood', 'forest')) + OR (subclass IN ('wood', 'forest')) + ); + +CREATE INDEX ON osm_landcover_gen_z10 USING GIST (geometry); + + +-- etldoc: osm_landcover_polygon -> osm_landcover_gen_z9 +CREATE TABLE simplify_vw_z9 AS +( + SELECT subclass, + ST_MakeValid( + ST_SnapToGrid( + ST_SimplifyVW(geometry, power(zres(9),2)), + 0.001)) AS geometry + FROM simplify_vw_z10 + WHERE ST_Area(geometry) > power(zres(7),2) +); +CREATE INDEX ON simplify_vw_z9 USING GIST (geometry); + +CREATE TABLE osm_landcover_gen_z9 AS +( +SELECT subclass, + ST_MakeValid( + (ST_dump( + ST_Union(geometry))).geom) AS geometry + FROM ( + SELECT subclass, + ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry + FROM simplify_vw_z9 + WHERE ST_NPoints(geometry) < 50 + AND subclass IN ('wood', 'forest')) union_geom50 + GROUP BY subclass, + cid + UNION ALL + SELECT subclass, ST_MakeValid((ST_dump(ST_Union(geometry))).geom) AS geometry + FROM ( + SELECT subclass, + ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry + FROM simplify_vw_z9 + WHERE ST_NPoints(geometry) >= 50 + AND ST_NPoints(geometry) < 300 + AND subclass IN ('wood', 'forest')) union_geom300 + GROUP BY subclass, + cid + UNION ALL + SELECT subclass, + ST_MakeValid( + (ST_Dump( + ST_Union(geometry))).geom) AS geometry + FROM ( + SELECT subclass, + ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry + FROM simplify_vw_z9 + WHERE ST_NPoints(geometry) >= 300 + AND subclass IN ('wood', 'forest')) union_geom_rest + GROUP BY subclass, + cid + UNION ALL + SELECT subclass, + geometry + FROM simplify_vw_z9 + WHERE subclass NOT IN ('wood', 'forest') + ); + +CREATE INDEX ON osm_landcover_gen_z9 USING GIST (geometry); + + +-- etldoc: osm_landcover_polygon -> osm_landcover_gen_z8 +CREATE TABLE simplify_vw_z8 AS +( + SELECT subclass, + ST_MakeValid( + ST_SnapToGrid( + ST_SimplifyVW(geometry, power(zres(8),2)), + 0.001)) AS geometry + FROM simplify_vw_z9 + WHERE ST_Area(geometry) > power(zres(6),2) + ); +CREATE INDEX ON simplify_vw_z8 USING GIST (geometry); + +CREATE TABLE osm_landcover_gen_z8 AS +( +SELECT subclass, ST_MakeValid( (ST_Dump( - ST_Union(geometry))).geom) AS geometry - FROM + ST_Union(geometry))).geom) AS geometry + FROM ( - SELECT subclass, - ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) OVER () AS cid, + SELECT subclass, + ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) OVER () AS cid, + geometry + FROM simplify_vw_z8 + ) union_geom + GROUP BY subclass, + cid + UNION ALL + SELECT subclass, + geometry + FROM simplify_vw_z8 + WHERE subclass NOT IN ('wood', 'forest') + ); + +CREATE INDEX ON osm_landcover_gen_z8 USING GIST (geometry); + + +-- etldoc: osm_landcover_polygon -> osm_landcover_gen_z7 +CREATE TABLE simplify_vw_z7 AS +( + SELECT subclass, + ST_MakeValid( + ST_SnapToGrid( + ST_SimplifyVW(geometry, power(zres(7),2)), + 0.001)) AS geometry + FROM simplify_vw_z8 + WHERE ST_Area(geometry) > power(zres(5),2) +); +CREATE INDEX ON simplify_vw_z7 USING GIST (geometry); + +CREATE TABLE osm_landcover_gen_z7 AS +( +SELECT subclass, + ST_MakeValid( + (ST_Dump( + ST_Union(geometry))).geom) AS geometry + FROM + ( + SELECT subclass, + ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) OVER () AS cid, geometry FROM simplify_vw_z7 ) union_geom @@ -35,243 +340,10 @@ GROUP BY subclass, CREATE INDEX ON osm_landcover_gen_z7 USING GIST (geometry); --- etldoc: osm_landcover_polygon -> osm_landcover_gen_z8 -CREATE TABLE osm_landcover_gen_z8 AS -( - WITH simplify_vw_z8 AS - ( - SELECT subclass, - ST_MakeValid( - ST_SimplifyVW(geometry, zres(8)*zres(8))) AS geometry - FROM osm_landcover_polygon - WHERE ST_Area(geometry) > power(zres(6),2) - ) - -SELECT subclass, - ST_MakeValid( - (ST_Dump( - ST_Union(geometry))).geom) AS geometry - FROM - ( - SELECT subclass, - ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) OVER () AS cid, - geometry - FROM simplify_vw_z8 - ) union_geom -GROUP BY subclass, - cid - ); - -CREATE INDEX ON osm_landcover_gen_z8 USING GIST (geometry); - --- etldoc: osm_landcover_polygon -> osm_landcover_gen_z9 -CREATE TABLE osm_landcover_gen_z9 AS -( - WITH simplify_vw_z9 AS - ( - SELECT subclass, - ST_MakeValid( - ST_SimplifyVW(geometry, zres(9)*zres(9))) AS geometry - FROM osm_landcover_polygon - WHERE ST_Area(geometry) > power(zres(7),2) - ) - -SELECT subclass, - ST_MakeValid( - (ST_dump( - ST_Union(geometry))).geom) AS geometry - FROM ( - SELECT subclass, - ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry - FROM simplify_vw_z9 - WHERE ST_NPoints(geometry) < 50) union_geom50 - GROUP BY subclass, - cid - UNION ALL - SELECT subclass, st_makevalid((ST_dump(ST_Union(geometry))).geom) AS geometry - FROM ( - SELECT subclass, - ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry - FROM simplify_vw_z9 - WHERE ST_NPoints(geometry) >= 50 AND ST_NPoints(geometry) < 300) union_geom300 - GROUP BY subclass, - cid - UNION ALL - SELECT subclass, - ST_MakeValid( - (ST_Dump( - ST_Union(geometry))).geom) AS geometry - FROM ( - SELECT subclass, - ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry - FROM simplify_vw_z9 - WHERE ST_NPoints(geometry) >= 300) union_geom_rest - GROUP BY subclass, - cid - ); - -CREATE INDEX ON osm_landcover_gen_z9 USING GIST (geometry); - --- etldoc: osm_landcover_polygon -> osm_landcover_gen_z10 -CREATE TABLE osm_landcover_gen_z10 AS -( - WITH simplify_vw_z10 AS - ( - SELECT subclass, - ST_MakeValid( - ST_SimplifyVW(geometry, zres(10)*zres(10))) AS geometry - FROM osm_landcover_polygon - WHERE ST_Area(geometry) > power(zres(8),2) - ) - -SELECT subclass, - ST_MakeValid( - (ST_dump( - ST_Union(geometry))).geom) AS geometry - FROM ( - SELECT subclass, - ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry - FROM simplify_vw_z10 - WHERE ST_NPoints(geometry) < 50) union_geom50 - GROUP BY subclass, - cid - UNION ALL - SELECT subclass, st_makevalid((ST_dump(ST_Union(geometry))).geom) AS geometry - FROM ( - SELECT subclass, - ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry - FROM simplify_vw_z10 - WHERE ST_NPoints(geometry) >= 50 AND ST_NPoints(geometry) < 300) union_geom300 - GROUP BY subclass, - cid - UNION ALL - SELECT subclass, - geometry - FROM simplify_vw_z10 - WHERE ST_NPoints(geometry) >= 300 - ); - -CREATE INDEX ON osm_landcover_gen_z10 USING GIST (geometry); - --- etldoc: osm_landcover_polygon -> osm_landcover_gen_z11 -CREATE TABLE osm_landcover_gen_z11 AS -( - WITH simplify_vw_z11 AS - ( - SELECT subclass, - ST_MakeValid( - ST_SimplifyVW(geometry, zres(11)*zres(11))) AS geometry - FROM osm_landcover_polygon - WHERE ST_Area(geometry) > power(zres(8),2) - ) - -SELECT subclass, - ST_MakeValid( - (ST_dump( - ST_Union(geometry))).geom) AS geometry - FROM ( - SELECT subclass, - ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry - FROM simplify_vw_z11 - WHERE ST_NPoints(geometry) < 50) union_geom50 - GROUP BY subclass, - cid - UNION ALL - SELECT subclass, st_makevalid((ST_dump(ST_Union(geometry))).geom) AS geometry - FROM ( - SELECT subclass, - ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry - FROM simplify_vw_z11 - WHERE ST_NPoints(geometry) >= 50 AND ST_NPoints(geometry) < 300) union_geom300 - GROUP BY subclass, - cid - UNION ALL - SELECT subclass, - geometry - FROM simplify_vw_z11 - WHERE ST_NPoints(geometry) >= 300 - ); - -CREATE INDEX ON osm_landcover_gen_z11 USING GIST (geometry); - --- etldoc: osm_landcover_polygon -> osm_landcover_gen_z12 -CREATE TABLE osm_landcover_gen_z12 AS -( - WITH simplify_vw_z12 AS - ( - SELECT subclass, - ST_MakeValid( - ST_SimplifyVW(geometry, zres(12)*zres(12))) AS geometry - FROM osm_landcover_polygon - WHERE ST_Area(geometry) > power(zres(9),2) - ) - -SELECT subclass, - ST_MakeValid( - (ST_dump( - ST_Union(geometry))).geom) AS geometry - FROM ( - SELECT subclass, - ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry - FROM simplify_vw_z12 - WHERE ST_NPoints(geometry) < 50) union_geom50 - GROUP BY subclass, - cid - UNION ALL - SELECT subclass, st_makevalid((ST_dump(ST_Union(geometry))).geom) AS geometry - FROM ( - SELECT subclass, - ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry - FROM simplify_vw_z12 - WHERE ST_NPoints(geometry) >= 50 AND ST_NPoints(geometry) < 300) union_geom300 - GROUP BY subclass, - cid - UNION ALL - SELECT subclass, - geometry - FROM simplify_vw_z12 - WHERE ST_NPoints(geometry) >= 300 - ); - -CREATE INDEX ON osm_landcover_gen_z12 USING GIST (geometry); - --- etldoc: osm_landcover_polygon -> osm_landcover_gen_z13 -CREATE TABLE osm_landcover_gen_z13 AS -( - WITH simplify_vw_z13 AS - ( - SELECT subclass, - ST_MakeValid( - ST_SimplifyVW(geometry, zres(13)*zres(13))) AS geometry - FROM osm_landcover_polygon - WHERE ST_Area(geometry) > power(zres(10),2) - ) - -SELECT subclass, - ST_MakeValid( - (ST_dump( - ST_Union(geometry))).geom) AS geometry - FROM ( - SELECT subclass, - ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry - FROM simplify_vw_z13 - WHERE ST_NPoints(geometry) < 50) union_geom50 - GROUP BY subclass, - cid - UNION ALL - SELECT subclass, st_makevalid((ST_dump(ST_Union(geometry))).geom) AS geometry - FROM ( - SELECT subclass, - ST_ClusterDBSCAN(geometry, eps := 0, minpoints := 1) over () AS cid, geometry - FROM simplify_vw_z13 - WHERE ST_NPoints(geometry) >= 50 AND ST_NPoints(geometry) < 300) union_geom300 - GROUP BY subclass, - cid - UNION ALL - SELECT subclass, - geometry - FROM simplify_vw_z13 - WHERE ST_NPoints(geometry) >= 300 - ); - -CREATE INDEX ON osm_landcover_gen_z13 USING GIST (geometry); \ No newline at end of file +DROP TABLE IF EXISTS simplify_vw_z7 CASCADE; +DROP TABLE IF EXISTS simplify_vw_z8 CASCADE; +DROP TABLE IF EXISTS simplify_vw_z9 CASCADE; +DROP TABLE IF EXISTS simplify_vw_z10 CASCADE; +DROP TABLE IF EXISTS simplify_vw_z11 CASCADE; +DROP TABLE IF EXISTS simplify_vw_z12 CASCADE; +DROP TABLE IF EXISTS simplify_vw_z13 CASCADE;