Ticket #87: routing_core.sql

File routing_core.sql, 11.0 KB (added by rodj59, 3 years ago)
Line 
1--
2-- Copyright (c) 2005 Sylvain Pasche,
3--               2006-2007 Anton A. Patrushev, Orkney, Inc.
4--
5-- This program is free software; you can redistribute it and/or modify
6-- it under the terms of the GNU General Public License as published by
7-- the Free Software Foundation; either version 2 of the License, or
8-- (at your option) any later version.
9--
10-- This program is distributed in the hope that it will be useful,
11-- but WITHOUT ANY WARRANTY; without even the implied warranty of
12-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13-- GNU General Public License for more details.
14--
15-- You should have received a copy of the GNU General Public License
16-- along with this program; if not, write to the Free Software
17-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18--
19
20
21CREATE TYPE path_result AS (vertex_id integer, edge_id integer, cost float8);
22CREATE TYPE vertex_result AS (x float8, y float8);
23
24-----------------------------------------------------------------------
25-- Core function for shortest_path computation
26-- See README for description
27-----------------------------------------------------------------------
28CREATE OR REPLACE FUNCTION shortest_path(sql text, source_id integer,
29        target_id integer, directed boolean, has_reverse_cost boolean)
30        RETURNS SETOF path_result
31        AS '$libdir/librouting'
32        LANGUAGE 'C' IMMUTABLE STRICT;
33
34-----------------------------------------------------------------------
35-- Core function for shortest_path_astar computation
36-- Simillar to shortest_path in usage but uses the A* algorithm
37-- instead of Dijkstra's.
38-----------------------------------------------------------------------
39CREATE OR REPLACE FUNCTION shortest_path_astar(sql text, source_id integer,
40        target_id integer,directed boolean, has_reverse_cost boolean)
41         RETURNS SETOF path_result
42         AS '$libdir/librouting'
43         LANGUAGE 'C' IMMUTABLE STRICT;
44
45-----------------------------------------------------------------------
46-- Core function for shortest_path_astar computation
47-- Simillar to shortest_path in usage but uses the Shooting* algorithm
48-----------------------------------------------------------------------
49CREATE OR REPLACE FUNCTION shortest_path_shooting_star(sql text, source_id integer,
50        target_id integer,directed boolean, has_reverse_cost boolean)
51         RETURNS SETOF path_result
52         AS '$libdir/librouting'
53         LANGUAGE 'C' IMMUTABLE STRICT;
54
55-----------------------------------------------------------------------
56-- This function should not be used directly. Use create_graph_tables instead
57--
58-- Insert a vertex into the vertices table if not already there, and
59--  return the id of the newly inserted or already existing element
60-----------------------------------------------------------------------
61CREATE OR REPLACE FUNCTION insert_vertex(vertices_table varchar,
62       geom_id int)
63       RETURNS int AS
64$$
65DECLARE
66        vertex_id int;
67        myrec record;
68BEGIN
69        LOOP
70          FOR myrec IN EXECUTE 'SELECT id FROM ' ||
71                     quote_ident(vertices_table) ||
72                     ' WHERE geom_id = ' || quote_literal(geom_id)  LOOP
73
74                        IF myrec.id IS NOT NULL THEN
75                                RETURN myrec.id;
76                        END IF;
77          END LOOP;
78          EXECUTE 'INSERT INTO ' || quote_ident(vertices_table) ||
79                  ' (geom_id) VALUES (' || quote_literal(geom_id) || ')';
80        END LOOP;
81END;
82$$
83LANGUAGE 'plpgsql' VOLATILE STRICT;
84
85
86-----------------------------------------------------------------------
87-- Create the vertices and edges tables from a table matching the
88--  geometry schema described above.
89-----------------------------------------------------------------------
90CREATE OR REPLACE FUNCTION create_graph_tables(geom_table varchar)
91       RETURNS void AS
92$$
93BEGIN
94                EXECUTE 'SELECT create_graph_tables('''||quote_ident(geom_table)||''',''int4'',' || '''gid'' ,''source_id'',''target_id'')';
95END;
96$$
97LANGUAGE 'plpgsql' VOLATILE STRICT;
98
99CREATE OR REPLACE FUNCTION create_graph_tables(geom_table varchar,
100       column_type varchar )
101       RETURNS void AS
102$$
103BEGIN
104                EXECUTE 'SELECT create_graph_tables('''||quote_ident(geom_table)||''','''||quote_ident(column_type)||''',' || '''gid'' ,''source_id'',''target_id'')';
105END;
106$$
107LANGUAGE 'plpgsql' VOLATILE STRICT;
108
109CREATE OR REPLACE FUNCTION create_graph_tables(geom_table varchar,
110       column_type varchar , id_name varchar)
111       RETURNS void AS
112$$
113BEGIN
114                EXECUTE 'SELECT create_graph_tables('''||quote_literal(geom_table)||''','''||quote_literal(column_type)||''',''' || quote_literal(id_name) || ''' ,''source_id'',''target_id'')';
115        RETURN;
116END;
117$$
118LANGUAGE 'plpgsql' VOLATILE STRICT;
119
120
121
122
123CREATE OR REPLACE FUNCTION create_graph_tables(geom_table varchar,
124       column_type varchar, id_name varchar,source_name varchar,target_name varchar)
125       RETURNS void AS
126$$
127DECLARE
128        geom record;
129        edge_id int;
130        myrec record;
131        source_id int;
132        target_id int;
133        vertices_table varchar := quote_ident(geom_table) || '_vertices';
134        edges_table varchar := quote_ident(geom_table) || '_edges';
135BEGIN
136
137        EXECUTE 'CREATE TABLE ' || vertices_table ||
138                ' (id serial, geom_id ' || quote_ident(column_type) ||
139                '  NOT NULL UNIQUE)';
140
141        EXECUTE 'CREATE INDEX ' || vertices_table || '_id_idx on ' ||
142                vertices_table || ' (id)';
143
144        EXECUTE 'CREATE TABLE ' || edges_table ||
145                ' (id serial, source int, target int, ' ||
146                'cost float8, reverse_cost float8, UNIQUE (source, target))';
147
148        EXECUTE 'CREATE INDEX ' || edges_table ||
149                '_source_target_idx on ' || edges_table ||
150                ' (source, target)';
151
152                BEGIN
153                        EXECUTE 'ALTER TABLE ' || quote_ident(geom_table) ||' ADD COLUMN edge_id int4';
154                EXCEPTION
155                        WHEN DUPLICATE_COLUMN THEN
156                END;
157
158
159        FOR geom IN EXECUTE 'SELECT '|| quote_ident(id_name) ||' as id, ' ||
160                                quote_ident(source_name) ||
161             ' AS source, ' ||
162                                quote_ident(target_name) ||
163             ' AS target FROM ' || quote_ident(geom_table) LOOP
164
165                SELECT INTO source_id insert_vertex(vertices_table,
166                                                    geom.source);
167
168                SELECT INTO target_id insert_vertex(vertices_table,
169                                                    geom.target);
170
171                BEGIN
172                    EXECUTE 'INSERT INTO ' || edges_table ||
173                            ' (source, target) VALUES ('  ||
174                            quote_literal(source_id) || ', ' ||
175                            quote_literal(target_id) || ')';
176
177                EXCEPTION
178                        WHEN UNIQUE_VIOLATION THEN
179                END;
180
181                FOR myrec IN EXECUTE 'SELECT id FROM ' || edges_table ||
182                    ' e WHERE ' || ' e.source = ' ||
183                    quote_literal(source_id) ||
184                    ' and e.target = ' ||
185                    quote_literal(target_id) LOOP
186                END LOOP;
187
188                edge_id := myrec.id;
189
190                IF edge_id IS NULL OR edge_id < 0 THEN
191                        RAISE EXCEPTION 'Bad edge id';
192                END IF;
193
194                EXECUTE 'UPDATE ' || quote_ident(geom_table) ||
195                        ' SET edge_id = ' || edge_id ||
196                        ' WHERE ' || quote_ident(id_name) || ' =  ' || geom.id;
197        END LOOP;
198        RETURN;
199END;
200$$
201LANGUAGE 'plpgsql' VOLATILE STRICT;
202
203-----------------------------------------------------------------------
204-- Compute the shortest path using edges and vertices table, and return
205--  the result as a set of (gid integer, the_geom gemoetry) records.
206-- This function uses the internal vertices identifiers.
207-----------------------------------------------------------------------
208CREATE OR REPLACE FUNCTION shortest_path_as_geometry_internal_id(
209       geom_table varchar, source int4, target int4)
210       RETURNS SETOF GEOMS AS
211$$
212DECLARE
213        r record;
214        path_result record;
215        v_id integer;
216        e_id integer;
217        geom geoms;
218BEGIN
219       
220        FOR path_result IN EXECUTE 'SELECT gid,the_geom FROM ' ||
221          'shortest_path(''SELECT gid as id, source::integer, target::integer, ' ||
222          'length::double precision as cost FROM ' ||
223          quote_ident(geom_table) || ''', ' || quote_literal(source) ||
224          ' , ' || quote_literal(target) || ' , false, false), ' ||
225          quote_ident(geom_table) || ' where edge_id = gid '
226        LOOP
227
228                 geom.gid      := path_result.gid;
229                 geom.the_geom := path_result.the_geom;
230                 
231                 RETURN NEXT geom;
232
233        END LOOP;
234        RETURN;
235END;
236$$
237LANGUAGE 'plpgsql' VOLATILE STRICT;
238
239CREATE OR REPLACE FUNCTION shortest_path_as_geometry_internal_id_directed(
240       geom_table varchar, source int4, target int4, dir boolean, rc boolean)
241       RETURNS SETOF GEOMS AS
242$$
243DECLARE
244        r record;
245        path_result record;
246        v_id integer;
247        e_id integer;
248        geom geoms;
249        query text;
250BEGIN
251       
252        query := 'SELECT gid,the_geom FROM ' ||
253          'shortest_path(''SELECT gid as id, source::integer, target::integer, ' ||
254          'length::double precision as cost ';
255         
256        IF rc THEN query := query || ', reverse_cost '; 
257        END IF;
258       
259        query := query || 'FROM ' ||  quote_ident(geom_table) || ''', ' || quote_literal(source) ||
260          ' , ' || quote_literal(target) || ' , '''||dir||''', '''||rc||'''), ' ||
261          quote_ident(geom_table) || ' where edge_id = gid ';
262
263        FOR path_result IN EXECUTE query
264        LOOP
265
266                 geom.gid      := path_result.gid;
267                 geom.the_geom := path_result.the_geom;
268                 
269                 RETURN NEXT geom;
270
271        END LOOP;
272        RETURN;
273END;
274$$
275LANGUAGE 'plpgsql' VOLATILE STRICT;
276
277-----------------------------------------------------------------------
278-- Compute the shortest path using edges and vertices table, and return
279--  the result as a set of (gid integer, the_geom gemoetry) records.
280-----------------------------------------------------------------------
281CREATE OR REPLACE FUNCTION shortest_path_as_geometry(geom_table varchar,
282       geom_source anyelement,geom_target anyelement)
283       RETURNS SETOF GEOMS AS
284$$
285DECLARE
286        r record;
287        source int4;
288        target int4;
289        path_result record;
290        v_id integer;
291        e_id integer;
292        geom geoms;
293BEGIN
294        FOR r IN EXECUTE 'SELECT id FROM ' || quote_ident(geom_table) ||
295           '_vertices WHERE geom_id = ' || quote_literal(geom_source) LOOP
296
297                source = r.id;
298
299        END LOOP;
300
301        IF source IS NULL THEN
302                RAISE EXCEPTION 'Can''t find source edge';
303        END IF;
304
305        FOR r IN EXECUTE 'SELECT id FROM ' || quote_ident(geom_table) ||
306            '_vertices WHERE geom_id = ' || quote_literal(geom_target) LOOP
307                target = r.id;
308        END LOOP;
309
310        IF target IS NULL THEN
311                RAISE EXCEPTION 'Can''t find target edge';
312        END IF;
313       
314        FOR geom IN SELECT * FROM
315          shortest_path_as_geometry_internal_id(geom_table,
316                                                source, target) LOOP
317                RETURN NEXT geom;
318        END LOOP;
319
320        RETURN;
321END;
322$$
323LANGUAGE 'plpgsql' VOLATILE STRICT;
324
325
326