| 1 |
pgRouting - Routing Functionalities on PostgreSQL |
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
INTRODUCTION |
|---|
| 5 |
|
|---|
| 6 |
This library contains following features: |
|---|
| 7 |
|
|---|
| 8 |
* Dijkstra algorithm - Shortest path algorithm, which named in honor |
|---|
| 9 |
of Prof. Dr. Edsger Wybe Dijkstra who has invented it |
|---|
| 10 |
* A-star (A*) algorithm - Shortest path algorithm using heuristical |
|---|
| 11 |
function |
|---|
| 12 |
* Driving distance - area person can cover in certain time from start |
|---|
| 13 |
point using road network |
|---|
| 14 |
* TSP - Travelling Salesman Problem solution with default mazimum of |
|---|
| 15 |
40 points |
|---|
| 16 |
* Shooting star (Shooting*) algorithm - Shortest path algorithm for |
|---|
| 17 |
real road networks with turn restrictions, traffic lights and one |
|---|
| 18 |
way streets. |
|---|
| 19 |
|
|---|
| 20 |
REQUIREMENT |
|---|
| 21 |
|
|---|
| 22 |
* C and C++ compilers |
|---|
| 23 |
* Postgresql 8.x |
|---|
| 24 |
* PostGIS 1.x |
|---|
| 25 |
* Proj 4.x |
|---|
| 26 |
* GEOS (Geometry Engine - Open Source) library 2.x |
|---|
| 27 |
See http://geos.refractions.net/ |
|---|
| 28 |
* The Boost Graph Library (BGL). |
|---|
| 29 |
Version >= 1.33 or previous having astar.hpp |
|---|
| 30 |
See http://www.boost.org/libs/graph/doc/index.html |
|---|
| 31 |
* The Genetic Algorithm Utility Library (GAUL). |
|---|
| 32 |
See http://gaul.sourceforge.net |
|---|
| 33 |
* Computational Geometry Algorithms Library (CGAL) version >= 3.2. |
|---|
| 34 |
See http://www.cgal.org/ |
|---|
| 35 |
|
|---|
| 36 |
INSTALLATION |
|---|
| 37 |
|
|---|
| 38 |
* Edit Makefile, and set the BOOST_PATH with the location of your |
|---|
| 39 |
boost library (if you are on Debian, just type |
|---|
| 40 |
"apt-get install libboost-graph-dev" and you don't need to modify anything) |
|---|
| 41 |
|
|---|
| 42 |
* Type "make install" |
|---|
| 43 |
|
|---|
| 44 |
* If you have BGL installed but the version is less than 1.33.0, |
|---|
| 45 |
just download the astar.hpp file from |
|---|
| 46 |
http://www.boost.org/boost/graph/astar_search.hpp and copy it to |
|---|
| 47 |
BOOST_PATH/graph directory. |
|---|
| 48 |
|
|---|
| 49 |
* If you have PostGIS installed, you can launch dijkstra_postgis.sql |
|---|
| 50 |
which will create PostGIS import and manipulation functions. |
|---|
| 51 |
|
|---|
| 52 |
* GAUL library should be compilled with --no-slang option. |
|---|
| 53 |
Otherwise make sure you have slang.h installed in /usr/include. |
|---|
| 54 |
For more details please refer to corresponding README or INSTALL file. |
|---|
| 55 |
|
|---|
| 56 |
* Use interactive mode to install CGAL library. To avoid conflicts you should |
|---|
| 57 |
exclude BOOST support from the installation (follow on-screen instructions). |
|---|
| 58 |
|
|---|
| 59 |
* Execute the sql file dijkstra.sql to install the functions in your database |
|---|
| 60 |
(you need the plpgsql language enabled on your database. |
|---|
| 61 |
Type "createlang plpgsql YOUR_DATABASE" if not) |
|---|
| 62 |
|
|---|
| 63 |
|
|---|
| 64 |
|
|---|
| 65 |
USAGE |
|---|
| 66 |
|
|---|
| 67 |
The core module is a function which computes a shortest path from a |
|---|
| 68 |
set of edges and vertices. The function expects data in a specific |
|---|
| 69 |
format in input. |
|---|
| 70 |
|
|---|
| 71 |
Some functions are provided for importing data from geometric tables, |
|---|
| 72 |
and for generating results as geometries. |
|---|
| 73 |
|
|---|
| 74 |
|
|---|
| 75 |
The shortest_path functions have the following signature: |
|---|
| 76 |
======================================================== |
|---|
| 77 |
|
|---|
| 78 |
CREATE OR REPLACE FUNCTION shortest_path(sql text, source_id integer, target_id integer, |
|---|
| 79 |
directed boolean, has_reverse_cost boolean) |
|---|
| 80 |
RETURNS SETOF path_result |
|---|
| 81 |
|
|---|
| 82 |
Where path_result is: |
|---|
| 83 |
|
|---|
| 84 |
CREATE TYPE path_result AS (vertex_id integer, edge_id integer, cost float8); |
|---|
| 85 |
|
|---|
| 86 |
arguments are: |
|---|
| 87 |
|
|---|
| 88 |
* sql: a SQL query, which should return a set of rows with the |
|---|
| 89 |
following columns: |
|---|
| 90 |
|
|---|
| 91 |
- id: an int4 identifier of the edge |
|---|
| 92 |
- source: an int4 identifier of the source vertex |
|---|
| 93 |
- target: an int4 identifier of the target vertex |
|---|
| 94 |
- cost: double precision value of the edge traversal cost. (a negative cost |
|---|
| 95 |
will prevent the edge from being inserted in the graph). |
|---|
| 96 |
- reverse_cost (optional): the cost for the reverse traversal of the |
|---|
| 97 |
edge. This is only used when the directed and has_reverse_cost |
|---|
| 98 |
parameters are true (see the above remark about negative costs). |
|---|
| 99 |
- directed: true if the graph is directed |
|---|
| 100 |
- has_reverse_cost: if true, the reverse_cost column of the SQL |
|---|
| 101 |
generated set of rows will be used for the cost of the traversal of |
|---|
| 102 |
the edge in the opposite direction. |
|---|
| 103 |
|
|---|
| 104 |
A* and Shooting* functions also need: |
|---|
| 105 |
- x1: double precision value of x coordinate for edge's start vertex |
|---|
| 106 |
- y1: double precision value of y coordinate for edge's start vertex |
|---|
| 107 |
- x2: double precision value of x coordinate for edge's end vertex |
|---|
| 108 |
- y2: double precision value of y coordinate for edge's end vertex |
|---|
| 109 |
|
|---|
| 110 |
Shooting* function also needs: |
|---|
| 111 |
- rule: a string with a comma separated list of edge ids which describes |
|---|
| 112 |
a rule for turning restriction (if you came along these edges, you can |
|---|
| 113 |
pass through the current one only with the cost stated in to_cost column) |
|---|
| 114 |
- to_cost: a cost of restricted passage (can be very high in a case of |
|---|
| 115 |
turn restriction or comparable with an edge cost in a case of traffic light) |
|---|
| 116 |
|
|---|
| 117 |
For example, |
|---|
| 118 |
|
|---|
| 119 |
gid | source | target | cost | x1 | y1 | x2 | y2 | to_cost | rule |
|---|
| 120 |
-----+--------+--------+------+----+----+----+----+---------+------ |
|---|
| 121 |
12 | 3 | 10 | 2 | 4 | 3 | 4 | 5 | 1000 | 14 |
|---|
| 122 |
|
|---|
| 123 |
means that the cost of going from edge 14 to edge 12 is 1000, |
|---|
| 124 |
|
|---|
| 125 |
and |
|---|
| 126 |
|
|---|
| 127 |
gid | source | target | cost | x1 | y1 | x2 | y2 | to_cost | rule |
|---|
| 128 |
-----+--------+--------+------+----+----+----+----+---------+------ |
|---|
| 129 |
12 | 3 | 10 | 2 | 4 | 3 | 4 | 5 | 1000 | 14, 4 |
|---|
| 130 |
|
|---|
| 131 |
means that the cost of going from edge 14 to edge 12 through edge 4 is 1000. |
|---|
| 132 |
|
|---|
| 133 |
|
|---|
| 134 |
The function returns a set of rows. There is one row for each crossed |
|---|
| 135 |
edge, and an additional one containing the terminal vertex. |
|---|
| 136 |
The columns of each row are: |
|---|
| 137 |
|
|---|
| 138 |
- vertex_id: the identifier of source vertex of each edge. There is one |
|---|
| 139 |
more row after the last edge, which contains the vertex identifier of |
|---|
| 140 |
the target path. |
|---|
| 141 |
- edge_id: the identifier of the edge crossed |
|---|
| 142 |
- cost: The cost associated to the current edge. It is 0 for the row |
|---|
| 143 |
after the last edge. Thus, the path total cost can be computated using |
|---|
| 144 |
a sum of all rows in the cost column. |
|---|
| 145 |
|
|---|
| 146 |
examples: |
|---|
| 147 |
|
|---|
| 148 |
SELECT * from shortest_path('SELECT source, id, target, cost FROM edges', |
|---|
| 149 |
3, 7, false, false); |
|---|
| 150 |
|
|---|
| 151 |
vertex_id | edge_id | cost |
|---|
| 152 |
-----------+---------+------ |
|---|
| 153 |
3 | 2 | 0 |
|---|
| 154 |
4 | 21 | 0 |
|---|
| 155 |
6 | 5 | 0 |
|---|
| 156 |
7 | -1 | 0 |
|---|
| 157 |
(4 rows) |
|---|
| 158 |
|
|---|
| 159 |
|
|---|
| 160 |
To search a path using the A* algorithm: |
|---|
| 161 |
|
|---|
| 162 |
SELECT * from shortest_path_astar('SELECT id, source, target, cost, |
|---|
| 163 |
x1, y1, x2, y2 FROM edges',3, 7, false, false); |
|---|
| 164 |
|
|---|
| 165 |
vertex_id | edge_id | cost |
|---|
| 166 |
-----------+---------+------------------------ |
|---|
| 167 |
3 | 2 | 0.000763954363701041 |
|---|
| 168 |
4 | 21 | 0.00150254971056274 |
|---|
| 169 |
6 | 5 | 0.000417442425988342 |
|---|
| 170 |
7 | -1 | 0 |
|---|
| 171 |
(4 rows) |
|---|
| 172 |
|
|---|
| 173 |
|
|---|
| 174 |
Shooting* algorithm calculates a path from edge to edge (not from vertex to |
|---|
| 175 |
vertex). Column vertex_id contains start vertex of an edge from column edge_id. |
|---|
| 176 |
|
|---|
| 177 |
To search a path using the Shooting* algorithm: |
|---|
| 178 |
|
|---|
| 179 |
SELECT * from shortest_path_shooting_star('SELECT id, source, target, cost, |
|---|
| 180 |
x1, y1, x2, y2, rule, to_cost FROM edges', 17, 9, true, false); |
|---|
| 181 |
|
|---|
| 182 |
vertex_id | edge_id | cost |
|---|
| 183 |
-----------+---------+------ |
|---|
| 184 |
16 | 17 | 1 |
|---|
| 185 |
15 | 16 | 1 |
|---|
| 186 |
2 | 5 | 1 |
|---|
| 187 |
3 | 4 | 1 |
|---|
| 188 |
20 | 12 | 2 |
|---|
| 189 |
10 | 9 | 2 |
|---|
| 190 |
(6 rows) |
|---|
| 191 |
|
|---|
| 192 |
|
|---|
| 193 |
The tsp function has the following signature: |
|---|
| 194 |
============================================ |
|---|
| 195 |
|
|---|
| 196 |
CREATE OR REPLACE FUNCTION tsp(sql text, ids varchar, source_id integer) |
|---|
| 197 |
RETURNS SETOF path_result |
|---|
| 198 |
|
|---|
| 199 |
arguments are: |
|---|
| 200 |
|
|---|
| 201 |
* sql: a SQL query, which should return a set of rows with the |
|---|
| 202 |
following columns: |
|---|
| 203 |
|
|---|
| 204 |
- source_id: an int4 identifier of the vertex |
|---|
| 205 |
- x: x coordinate of the vertex |
|---|
| 206 |
- y: y coordinate of the vertex |
|---|
| 207 |
|
|---|
| 208 |
* ids: text string containig int4 ids of vertices separated by commas |
|---|
| 209 |
* source_id: int 4 id of the start point |
|---|
| 210 |
|
|---|
| 211 |
The function returns a set of rows. There is one row for each crossed |
|---|
| 212 |
edge, and an additional one containing the terminal vertex. |
|---|
| 213 |
The columns of each row are: |
|---|
| 214 |
|
|---|
| 215 |
- vertex_id: the identifier of source vertex of each edge. There is one |
|---|
| 216 |
more row after the last edge, which contains the vertex identifier of |
|---|
| 217 |
the target path. |
|---|
| 218 |
- edge_id: unused, always 0 |
|---|
| 219 |
- cost: unused, always 0 |
|---|
| 220 |
|
|---|
| 221 |
examples: |
|---|
| 222 |
|
|---|
| 223 |
SELECT * from tsp('select distinct source as source_id, x1::double precision as x, |
|---|
| 224 |
y1::double precision as y from dourol where source in (83593,66059,10549,18842,13)', |
|---|
| 225 |
'83593,66059,10549,18842,13', 10549); |
|---|
| 226 |
|
|---|
| 227 |
vertex_id | edge_id | cost |
|---|
| 228 |
-----------+---------+------ |
|---|
| 229 |
10549 | 0 | 0 |
|---|
| 230 |
83593 | 0 | 0 |
|---|
| 231 |
66059 | 0 | 0 |
|---|
| 232 |
18842 | 0 | 0 |
|---|
| 233 |
13 | 0 | 0 |
|---|
| 234 |
(5 rows) |
|---|
| 235 |
|
|---|
| 236 |
Afterwards vertex_id column can be used for shortest path calculation. |
|---|
| 237 |
|
|---|
| 238 |
|
|---|
| 239 |
The driving_distance function has the following signature: |
|---|
| 240 |
========================================================= |
|---|
| 241 |
|
|---|
| 242 |
CREATE OR REPLACE FUNCTION driving_distance(sql text, source_id integer, distance float8) |
|---|
| 243 |
|
|---|
| 244 |
RETURNS SETOF path_result |
|---|
| 245 |
|
|---|
| 246 |
arguments are: |
|---|
| 247 |
|
|---|
| 248 |
* sql: a SQL query, which should return a set of rows with the |
|---|
| 249 |
following columns: |
|---|
| 250 |
|
|---|
| 251 |
- id: an int4 identifier of the edge |
|---|
| 252 |
- source: an int4 identifier of the source vertex |
|---|
| 253 |
- target: an int4 identifier of the target vertex |
|---|
| 254 |
- cost: an float8 value, of the edge traversal cost. (a negative cost |
|---|
| 255 |
will prevent the edge from being inserted in the graph). |
|---|
| 256 |
|
|---|
| 257 |
* source_id: int4 id of the start point |
|---|
| 258 |
* distance: float8 value of distance in degrees |
|---|
| 259 |
|
|---|
| 260 |
The function returns a set of rows. There is one row for each crossed |
|---|
| 261 |
edge, and an additional one containing the terminal vertex. |
|---|
| 262 |
The columns of each row are: |
|---|
| 263 |
|
|---|
| 264 |
- vertex_id: the identifier of source vertex of each edge. There is one |
|---|
| 265 |
more row after the last edge, which contains the vertex identifier of |
|---|
| 266 |
the target path. |
|---|
| 267 |
- edge_id: the identifier of the edge crossed |
|---|
| 268 |
- cost: The cost associated to the current edge. It is 0 for the row |
|---|
| 269 |
after the last edge. Thus, the path total cost can be computated using |
|---|
| 270 |
a sum of all rows in the cost column. |
|---|
| 271 |
|
|---|
| 272 |
examples: |
|---|
| 273 |
|
|---|
| 274 |
SELECT * from driving_distance('select gid as id,source,target, |
|---|
| 275 |
length::double precision as cost from dourol',10549,0.01); |
|---|
| 276 |
|
|---|
| 277 |
vertex_id | edge_id | cost |
|---|
| 278 |
-----------+---------+--------------- |
|---|
| 279 |
6190 | 120220 | 0.00967666852 |
|---|
| 280 |
6205 | 118671 | 0.00961557335 |
|---|
| 281 |
6225 | 119384 | 0.00965668162 |
|---|
| 282 |
6320 | 119378 | 0.00959826176 |
|---|
| 283 |
. |
|---|
| 284 |
. |
|---|
| 285 |
. |
|---|
| 286 |
15144 | 122612 | 0.00973386526 |
|---|
| 287 |
15285 | 120471 | 0.00912965866 |
|---|
| 288 |
15349 | 122085 | 0.00944814966 |
|---|
| 289 |
15417 | 120471 | 0.00942316736 |
|---|
| 290 |
15483 | 121629 | 0.00972957546 |
|---|
| 291 |
(293 rows) |
|---|
| 292 |
|
|---|
| 293 |
|
|---|
| 294 |
|
|---|
| 295 |
|
|---|
| 296 |
The power of SQL can be used for more complex cost computation: |
|---|
| 297 |
|
|---|
| 298 |
SELECT shortest_path('SELECT gid as id, node1_id as source, node2_id |
|---|
| 299 |
as target, coalesce(CASE WHEN gid IN |
|---|
| 300 |
(1956, 123) THEN 12 ELSE weights1.weight END, 99999) as cost |
|---|
| 301 |
FROM lines2 LEFT JOIN weights1 USING (gid)', 12, 78, false, false); |
|---|
| 302 |
|
|---|
| 303 |
|
|---|
| 304 |
|
|---|
| 305 |
|
|---|
| 306 |
GRAPH IMPORTATION |
|---|
| 307 |
|
|---|
| 308 |
The shortest_path function expects edges id and vertices id to be |
|---|
| 309 |
integer ranging from zero to the maximum number of edges or vertices |
|---|
| 310 |
(holes are allowed, but it will be less efficient). |
|---|
| 311 |
However, you may want to compute shortest path on a table which has |
|---|
| 312 |
vertex identifier stored as strings, like in the following example: |
|---|
| 313 |
|
|---|
| 314 |
SELECT * FROM graph1; |
|---|
| 315 |
|
|---|
| 316 |
gid | source_id | target_id | edge_id |
|---|
| 317 |
-----+-----------+-----------+--------- |
|---|
| 318 |
0 | A | B | |
|---|
| 319 |
1 | A | C | |
|---|
| 320 |
2 | D | A | |
|---|
| 321 |
3 | B | C | |
|---|
| 322 |
(4 rows) |
|---|
| 323 |
|
|---|
| 324 |
A function called "create_graph_tables" is available which will create |
|---|
| 325 |
two tables for edges and vertices. Example: |
|---|
| 326 |
|
|---|
| 327 |
SELECT create_graph_tables('graph1', 'varchar'); |
|---|
| 328 |
|
|---|
| 329 |
The first argument is the name of the table containing the graph, and |
|---|
| 330 |
the second is the type of the source and target vertex identifiers. |
|---|
| 331 |
|
|---|
| 332 |
It will create the following tables: |
|---|
| 333 |
|
|---|
| 334 |
SELECT * FROM graph1_edges; |
|---|
| 335 |
|
|---|
| 336 |
id | source | target | cost | reverse_cost |
|---|
| 337 |
----+--------+--------+------+-------------- |
|---|
| 338 |
1 | 1 | 2 | | |
|---|
| 339 |
2 | 1 | 3 | | |
|---|
| 340 |
3 | 4 | 1 | | |
|---|
| 341 |
4 | 2 | 3 | | |
|---|
| 342 |
(4 rows) |
|---|
| 343 |
|
|---|
| 344 |
And |
|---|
| 345 |
|
|---|
| 346 |
SELECT * FROM graph1_vertices; |
|---|
| 347 |
|
|---|
| 348 |
id | geom_id |
|---|
| 349 |
----+--------- |
|---|
| 350 |
1 | A |
|---|
| 351 |
2 | B |
|---|
| 352 |
3 | C |
|---|
| 353 |
4 | D |
|---|
| 354 |
(4 rows) |
|---|
| 355 |
|
|---|
| 356 |
|
|---|
| 357 |
Notice the function will also update the edge_id column of graph1: |
|---|
| 358 |
|
|---|
| 359 |
gid | source_id | target_id | edge_id |
|---|
| 360 |
-----+-----------+-----------+--------- |
|---|
| 361 |
0 | A | B | 1 |
|---|
| 362 |
1 | A | C | 2 |
|---|
| 363 |
2 | D | A | 3 |
|---|
| 364 |
3 | B | C | 4 |
|---|
| 365 |
(4 rows) |
|---|
| 366 |
|
|---|
| 367 |
|
|---|
| 368 |
Then, you can use the shortest_path function, as below: |
|---|
| 369 |
|
|---|
| 370 |
SELECT * FROM shortest_path('SELECT id, source, target, 1::float8 AS |
|---|
| 371 |
cost FROM graph1_edges', |
|---|
| 372 |
(SELECT id FROM graph1_vertices WHERE geom_id = 'A'), |
|---|
| 373 |
(SELECT id FROM graph1_vertices WHERE geom_id = 'C'), |
|---|
| 374 |
false, false); |
|---|
| 375 |
|
|---|
| 376 |
The initial table has to contain the following columns: |
|---|
| 377 |
|
|---|
| 378 |
- gid anyelement: a unique identifier for each edge in you graph |
|---|
| 379 |
- source_id anyelement: an identifier for the starting vertex of the line |
|---|
| 380 |
- target_id anyelement: an identifier for the target vertex of the line |
|---|
| 381 |
(if the graph is not directed, source or target has the same |
|---|
| 382 |
meaning) |
|---|
| 383 |
- edge_id integer: this column will be filled by the allocated edge |
|---|
| 384 |
identifier. All data there will be overwritten, and you need to create |
|---|
| 385 |
this column if it does not exists before. |
|---|
| 386 |
|
|---|
| 387 |
The function "drop_graph_tables" will simply delete the edges and |
|---|
| 388 |
vertices associated tables. Example: |
|---|
| 389 |
|
|---|
| 390 |
SELECT drop_graph_tables('graph1'); |
|---|
| 391 |
|
|---|
| 392 |
|
|---|
| 393 |
POSTGIS GEOMETRIES IMPORTATION |
|---|
| 394 |
|
|---|
| 395 |
Some pl/pgsql functions are available for working with geographical |
|---|
| 396 |
data from PostGis tables. |
|---|
| 397 |
|
|---|
| 398 |
The table containing the graph has to contain the columns described in |
|---|
| 399 |
the previous section, and an additional geometric column called |
|---|
| 400 |
"the_geom" of type MULTILINESTRING. Only the first line in the |
|---|
| 401 |
multiline geomety will be handled. This restriction is because the |
|---|
| 402 |
shp2pgsql tool provided with postgis creates MULTILINESTRING geometric |
|---|
| 403 |
tables for shapefiles containing a set of lines. The importation |
|---|
| 404 |
should however handle more that only the first line in the multi line |
|---|
| 405 |
geometry (see TODO). |
|---|
| 406 |
|
|---|
| 407 |
Here's an example of such a table: |
|---|
| 408 |
|
|---|
| 409 |
SELECT gid, source_id, target_id, astext(the_geom) FROM graph2 LIMIT 4; |
|---|
| 410 |
|
|---|
| 411 |
gid | source_id | target_id | astext |
|---|
| 412 |
-----+-----------+-----------+-------------------------------------------------------------------------------------------- |
|---|
| 413 |
0 | | | MULTILINESTRING((-0.357902298850575 51.2777105057471,-0.364822129560221 51.455488954023)) |
|---|
| 414 |
1 | | | MULTILINESTRING((-0.415775862068966 51.6386587816092,-0.478232130809596 51.5784636541729)) |
|---|
| 415 |
2 | | | MULTILINESTRING((-0.478232130809596 51.5784636541729,-0.382585141804099 51.5791468469515)) |
|---|
| 416 |
3 | | | MULTILINESTRING((-0.364822129560221 51.455488954023,-0.433824600199901 51.5244914246627)) |
|---|
| 417 |
(4 rows) |
|---|
| 418 |
|
|---|
| 419 |
|
|---|
| 420 |
If the graph table does not contain identifier values in the source_id |
|---|
| 421 |
and target_id columns, a function is able to generate such ids, by |
|---|
| 422 |
extracting the starting and ending points of the line, and generating |
|---|
| 423 |
an unique id, for all points that are in a given distance. Example: |
|---|
| 424 |
|
|---|
| 425 |
SELECT assign_vertex_id('graph2', 0.1); |
|---|
| 426 |
|
|---|
| 427 |
SELECT gid, source_id, target_id, astext(the_geom) FROM graph2 LIMIT 4; |
|---|
| 428 |
|
|---|
| 429 |
gid | source_id | target_id | astext |
|---|
| 430 |
-----+-----------+-----------+-------------------------------------------------------------------------------------------- |
|---|
| 431 |
0 | 1 | 2 | MULTILINESTRING((-0.357902298850575 51.2777105057471,-0.364822129560221 51.455488954023)) |
|---|
| 432 |
1 | 3 | 3 | MULTILINESTRING((-0.415775862068966 51.6386587816092,-0.478232130809596 51.5784636541729)) |
|---|
| 433 |
2 | 3 | 3 | MULTILINESTRING((-0.478232130809596 51.5784636541729,-0.382585141804099 51.5791468469515)) |
|---|
| 434 |
3 | 2 | 2 | MULTILINESTRING((-0.364822129560221 51.455488954023,-0.433824600199901 51.5244914246627)) |
|---|
| 435 |
|
|---|
| 436 |
|
|---|
| 437 |
Now that the source_id and target_id are filled, the function |
|---|
| 438 |
create_graph_tables() can be used to create the edges |
|---|
| 439 |
and vertices tables (see above for the detailed description of |
|---|
| 440 |
create_graph_tables): |
|---|
| 441 |
|
|---|
| 442 |
SELECT create_graph_tables('graph2', 'int4'); |
|---|
| 443 |
|
|---|
| 444 |
Here's the content of the edges table: |
|---|
| 445 |
|
|---|
| 446 |
SELECT * FROM graph2_edges LIMIT 3; |
|---|
| 447 |
|
|---|
| 448 |
id | source | target | cost | reverse_cost |
|---|
| 449 |
----+--------+--------+------+-------------- |
|---|
| 450 |
1 | 1 | 2 | | |
|---|
| 451 |
2 | 3 | 3 | | |
|---|
| 452 |
4 | 2 | 2 | | |
|---|
| 453 |
(3 rows) |
|---|
| 454 |
|
|---|
| 455 |
We can see that it contains NULL values for the cost column. |
|---|
| 456 |
|
|---|
| 457 |
The function update_cost_from_distance can update the cost column with |
|---|
| 458 |
the distance of the lines contained in the geometry table, attached to |
|---|
| 459 |
each edge: |
|---|
| 460 |
|
|---|
| 461 |
SELECT update_cost_from_distance('graph2'); |
|---|
| 462 |
|
|---|
| 463 |
The costs are now: |
|---|
| 464 |
|
|---|
| 465 |
SELECT * FROM graph2_edges LIMIT 3; |
|---|
| 466 |
|
|---|
| 467 |
id | source | target | cost | reverse_cost |
|---|
| 468 |
----+--------+--------+-------------------+-------------- |
|---|
| 469 |
1 | 1 | 2 | 0.230081516048264 | |
|---|
| 470 |
2 | 3 | 3 | 0.446760794328524 | |
|---|
| 471 |
4 | 2 | 2 | 0.174348470878483 | |
|---|
| 472 |
|
|---|
| 473 |
|
|---|
| 474 |
Now, all is set up correctly for using the shortest_path() on these |
|---|
| 475 |
data: |
|---|
| 476 |
|
|---|
| 477 |
SELECT * FROM shortest_path('SELECT id, source, target, cost FROM graph2_edges', |
|---|
| 478 |
1, 2, false, false); |
|---|
| 479 |
|
|---|
| 480 |
vertex_id | edge_id | cost |
|---|
| 481 |
-----------+---------+------ |
|---|
| 482 |
1 | 1 | 0 |
|---|
| 483 |
2 | -1 | 0 |
|---|
| 484 |
|
|---|
| 485 |
An additional function shortest_path_as_geometry() can be used to |
|---|
| 486 |
retrieve the result as a set of rows containing the geometry |
|---|
| 487 |
identifier and the geometry itself: |
|---|
| 488 |
|
|---|
| 489 |
SELECT gid, astext(the_geom) FROM shortest_path_as_geometry('graph2', 1, 2); |
|---|
| 490 |
|
|---|
| 491 |
gid | astext |
|---|
| 492 |
-----+-------------------------------------------------------------------------------------------- |
|---|
| 493 |
0 | MULTILINESTRING((-0.357902298850575 51.2777105057471,-0.364822129560221 51.455488954023)) |
|---|
| 494 |
22 | MULTILINESTRING((-0.417298850574714 51.3371070574713,-0.408546467391305 51.3885360617191)) |
|---|
| 495 |
(2 rows) |
|---|
| 496 |
|
|---|
| 497 |
|
|---|
| 498 |
MAPSERVER INTEGRATION |
|---|
| 499 |
|
|---|
| 500 |
The function shortest_path_as_geometry() can be used inside mapserver |
|---|
| 501 |
to draw shortest path directly, as in the following example: |
|---|
| 502 |
|
|---|
| 503 |
|
|---|
| 504 |
LAYER |
|---|
| 505 |
NAME "europe2" |
|---|
| 506 |
TYPE LINE |
|---|
| 507 |
|
|---|
| 508 |
STATUS DEFAULT |
|---|
| 509 |
CONNECTIONTYPE postgis |
|---|
| 510 |
CONNECTION "user=postgres host=localhost dbname=geo" |
|---|
| 511 |
DATA "the_geom from (SELECT the_geom, gid from |
|---|
| 512 |
shortest_path_as_geometry('bahnlinien_europa_polyline', 2629, 10171)) as |
|---|
| 513 |
foo using unique gid using srid=-1" |
|---|
| 514 |
|
|---|
| 515 |
TEMPLATE "t" |
|---|
| 516 |
CLASS |
|---|
| 517 |
NAME "0" |
|---|
| 518 |
STYLE |
|---|
| 519 |
SYMBOL "circle" |
|---|
| 520 |
SIZE 10 |
|---|
| 521 |
COLOR 50 50 100 |
|---|
| 522 |
END |
|---|
| 523 |
END |
|---|
| 524 |
END |
|---|
| 525 |
|
|---|
| 526 |
Notice however, that this function will be called at each map |
|---|
| 527 |
display, computing the shortest path every time. |
|---|
| 528 |
|
|---|
| 529 |
A better approach would be to generate the shortest path in a |
|---|
| 530 |
temporary table. |
|---|
| 531 |
|
|---|
| 532 |
|
|---|
| 533 |
LIMITATION / TODO |
|---|
| 534 |
|
|---|
| 535 |
Usage of the Boost graph library can certainly be optimised. Help from |
|---|
| 536 |
Boost/STL experts is welcomed. |
|---|
| 537 |
|
|---|
| 538 |
Might not work on very large datasets due to memory |
|---|
| 539 |
requirements. (Tested with sucess on a 8 million edges table). |
|---|
| 540 |
|
|---|
| 541 |
LICENCE |
|---|
| 542 |
|
|---|
| 543 |
Most features are available under GPL. |
|---|
| 544 |
Some Boost extesions are available under Boost license (see LICENSE_1_0.txt) |
|---|
| 545 |
|
|---|
| 546 |
AUTHORS |
|---|
| 547 |
|
|---|
| 548 |
Anton A. Patrushev <anton@orkney.co.jp> |
|---|
| 549 |
Mario H. Basa <mbasa@orkney.co.jp> |
|---|
| 550 |
|
|---|
| 551 |
Dijkstra part was made by |
|---|
| 552 |
Sylvain Pasche <sylvain.pasche@camptocamp.com> |
|---|