Upload
others
View
74
Download
0
Embed Size (px)
Citation preview
PGRouting for dummiesJulien-Samuel Lacroix
Mapgears@juliensam
PGRouting
➔ Installation➔ Configuration➔ Querying➔ Integration
Quick Installation
http://pgrouting.org/download.html
Available for:➔ Linux➔ Mac➔ Windows
As simple as:$ sudo aptget install postgresql9.1pgrouting
Prepare the Database
Load PostGIS:createdb routing
psql -f postgis.sql routing
psql -f spatial_ref_sys.sql routing
psql -f legacy.sql routing
Load PGRouting:psql -f routing_core.sql routing
psql -f routing_topology.sql routing
psql -f routing_core_wrappers.sql routing
Load the data
Load the data normally in PostGIS
shp2pgsql your_shp_file.shp > psql routing
The network segments need to be linked together at intersection.
Connecting network
Route the data
PGRouting:
- node -> node
- segment -> segment
ALTER TABLE ways ADD COLUMN "source" integer;
ALTER TABLE ways ADD COLUMN "target" integer;
SELECT assign_vertex_id('ways', 1, 'the_geom', 'gid');
CREATE INDEX source_idx ON ways("source");
CREATE INDEX target_idx ON ways("target");
Source and target
Route on what?
Define the cost of each segment in the network.
It can be anything or a combinaison of things:
➔ Length➔ Road type➔ Topology➔ Speed limit➔ Toll➔ etc...
$$$ Cost $$$-- Add cost column
ALTER TABLE ways ADD COLUMN length double precision;
UPDATE ways SET length = ST_LENGTH(the_geom);
-- Make the cost column different depending on road type
UPDATE
ways
SET length =
CASE
WHEN class='motorways' THEN
ST_LENGTH(the_geom)/4
WHEN class='railways' THEN
99999999
ELSE
ST_LENGTH(the_geom)
END;
The OSM case
● OSM data needs to to be splitted at intersection
● osm2pgrouting split and give you most of the information for basic routing
osm2pgrouting \
-file nottinghamshire-latest.osm \
-dbname routing \
-clean \
-user jlacroix \
-passwd ttt123 \
-conf ./osm2pgrouting-master/mapconfig.xml
Choose your algorithm
Dijkstra
More precise
shortest_path()
A*
Faster
shortest_path_astar()
Others available in 2.0
Query the data
SELECT *
FROM
shortest_path(
'SELECT
gid as id,
source::integer,
target::integer,
length::double precision as cost
FROM ways',
37725,
37720,
false,
false);
Visualize the result
seq | node | edge | cost
-----+------+------+---------------------
0 | 30 | 53 | 0.0591267653820616
1 | 44 | 52 | 0.0665408320949312
2 | 14 | 15 | 0.0809556879332114
...
6 | 10 | 6869 | 0.0164274192597773
7 | 59 | 72 | 0.0109385169537801
8 | 60 | -1 | 0
(9 rows)
Visualize the result
SELECT
*
FROM
shortest_path(
'SELECT
gid as id,
source::integer,
target::integer,
length::double precision as cost
FROM
Ways',
37725, 37720, false, false) as route,
ways
WHERE
ways.gid=route.edge_id;
Visualize the result
seq | geom | edge | cost | name
-----+------+------+---------------------+------
0 | ... | 53 | 0.0591267653820616 | ...
1 | ... | 52 | 0.0665408320949312 | ...
2 | ... | 15 | 0.0809556879332114 | ...
...
6 | ... | 6869 | 0.0164274192597773 | ...
7 | ... | 72 | 0.0109385169537801 | ...
8 | ... | -1 | 0 | ...
(9 rows)
Visualize the result
MapServer:DATA “geom FROM (SELECT * FROM shortest_path(...) as ... )”
Be smart
From lat/lon to lat/lon
Load the smart file:psql -f routing_core_smart.sql routing
select add_network_info('ways');
Get it from:https://github.com/pgRouting/pgrouting-contrib/blob/master/functions-v1.x/routing_core_smart.sql
Query the data (again)
SELECT *
FROM
sp_smart_directed(
'ways',
true,
-131675, 6976548,
-131475, 6976431,
10000,
'length',
'length',
false,
false) JOIN ...;
Visualize the result
With Openlayers:
One-way
SELECT *
FROM
sp_smart_directed(
'ways',
true,
-131675, 6976548,
-131475, 6976431,
10000,
'cost_column',
'reverse_cost_column',
true,
true) JOIN ...;
It's also possible to get left-turn based cost
Get the tools
➔ OpenLayers➔ GeoExt➔ Server-side routing service
Get a map up and running
// create the map panel
var panel = new GeoExt.MapPanel({
renderTo: "gxmap",
map: {
Layers: [
new OpenLayers.Layer.WMS("My route WMS",...)
]},
center: [-112000, 7000000],
zoom: 8,
height: 400,
width: 600,
title: "A Simple GeoExt Map"
});
var map = panel.map;
Add the route layers
// create the layer where the route will be drawn
var route_layer = new OpenLayers.Layer.Vector("route");
//create the layer where the start and final points will be drawn
var points_layer = new OpenLayers.Layer.Vector("points");
// add the layers to the map
map.addLayers([points_layer, route_layer]);
Add the routing tools
// when a new point is added to the layer,
// call the pgrouting function
points_layer.events.on({
featureadded: function() {
pgrouting(store, points_layer, '');
}
});
// create the control to draw the points
// (see the DrawPoints.js file)
var draw_points = new DrawPoints(points_layer);
Add the routing tools
// create the control to move the points
var drag_points = new OpenLayers.Control.DragFeature(
points_layer, {autoActivate: true});
// when a point is moved, call the pgrouting function
drag_points.onComplete = function() {
pgrouting(store, points_layer, '');
};
// add the controls to the map
map.addControls([draw_points, drag_points]);
The routing functionfunction pgrouting(store, layer, method) {
if (layer.features.length == 2) {
store.removeAll(); // erase the previous route
// transform the two geometries from EPSG:900913 to EPSG:4326
var startpoint = layer.features[0].geometry.clone();
startpoint.transform(epsg_900913, epsg_4326);
finalpoint = ...;
// load to route
store.load({
params: {
startpoint: startpoint.x + " " + startpoint.y,
finalpoint: finalpoint.x + " " + finalpoint.y,
method: method
}});
...
The store
// create the store to query the web service
var store = new GeoExt.data.FeatureStore({
layer: route_layer,
fields: [
{name: "length"}
],
proxy: new GeoExt.data.ProtocolProxy({
protocol: new OpenLayers.Protocol.HTTP({
url: "route.php",
format: new OpenLayers.Format.GeoJSON({
internalProjection: epsg_900913,
externalProjection: epsg_4326
})
})
})
});
The server-side
// Build the query
$sql = "
SELECT
*, ST_AsGeoJSON(the_geom) as geojson, ST_Length(the_geom) as length
FROM
sp_smart_directed(
'".TABLE."',
true,
".$startPoint[0].",
".$startPoint[1].",
".$endPoint[0].",
".$endPoint[1].",
1000, 'cost', 'cost', false, false
);";
The server-side
// Execute the query
psql_query(...);
// Return routing result
header('Content-type: application/json',true);
echo json_encode($geojson);
Demo!
Get some style for the line
// create the layer where the route will be drawn
var route_layer = new OpenLayers.Layer.Vector("route", {
styleMap: new OpenLayers.StyleMap(new OpenLayers.Style({
strokeColor: "#ff3333",
strokeOpacity: 0.7,
strokeWidth: 3
}))
});
Get some style for the points
// create the layer where the start and final points will be drawn
var points_layer = new OpenLayers.Layer.Vector("points", {
styleMap: new OpenLayers.StyleMap(new OpenLayers.Style({
"fillColor": "${getColor}",
"strokeColor": "${getColor}",
"pointRadius": 7,
"fillOpacity": 0.5
}, {context: {
"getColor": function(feature) {
return (feature.layer.features[0] == feature) ?
'green' : 'red';
}
}}))
});
What’s next?
➔ PGRouting 2.0➔ API refactoring➔ Tests➔ Documentation➔ Examples➔ See the presentation a 2:30PM in this
same room
Questions?The code is available at:
http://dl.mapgears.com/pgrouting/foss4g2013/routing.tar.gz