1-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2-- 3-- PostGIS - Spatial Types for PostgreSQL 4-- http://postgis.net 5-- 6-- Copyright (C) 2012 Sandro Santilli <strk@kbt.io> 7-- 8-- This is free software; you can redistribute and/or modify it under 9-- the terms of the GNU General Public Licence. See the COPYING file. 10-- 11-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 12 13-- { 14-- Get a simplified geometry version from a TopoGeometry 15-- 16-- Performs Douglas Peucker algorithm on each edge composing 17-- the given TopoGeometry 18-- 19-- }{ 20CREATE OR REPLACE FUNCTION topology.ST_Simplify(tg topology.TopoGeometry, tolerance float8) 21 RETURNS geometry 22AS 23$$ 24DECLARE 25 topology_info RECORD; 26 layer_info RECORD; 27 child_layer_info RECORD; 28 geom geometry; 29 sql TEXT; 30BEGIN 31 32 -- Get topology information 33 SELECT id, name FROM topology.topology 34 INTO topology_info 35 WHERE id = tg.topology_id; 36 IF NOT FOUND THEN 37 RAISE EXCEPTION 'No topology with id "%" in topology.topology', tg.topology_id; 38 END IF; 39 40 -- Get layer info 41 SELECT * FROM topology.layer 42 WHERE topology_id = tg.topology_id 43 AND layer_id = tg.layer_id 44 INTO layer_info; 45 IF NOT FOUND THEN 46 RAISE EXCEPTION 'Could not find TopoGeometry layer % in topology %', tg.layer_id, tg.topology_id; 47 END IF; 48 49 -- 50 -- If this feature layer is on any level > 0 we will 51 -- compute the topological union of all simplified child 52 -- features in fact recursing. 53 -- 54 IF layer_info.level > 0 THEN -- { 55 56 -- Get child layer info 57 SELECT * FROM topology.layer WHERE layer_id = layer_info.child_id 58 AND topology_id = tg.topology_id 59 INTO child_layer_info; 60 IF NOT FOUND THEN 61 RAISE EXCEPTION 'Invalid layer % in topology % (unexistent child layer %)', tg.layer_id, tg.topology_id, layer_info.child_id; 62 END IF; 63 64 sql := 'SELECT st_multi(st_union(topology.ST_Simplify(' 65 || quote_ident(child_layer_info.feature_column) 66 || ',' || tolerance || '))) as geom FROM ' 67 || quote_ident(child_layer_info.schema_name) || '.' 68 || quote_ident(child_layer_info.table_name) 69 || ', ' || quote_ident(topology_info.name) || '.relation pr' 70 || ' WHERE ' 71 || ' pr.topogeo_id = ' || tg.id 72 || ' AND ' 73 || ' pr.layer_id = ' || tg.layer_id 74 || ' AND ' 75 || ' id('||quote_ident(child_layer_info.feature_column) 76 || ') = pr.element_id ' 77 || ' AND ' 78 || 'layer_id('||quote_ident(child_layer_info.feature_column) 79 || ') = pr.element_type '; 80 RAISE DEBUG '%', sql; 81 EXECUTE sql INTO geom; 82 83 ELSIF tg.type = 3 THEN -- [multi]polygon -- }{ 84 85 -- TODO: use ST_GetFaceEdges 86 -- TODO: is st_unaryunion needed? 87 sql := 'SELECT st_multi(st_unaryunion(ST_BuildArea(ST_Node(ST_Collect(ST_Simplify(geom, ' 88 || tolerance || ')))))) as geom FROM ' 89 || quote_ident(topology_info.name) 90 || '.edge_data e, ' 91 || quote_ident(topology_info.name) 92 || '.relation r WHERE ( e.left_face = r.element_id' 93 || ' OR e.right_face = r.element_id )' 94 || ' AND r.topogeo_id = ' || tg.id 95 || ' AND r.layer_id = ' || tg.layer_id 96 || ' AND element_type = 3 '; 97 RAISE DEBUG '%', sql; 98 EXECUTE sql INTO geom; 99 100 ELSIF tg.type = 2 THEN -- [multi]line -- }{ 101 102 sql := 103 'SELECT st_multi(ST_LineMerge(ST_Node(ST_Collect(ST_Simplify(e.geom,' 104 || tolerance || '))))) as g FROM ' 105 || quote_ident(topology_info.name) || '.edge e, ' 106 || quote_ident(topology_info.name) || '.relation r ' 107 || ' WHERE r.topogeo_id = ' || tg.id 108 || ' AND r.layer_id = ' || tg.layer_id 109 || ' AND r.element_type = 2 ' 110 || ' AND abs(r.element_id) = e.edge_id'; 111 EXECUTE sql INTO geom; 112 113 ELSIF tg.type = 1 THEN -- [multi]point -- }{ 114 115 -- Can't simplify points... 116 geom := topology.Geometry(tg); 117 118 ELSIF tg.type = 4 THEN -- mixed collection -- }{ 119 120 sql := 'WITH areas AS ( ' 121 || 'SELECT st_multi(st_union(ST_BuildArea(ST_Node(ST_Collect(ST_Simplify(geom, ' 122 || tolerance || ')))) as geom FROM ' 123 || quote_ident(topology_info.name) 124 || '.edge_data e, ' 125 || quote_ident(topology_info.name) 126 || '.relation r WHERE ( e.left_face = r.element_id' 127 || ' OR e.right_face = r.element_id )' 128 || ' AND r.topogeo_id = ' || tg.id 129 || ' AND r.layer_id = ' || tg.layer_id 130 || ' AND element_type = 3 ), ' 131 || 'lines AS ( ' 132 || 'SELECT st_multi(ST_LineMerge(ST_Collect(ST_Simplify(e.geom,' 133 || tolerance || ')))) as g FROM ' 134 || quote_ident(topology_info.name) || '.edge e, ' 135 || quote_ident(topology_info.name) || '.relation r ' 136 || ' WHERE r.topogeo_id = ' || tg.id 137 || ' AND r.layer_id = ' || tg.layer_id 138 || ' AND r.element_type = 2 ' 139 || ' AND abs(r.element_id) = e.edge_id ), ' 140 || ' points as ( SELECT st_union(n.geom) as g FROM ' 141 || quote_ident(topology_info.name) || '.node n, ' 142 || quote_ident(topology_info.name) || '.relation r ' 143 || ' WHERE r.topogeo_id = ' || tg.id 144 || ' AND r.layer_id = ' || tg.layer_id 145 || ' AND r.element_type = 1 ' 146 || ' AND r.element_id = n.node_id ), ' 147 || ' un as ( SELECT g FROM areas UNION ALL SELECT g FROM lines ' 148 || ' UNION ALL SELECT g FROM points ) ' 149 || 'SELECT ST_Multi(ST_Collect(g)) FROM un'; 150 EXECUTE sql INTO geom; 151 152 ELSE -- }{ 153 154 RAISE EXCEPTION 'Invalid TopoGeometries (unknown type %)', tg.type; 155 156 END IF; -- } 157 158 RETURN geom; 159 160END 161$$ 162LANGUAGE 'plpgsql' VOLATILE STRICT; 163-- } 164 165