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