-- Add some input variables -- Epsilon is the merge distance of two close points set @EPSILON = 1; -- River width is the minimal river width to take account for set @MINIMAL_RIVER_WIDTH = 4; -- Centrality is a network importance coefficient filtering between 0 and 1. set @RATIO_CENTRALITY = 0.8; -- Merge adjacent polygons, the simplify them and final densify their contours. Densification is done in order to create triangles where sides must fit into the width of the polygons. A theoretical density of 0m will create a valid skeleton of polygons. drop table if exists watersurf_accum; create table watersurf_accum as select ST_SIMPLIFYPRESERVETOPOLOGY(ST_BUFFER(ST_UNION(ST_ACCUM(the_geom)), 0),@EPSILON) the_geom from POLYGONS; -- Create voronoi edges drop table if exists water_voronoi; create table water_voronoi as select ST_VORONOI(ST_DELAUNAY(ST_UPDATEZ(ST_REMOVEREPEATEDPOINTS(ST_PRECISIONREDUCER(ST_TOMULTIPOINT(ST_DENSIFY(ST_ACCUM(THE_GEOM),@MINIMAL_RIVER_WIDTH / 2)),@EPSILON)),0)), 1) the_geom from watersurf; -- Explode the MultiLineStrings into multiple rows of LineString drop table if exists water_voronoi_edges; create table water_voronoi_edges as select * from st_explode('water_voronoi'); -- Create optimisation structure in order to speedup filtering SET @EXTENT = SELECT ST_EXTENT(THE_GEOM) THE_GEOM FROM watersurf_accum; SET @WIDTH = SELECT ST_XMAX(@EXTENT) - ST_XMIN(@EXTENT); SET @HEIGHT = SELECT ST_YMAX(@EXTENT) - ST_YMIN(@EXTENT); SET @CELL_SIZE = GREATEST(@WIDTH / 30, @HEIGHT/30); drop table if exists GRIDED_POLYGON; CREATE TABLE GRIDED_POLYGON AS SELECT ST_INTERSECTION(G.THE_GEOM, P.THE_GEOM) THE_GEOM FROM WATERSURF_ACCUM P, ST_MAKEGRID(@EXTENT,@CELL_SIZE, @CELL_SIZE) G WHERE ST_INTERSECTS(G.THE_GEOM, P.THE_GEOM); create spatial index on GRIDED_POLYGON(THE_GEOM); -- Keep only the voronoi edges that are inside the polygons drop table if exists water_skel; create table water_skel(THE_GEOM GEOMETRY) as select V.THE_GEOM THE_GEOM FROM water_voronoi_edges V WHERE ST_CONTAINS((SELECT ST_UNION(ST_ACCUM(W.THE_GEOM)) the_geom FROM GRIDED_POLYGON W WHERE v.the_geom && w.the_geom), v.the_geom); -- Union and simplify skeleton drop table if exists water_skel_simple_accum; create table water_skel_simple_accum as select ST_LINEMERGE(ST_ACCUM(THE_GEOM)) THE_GEOM FROM water_skel; drop table if exists water_skel_simple; create table water_skel_simple(PK SERIAL PRIMARY KEY, THE_GEOM GEOMETRY) as select null, the_geom from ST_EXPLODE('water_skel_simple_accum'); drop table if exists water_skel_simple_accum; drop table if exists graph_waternetwork; drop table if exists WATER_SKEL_SIMPLE_EDGES, WATER_SKEL_SIMPLE_NODES; call ST_GRAPH('WATER_SKEL_SIMPLE'); drop table if exists EDGES_WEIGHT; create table edges_weight as select E.*, ST_LENGTH(THE_GEOM) weight FROM WATER_SKEL_SIMPLE_EDGES E, WATER_SKEL_SIMPLE W WHERE W.PK = E.EDGE_ID ; -- This call is time and memory consuming drop table if exists EDGES_WEIGHT_EDGE_CENT,EDGES_WEIGHT_NODE_CENT; call ST_GraphAnalysis('EDGES_WEIGHT', 'undirected', 'weight'); drop table if exists central_skel; create table central_skel as select the_geom, LEAST(ENDNODE.BETWEENNESS, STARTNODE.BETWEENNESS) BETWEENNESS from EDGES_WEIGHT_NODE_CENT ENDNODE,EDGES_WEIGHT_NODE_CENT STARTNODE,WATER_SKEL_SIMPLE_EDGES E, WATER_SKEL_SIMPLE W WHERE E.START_NODE = STARTNODE.NODE_ID AND E.END_NODE = ENDNODE.NODE_ID AND W.PK = E.EDGE_ID AND LEAST(ENDNODE.BETWEENNESS, STARTNODE.BETWEENNESS) > @RATIO_CENTRALITY;