一 前言
PgRouting是基于開源空間數(shù)據(jù)庫PostGIS用于網(wǎng)絡分析的擴展模塊,最初它被稱作pgDijkstra,因為它只是利用Dijkstra算法實現(xiàn)最短路徑搜索,之后慢慢添加了其他的路徑分析算法,如A算法,雙向A算法,Dijkstra算法,雙向Dijkstra算法,tsp貨郎擔算法等,然后被更名為pgRouting[1]。該擴展庫依托PostGIS自身的gist索引,豐富的坐標系與圖形類型,強大的幾何處理能力,如空間查詢,空間處理,線性參考等優(yōu)勢,能保障在較大數(shù)據(jù)級別下的網(wǎng)絡分析效果更快更好。
PostGIS早已奠定了最優(yōu)秀的開源空間數(shù)據(jù)庫地位,在新時代GIS中的應用將會越來越普遍。其實,網(wǎng)絡分析算法很多服務端語言如java,C#等雖能實現(xiàn),但基于真實城市道路數(shù)據(jù)量較大且查詢分析操作步驟復雜與數(shù)據(jù)庫交互頻繁,以這類服務端頻繁訪問數(shù)據(jù)庫導致數(shù)據(jù)庫開銷壓力較大,分析較慢,故選擇PgRouting在數(shù)據(jù)庫內部實現(xiàn)算法,提升分析效率。最后,路徑分析不僅僅是最短路徑,在實際應用中還有最短耗時,最近距離,道路對車輛類型限制,道路對速度限制等因素,交通事故、市政事故導致的交通障礙點等問題,所有的問題本質其實是對路徑分析權重(Weight)的設置問題。
二 PgRounting安裝
windows安裝過程比較簡單,安裝PostgreSQL,PostGIS一直Next即可,安裝完自帶PgRouting擴展,這里主要以Centos7介紹安裝過程:
- 安裝PostgreSQL,參考 《Centos7安裝PostgreSQL》;
- 安裝PostGIS,PgRouting,具體安裝步驟參考《CentOS 7源碼安裝PostGIS(包含SFCGAL,PgRouting)》;
三 搭建網(wǎng)絡分析庫
3.1 創(chuàng)建測試數(shù)據(jù)庫
[root@localhost opt]# su - postgres
[postgres@localhost ~]$ psql
psql (9.6.1)
Type "help" for help.
postgres=# create database network;
CREATE DATABASE
postgres=# \c network
You are now connected to database "network" as user "postgres".
network=# create extension postgis;
CREATE EXTENSION
network=# create extension pgrouting;
CREATE EXTENSION
3.2 導入測試路網(wǎng)數(shù)據(jù)
PgRouting需要使用道路線型數(shù)據(jù),建立道路連通性topo關系。由于路網(wǎng)分析的特殊性,只支持LineString類型,不支持MultiLineString類型。測試數(shù)據(jù)從OSM下載得來。
一般下載shp,使用PostGIS自帶的shp2pgsql導入即可。其他格式可以使用osm2pgrouting工具,本文不做詳述。筆者下載后,將路網(wǎng)數(shù)據(jù)使用ArcMap只截取了南京市范圍內路網(wǎng)后,從epsg:4326轉換成了epsg:3857坐標系,然后導入數(shù)據(jù)庫,做測試數(shù)據(jù)。
[postgres@localhost ~]$ shp2pgsql -c -g geom -D -s 3857 -S -i -I /opt/roads.shp road | psql -d network
Shapefile type: Arc
Postgis type: LINESTRING[2]
SET
SET
BEGIN
CREATE TABLE
ALTER TABLE
addgeometrycolumn
----------------------------------------------------
public.road.geom SRID:3857 TYPE:LINESTRING DIMS:2
(1 row)
COPY 9731
CREATE INDEX
COMMIT
ANALYZE
關于shp2pgsql參數(shù)問題,參考http://www.lxweimin.com/p/1251fdc603ac。
注意:使用shp2pgsql工具,shp路徑不要太深,不要有中文。對于含有中文亂碼的,可使用-W gbk等轉碼。
3.3 創(chuàng)建網(wǎng)絡分析topo
PgRouting提供pgr_createTopology方法,對道路數(shù)據(jù)創(chuàng)建拓撲關系,比如單一線要素,建立與其連通的source,tartget連通點。詳細步驟如下:
#在network數(shù)據(jù)庫中對導入的road表建立source,target字段
network=# alter table road add column source int;
ALTER TABLE
network=# alter table road add column target int;
ALTER TABLE
#創(chuàng)建連通性topo
#road是表名稱,geom是該表的圖形字段名稱,gid是改變的主鍵id。
#一般我們使用shp2pgsql工具會自動創(chuàng)建gid為主鍵,geom為圖形。
#如果是自己其他形式建立的表,注意參數(shù)寫自己對應的字段
network=# SELECT pgr_createTopology('road', 0.00001, 'geom', 'gid');
正常情況下順利完成以上步驟。
由于在網(wǎng)絡分析中頻繁讀取source,target字段的topo關系值,為了提升查詢效率,需要對這兩個字段添加索引:
network=# create index road_source_idx on road("source");
network=# create index road_target_idx on road("target");
3.4 路網(wǎng)元數(shù)據(jù)說明
到此為止,全部數(shù)據(jù)準備工作已經完成了,查看本文用于測試路徑分析的數(shù)據(jù)描述如下:
network=# \d road
Table "public.road"
Column | Type | Modifiers
-----------+---------------------------+----------------------------------------------------
gid | integer | not null default nextval('road_gid_seq'::regclass)
direction | character varying(1) |
roadname | character varying(40) |
oneway | character varying(50) |
geom | geometry(LineString,3857) |
source | integer |
target | integer |
Indexes:
"road_pkey" PRIMARY KEY, btree (gid)
"road_geom_idx" gist (geom)
"road_source_idx" btree (source)
"road_target_idx" btree (target)
由此看出,road表擁有主鍵索引,geom的gist索引,source,target節(jié)點處索引,還有一般性的道路名稱字段,比較重要的是direction和oneway字段(有一個即可),這兩個字段都是說明道路真實方向的。
direction | oneway | 含義 |
---|---|---|
0,1 | 空值 | 道路雙向通行 |
2 | FT | 道路真實方向與數(shù)字化方向一致 |
3 | TF | 道路真實方向與數(shù)字化方向相反 |
4 | N | 道路禁止通行 |
3.5 通行成本權重設置
在算法中分為有向圖,無向圖,圖的path長度一般設置為權重,網(wǎng)絡分析中,具體到比如交通領域,也分為雙向通行道路,單向通行道路,交通事故導致的臨時交通阻塞無法通行(障礙點),不同等級道路對車輛類型限制,比如高架,高速只允許機動車,鄉(xiāng)間道路允許非機動車(條件限制因素),本節(jié)只是舉個例子說明下不同的條件下如何設置通行成本權重:
- 雙向通行:
update road set length=st_length(geom),rev_length=st_length(geom) where oneway is null;
--采用真實地理距離是這樣:
update road set lenght=st_length(st_transform(geom),4326),true),rev_length=st_length((st_transform(geom),4326),true) where oneway is null;
- 單向通行
#FT是道路方向與數(shù)字化方向一致,那么正向通行成本為道路長度,反向成本為正無窮(以極大值代替)
update road set length=st_length(geom),rev_length=99999999999 where oneway='FT';
update road set length=99999999999,rev_length=st_length(geom) where oneway='TF';
- 障礙點
#假設gid=20的道路因事故,修路暫時不能通行
update road set lenght=99999999999,rev_length=99999999999 where gid=20;
- 限制通行
假設當前是一輛大貨車,通過有限高限重的道路,在為他做規(guī)劃時,先獲取車輛類型,再查詢road表中是否有對其限制的因素(以下純邏輯描述sql)
#假設道路表有字段restrict,該字段是array,記錄了不可通行的車輛類型
update road set lenght=99999999999,rev_length=99999999999 where 'lorry'=any(restrict);
四 路徑分析
言歸正傳,本文從入門角度只闡述最簡單的單向,雙向通行道路的例子,其他概不設置限制。
4.1 創(chuàng)建cost
alter table road add column length numeric;
alter table road add column rev_length numeric;
update road set length=ST_Length(ST_TransForm(geom,4326),true),rev_length=ST_Length(ST_TransForm(geom,4326),true) where oneway is null;
update road set length=st_length(ST_TransForm(geom,4326),true),rev_length=99999999999 where oneway='FT';
update road set length=99999999999,rev_length=st_length(ST_TransForm(geom,4326),true) where oneway='TF';
4.2 創(chuàng)建路徑分析方法
- 單點到單點
建立好網(wǎng)絡topo的數(shù)據(jù)一定會有source,target字段,這是表達線的走向和連通性的關系,一條線的target,是與它尾部相連的其他線的source。
--忽視道路方向,每條路正反都可以通行
SELECT * FROM pgr_dijkstra(
'SELECT gid AS id,
source,
target,
cost
FROM roads',
1060, 1661,
directed := false);
--遵循道路真實方向,有的道路是單行道,如高速的一側,有的路是正反都可以通行,他們由cost,revcost決定的
SELECT * FROM pgr_dijkstra(
'SELECT gid AS id,
source,
target,
cost,rev_cost as reverse_cost
FROM roads',
1060, 1661,
directed := true);
所有的方法都有單-單,單-多,多-單,多- 多,詳細參考官方api
pgr_dijkstra(edges_sql, start_vid, end_vid)
pgr_dijkstra(edges_sql, start_vid, end_vid [, directed])
pgr_dijkstra(edges_sql, start_vid, end_vids [, directed])
pgr_dijkstra(edges_sql, start_vids, end_vid [, directed])
pgr_dijkstra(edges_sql, start_vids, end_vids [, directed])
本例子上述使用的是:
--單-單,無方向
pgr_dijkstra(edges_sql, start_vid, end_vid)
----單-單,有方向
pgr_dijkstra(edges_sql, start_vid, end_vid, true)
更多其他使用,請具體參考官方api,本文的方向,障礙點,限制車輛類型,限制車輛速度等等僅提供輔助參考作用,本質上都僅僅是設置roads的cost和rev_cost參數(shù)而已。