一 前言
PgRouting是基于開(kāi)源空間數(shù)據(jù)庫(kù)PostGIS用于網(wǎng)絡(luò)分析的擴(kuò)展模塊,最初它被稱作pgDijkstra,因?yàn)樗皇抢肈ijkstra算法實(shí)現(xiàn)最短路徑搜索,之后慢慢添加了其他的路徑分析算法,如A算法,雙向A算法,Dijkstra算法,雙向Dijkstra算法,tsp貨郎擔(dān)算法等,然后被更名為pgRouting[1]。該擴(kuò)展庫(kù)依托PostGIS自身的gist索引,豐富的坐標(biāo)系與圖形類型,強(qiáng)大的幾何處理能力,如空間查詢,空間處理,線性參考等優(yōu)勢(shì),能保障在較大數(shù)據(jù)級(jí)別下的網(wǎng)絡(luò)分析效果更快更好。
PostGIS早已奠定了最優(yōu)秀的開(kāi)源空間數(shù)據(jù)庫(kù)地位,在新時(shí)代GIS中的應(yīng)用將會(huì)越來(lái)越普遍。其實(shí),網(wǎng)絡(luò)分析算法很多服務(wù)端語(yǔ)言如java,C#等雖能實(shí)現(xiàn),但基于真實(shí)城市道路數(shù)據(jù)量較大且查詢分析操作步驟復(fù)雜與數(shù)據(jù)庫(kù)交互頻繁,以這類服務(wù)端頻繁訪問(wèn)數(shù)據(jù)庫(kù)導(dǎo)致數(shù)據(jù)庫(kù)開(kāi)銷壓力較大,分析較慢,故選擇PgRouting在數(shù)據(jù)庫(kù)內(nèi)部實(shí)現(xiàn)算法,提升分析效率。最后,路徑分析不僅僅是最短路徑,在實(shí)際應(yīng)用中還有最短耗時(shí),最近距離,道路對(duì)車輛類型限制,道路對(duì)速度限制等因素,交通事故、市政事故導(dǎo)致的交通障礙點(diǎn)等問(wèn)題,所有的問(wèn)題本質(zhì)其實(shí)是對(duì)路徑分析權(quán)重(Weight)的設(shè)置問(wèn)題。
二 PgRounting安裝
windows安裝過(guò)程比較簡(jiǎn)單,安裝PostgreSQL,PostGIS一直Next即可,安裝完自帶PgRouting擴(kuò)展,這里主要以Centos7介紹安裝過(guò)程:
- 安裝PostgreSQL,參考 《Centos7安裝PostgreSQL》;
- 安裝PostGIS,PgRouting,具體安裝步驟參考《CentOS 7源碼安裝PostGIS(包含SFCGAL,PgRouting)》;
三 搭建網(wǎng)絡(luò)分析庫(kù)
3.1 創(chuàng)建測(cè)試數(shù)據(jù)庫(kù)
[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 導(dǎo)入測(cè)試路網(wǎng)數(shù)據(jù)
PgRouting需要使用道路線型數(shù)據(jù),建立道路連通性topo關(guān)系。由于路網(wǎng)分析的特殊性,只支持LineString類型,不支持MultiLineString類型。測(cè)試數(shù)據(jù)從OSM下載得來(lái)。

一般下載shp,使用PostGIS自帶的shp2pgsql導(dǎo)入即可。其他格式可以使用osm2pgrouting工具,本文不做詳述。筆者下載后,將路網(wǎng)數(shù)據(jù)使用ArcMap只截取了南京市范圍內(nèi)路網(wǎng)后,從epsg:4326轉(zhuǎn)換成了epsg:3857坐標(biāo)系,然后導(dǎo)入數(shù)據(jù)庫(kù),做測(cè)試數(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
關(guān)于shp2pgsql參數(shù)問(wèn)題,參考http://www.itdecent.cn/p/1251fdc603ac。
注意:使用shp2pgsql工具,shp路徑不要太深,不要有中文。對(duì)于含有中文亂碼的,可使用-W gbk等轉(zhuǎn)碼。
3.3 創(chuàng)建網(wǎng)絡(luò)分析topo
PgRouting提供pgr_createTopology方法,對(duì)道路數(shù)據(jù)創(chuàng)建拓?fù)潢P(guān)系,比如單一線要素,建立與其連通的source,tartget連通點(diǎn)。詳細(xì)步驟如下:
#在network數(shù)據(jù)庫(kù)中對(duì)導(dǎo)入的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工具會(huì)自動(dòng)創(chuàng)建gid為主鍵,geom為圖形。
#如果是自己其他形式建立的表,注意參數(shù)寫自己對(duì)應(yīng)的字段
network=# SELECT pgr_createTopology('road', 0.00001, 'geom', 'gid');
正常情況下順利完成以上步驟。
由于在網(wǎng)絡(luò)分析中頻繁讀取source,target字段的topo關(guān)系值,為了提升查詢效率,需要對(duì)這兩個(gè)字段添加索引:
network=# create index road_source_idx on road("source");
network=# create index road_target_idx on road("target");
3.4 路網(wǎng)元數(shù)據(jù)說(shuō)明
到此為止,全部數(shù)據(jù)準(zhǔn)備工作已經(jīng)完成了,查看本文用于測(cè)試路徑分析的數(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表?yè)碛兄麈I索引,geom的gist索引,source,target節(jié)點(diǎn)處索引,還有一般性的道路名稱字段,比較重要的是direction和oneway字段(有一個(gè)即可),這兩個(gè)字段都是說(shuō)明道路真實(shí)方向的。
| direction | oneway | 含義 |
|---|---|---|
| 0,1 | 空值 | 道路雙向通行 |
| 2 | FT | 道路真實(shí)方向與數(shù)字化方向一致 |
| 3 | TF | 道路真實(shí)方向與數(shù)字化方向相反 |
| 4 | N | 道路禁止通行 |
3.5 通行成本權(quán)重設(shè)置
在算法中分為有向圖,無(wú)向圖,圖的path長(zhǎng)度一般設(shè)置為權(quán)重,網(wǎng)絡(luò)分析中,具體到比如交通領(lǐng)域,也分為雙向通行道路,單向通行道路,交通事故導(dǎo)致的臨時(shí)交通阻塞無(wú)法通行(障礙點(diǎn)),不同等級(jí)道路對(duì)車輛類型限制,比如高架,高速只允許機(jī)動(dòng)車,鄉(xiāng)間道路允許非機(jī)動(dòng)車(條件限制因素),本節(jié)只是舉個(gè)例子說(shuō)明下不同的條件下如何設(shè)置通行成本權(quán)重:
- 雙向通行:
update road set length=st_length(geom),rev_length=st_length(geom) where oneway is null;
--采用真實(shí)地理距離是這樣:
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ù)字化方向一致,那么正向通行成本為道路長(zhǎng)度,反向成本為正無(wú)窮(以極大值代替)
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';
- 障礙點(diǎn)
#假設(shè)gid=20的道路因事故,修路暫時(shí)不能通行
update road set lenght=99999999999,rev_length=99999999999 where gid=20;
- 限制通行
假設(shè)當(dāng)前是一輛大貨車,通過(guò)有限高限重的道路,在為他做規(guī)劃時(shí),先獲取車輛類型,再查詢r(jià)oad表中是否有對(duì)其限制的因素(以下純邏輯描述sql)
#假設(shè)道路表有字段restrict,該字段是array,記錄了不可通行的車輛類型
update road set lenght=99999999999,rev_length=99999999999 where 'lorry'=any(restrict);
四 路徑分析
言歸正傳,本文從入門角度只闡述最簡(jiǎn)單的單向,雙向通行道路的例子,其他概不設(shè)置限制。
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)建路徑分析方法
- 單點(diǎn)到單點(diǎn)
建立好網(wǎng)絡(luò)topo的數(shù)據(jù)一定會(huì)有source,target字段,這是表達(dá)線的走向和連通性的關(guān)系,一條線的target,是與它尾部相連的其他線的source。
--忽視道路方向,每條路正反都可以通行
SELECT * FROM pgr_dijkstra(
'SELECT gid AS id,
source,
target,
cost
FROM roads',
1060, 1661,
directed := false);
--遵循道路真實(shí)方向,有的道路是單行道,如高速的一側(cè),有的路是正反都可以通行,他們由cost,revcost決定的
SELECT * FROM pgr_dijkstra(
'SELECT gid AS id,
source,
target,
cost,rev_cost as reverse_cost
FROM roads',
1060, 1661,
directed := true);
所有的方法都有單-單,單-多,多-單,多- 多,詳細(xì)參考官方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])
本例子上述使用的是:
--單-單,無(wú)方向
pgr_dijkstra(edges_sql, start_vid, end_vid)
----單-單,有方向
pgr_dijkstra(edges_sql, start_vid, end_vid, true)
更多其他使用,請(qǐng)具體參考官方api,本文的方向,障礙點(diǎn),限制車輛類型,限制車輛速度等等僅提供輔助參考作用,本質(zhì)上都僅僅是設(shè)置roads的cost和rev_cost參數(shù)而已。