pgRouting

Ticket #87: routing_core.sql

File routing_core.sql, 11.0 kB (added by rodj59, 1 year 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
21 CREATE TYPE path_result AS (vertex_id integer, edge_id integer, cost float8);
22 CREATE TYPE vertex_result AS (x float8, y float8);
23
24 -----------------------------------------------------------------------
25 -- Core function for shortest_path computation
26 -- See README for description
27 -----------------------------------------------------------------------
28 CREATE 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 -----------------------------------------------------------------------
39 CREATE 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 -----------------------------------------------------------------------
49 CREATE 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 -----------------------------------------------------------------------
61 CREATE OR REPLACE FUNCTION insert_vertex(vertices_table varchar,
62        geom_id int)
63        RETURNS int AS
64 $$
65 DECLARE
66         vertex_id int;
67         myrec record;
68 BEGIN
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;
81 END;
82 $$
83 LANGUAGE 'plpgsql' VOLATILE STRICT;
84
85
86 -----------------------------------------------------------------------
87 -- Create the vertices and edges tables from a table matching the
88 --  geometry schema described above.
89 -----------------------------------------------------------------------
90 CREATE OR REPLACE FUNCTION create_graph_tables(geom_table varchar)
91        RETURNS void AS
92 $$
93 BEGIN
94                 EXECUTE 'SELECT create_graph_tables('''||quote_ident(geom_table)||''',''int4'',' || '''gid'' ,''source_id'',''target_id'')';
95 END;
96 $$
97 LANGUAGE 'plpgsql' VOLATILE STRICT;
98
99 CREATE OR REPLACE FUNCTION create_graph_tables(geom_table varchar,
100        column_type varchar )
101        RETURNS void AS
102 $$
103 BEGIN
104                 EXECUTE 'SELECT create_graph_tables('''||quote_ident(geom_table)||''','''||quote_ident(column_type)||''',' || '''gid'' ,''source_id'',''target_id'')';
105 END;
106 $$
107 LANGUAGE 'plpgsql' VOLATILE STRICT;
108
109 CREATE OR REPLACE FUNCTION create_graph_tables(geom_table varchar,
110        column_type varchar , id_name varchar)
111        RETURNS void AS
112 $$
113 BEGIN
114                 EXECUTE 'SELECT create_graph_tables('''||quote_literal(geom_table)||''','''||quote_literal(column_type)||''',''' || quote_literal(id_name) || ''' ,''source_id'',''target_id'')';
115         RETURN;
116 END;
117 $$
118 LANGUAGE 'plpgsql' VOLATILE STRICT;
119
120
121
122
123 CREATE 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 $$
127 DECLARE
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';
135 BEGIN
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;
199 END;
200 $$
201 LANGUAGE '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 -----------------------------------------------------------------------
208 CREATE OR REPLACE FUNCTION shortest_path_as_geometry_internal_id(
209        geom_table varchar, source int4, target int4)
210        RETURNS SETOF GEOMS AS
211 $$
212 DECLARE
213         r record;
214         path_result record;
215         v_id integer;
216         e_id integer;
217         geom geoms;
218 BEGIN
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;
235 END;
236 $$
237 LANGUAGE 'plpgsql' VOLATILE STRICT;
238
239 CREATE 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 $$
243 DECLARE
244         r record;
245         path_result record;
246         v_id integer;
247         e_id integer;
248         geom geoms;
249         query text;
250 BEGIN
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;
273 END;
274 $$
275 LANGUAGE '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 -----------------------------------------------------------------------
281 CREATE OR REPLACE FUNCTION shortest_path_as_geometry(geom_table varchar,
282        geom_source anyelement,geom_target anyelement)
283        RETURNS SETOF GEOMS AS
284 $$
285 DECLARE
286         r record;
287         source int4;
288         target int4;
289         path_result record;
290         v_id integer;
291         e_id integer;
292         geom geoms;
293 BEGIN
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;
321 END;
322 $$
323 LANGUAGE 'plpgsql' VOLATILE STRICT;
324
325
326