diff --git a/layers/building/building.sql b/layers/building/building.sql index f08e8631f..47b2c51ed 100644 --- a/layers/building/building.sql +++ b/layers/building/building.sql @@ -82,7 +82,7 @@ SELECT geometry, CASE WHEN hide_3d THEN TRUE END AS hide_3d FROM ( SELECT - -- etldoc: osm_building_polygon_gen1 -> layer_building:z13 + -- etldoc: osm_building_block_gen1 -> layer_building:z13 osm_id, geometry, NULL::int AS render_height, @@ -90,7 +90,7 @@ FROM ( NULL::text AS material, NULL::text AS colour, FALSE AS hide_3d - FROM osm_building_polygon_gen1 + FROM osm_building_block_gen1 WHERE zoom_level = 13 AND geometry && bbox UNION ALL diff --git a/layers/building/building.yaml b/layers/building/building.yaml index 1bf360b74..ea2bc6786 100644 --- a/layers/building/building.yaml +++ b/layers/building/building.yaml @@ -20,7 +20,8 @@ layer: hide_3d: | If True, building (part) should not be rendered in 3D. Currently, [building outlines](https://wiki.openstreetmap.org/wiki/Simple_3D_buildings) are marked as hide_3d. schema: + - ./update_building.sql - ./building.sql datasources: - type: imposm3 - mapping_file: ./mapping.yaml + mapping_file: ./mapping.yaml \ No newline at end of file diff --git a/layers/building/etl_diagram.png b/layers/building/etl_diagram.png index 53f5f042f..c77cd48fb 100644 Binary files a/layers/building/etl_diagram.png and b/layers/building/etl_diagram.png differ diff --git a/layers/building/mapping.yaml b/layers/building/mapping.yaml index ce72b97ce..858899ba6 100644 --- a/layers/building/mapping.yaml +++ b/layers/building/mapping.yaml @@ -1,9 +1,9 @@ -generalized_tables: - # etldoc: imposm3 -> osm_building_polygon_gen1 - building_polygon_gen1: - source: building_polygon - sql_filter: area>power(ZRES12,2) AND ST_IsValid(geometry) - tolerance: ZRES14 +#generalized_tables: +# # etldoc: imposm3 -> osm_building_polygon_gen1 +# building_polygon_gen1: +# source: building_polygon +# sql_filter: area>power(ZRES12,2) AND ST_IsValid(geometry) +# tolerance: ZRES14 tables: # etldoc: imposm3 -> osm_building_polygon @@ -157,4 +157,4 @@ tables: type: member_type mapping: type: [building] - type: relation_member + type: relation_member \ No newline at end of file diff --git a/layers/building/update_building.sql b/layers/building/update_building.sql new file mode 100644 index 000000000..5c15ae8a6 --- /dev/null +++ b/layers/building/update_building.sql @@ -0,0 +1,125 @@ +DROP TRIGGER IF EXISTS trigger_refresh ON buildings.updates; +DROP TRIGGER IF EXISTS trigger_flag ON osm_building_polygon; + +--creating aggregated building blocks with removed small polygons and small +--holes. Aggregated polygons are simplified. + +--function returning recordset for matview +--returning recordset of buildings aggregates by zres 14, with removed small +--holes and with removed small buildings/blocks +-- + +CREATE OR REPLACE FUNCTION osm_building_block_gen1() + RETURNS table + ( + osm_id bigint, + geometry geometry + ) +AS +$$ +DECLARE + zres14 float := Zres(14); + zres12 float := Zres(12); +BEGIN + FOR osm_id, geometry IN + WITH dta AS ( -- CTE is used because of optimization + SELECT o.osm_id, o.geometry, ST_ClusterDBSCAN(o.geometry, eps := zres14, minpoints := 1) OVER () cid + FROM osm_building_polygon o + ) + SELECT (array_agg(dta.osm_id))[1] osm_id, + ST_Buffer(ST_MemUnion(ST_Buffer(dta.geometry, zres14, 'join=mitre')), -zres14, 'join=mitre') geometry + FROM dta + GROUP BY cid + + LOOP + -- removing holes smaller than + IF ST_NumInteriorRings(geometry) > 0 THEN -- only from geometries wih holes + geometry := ( + -- there are some multi-geometries in this layer + SELECT ST_Collect(gn) + FROM ( + -- in some cases are "holes" NULL, because all holes are smaller than + SELECT COALESCE( + -- exterior ring + ST_MakePolygon(ST_ExteriorRing(dmp.geom), holes), + ST_MakePolygon(ST_ExteriorRing(dmp.geom)) + ) gn + + FROM ST_Dump(geometry) dmp, -- 1 dump polygons + LATERAL ( + SELECT array_agg(ST_Boundary(rg.geom)) holes -- 2 create array + FROM ST_DumpRings(dmp.geom) rg -- 3 from rings + WHERE rg.path[1] > 0 -- 5 except inner ring + AND ST_Area(rg.geom) >= power(zres12, 2) -- 4 bigger than + ) holes + ) new_geom + ); + END IF; + + IF ST_Area(geometry) < power(zres12, 2) THEN + CONTINUE; + END IF; + + -- simplify + geometry := ST_SimplifyPreserveTopology(geometry, zres14::float); + + RETURN NEXT; + END LOOP; +END; +$$ LANGUAGE plpgsql STABLE + STRICT + PARALLEL SAFE; + + +DROP MATERIALIZED VIEW IF EXISTS osm_building_block_gen1; + +CREATE MATERIALIZED VIEW osm_building_block_gen1 AS +SELECT * +FROM osm_building_block_gen1(); + +CREATE INDEX ON osm_building_block_gen1 USING gist (geometry); +CREATE UNIQUE INDEX ON osm_building_block_gen1 USING btree (osm_id); + + +-- Handle updates + +CREATE SCHEMA IF NOT EXISTS buildings; + +CREATE TABLE IF NOT EXISTS buildings.updates +( + id serial PRIMARY KEY, + t text, + UNIQUE (t) +); + +CREATE OR REPLACE FUNCTION buildings.flag() RETURNS trigger AS +$$ +BEGIN + INSERT INTO buildings.updates(t) VALUES ('y') ON CONFLICT(t) DO NOTHING; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION buildings.refresh() RETURNS trigger AS +$$ +BEGIN + RAISE LOG 'Refresh buildings block'; + REFRESH MATERIALIZED VIEW osm_building_block_gen1; + -- noinspection SqlWithoutWhere + DELETE FROM buildings.updates; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trigger_flag + AFTER INSERT OR UPDATE OR DELETE + ON osm_building_polygon + FOR EACH STATEMENT +EXECUTE PROCEDURE buildings.flag(); + +CREATE CONSTRAINT TRIGGER trigger_refresh + AFTER INSERT + ON buildings.updates + INITIALLY DEFERRED + FOR EACH ROW +EXECUTE PROCEDURE buildings.refresh(); \ No newline at end of file