因業務需求,需要做最短路徑分析。最近幾天查詢資料,並自己動手,實現了簡單的路徑分析。
下面就介紹具體的實現過程。
本篇文章最終結果是在 PostgreSQL 資料庫中實現的,後續的視覺化展示會跟進。
如果你已經有了道路資料,那就直接使用。
由於當前並沒有較好的道路資料,這裡我自己用 QGIS 造了些資料以供使用。
為了效果較好,在建立道路資料時是疊加了影像圖的。並且要開啟「捕捉工具」,這樣在後續的拓撲分析中更好。
在完成道路資料的建立後,我直接進行了後續的工作,但是最終發現有問題,分析時發現:道路的資料在每個相交的點處要進行打斷,否則無法進行路徑分析。
於是在這裡對道路資料做了處理。使用「線相交」工具,輸入、相交圖層選當前道路圖層:
如下圖:
這三段本是一條道路,但是為了拓撲分析,需要進行在和別的道路相交點進行打斷。
此處部分要注意:
1、編輯時開啟「捕捉工具」
2、完成道路後進行線的打斷
資料庫這一塊,因為 PostgreSQL 有強大的空間資料處理擴充套件外掛(PostGIS),並且也有路徑分析的外掛(pgRouting),所以選用該資料庫。
1)、PostgreSQL 資料安裝
1、windows 下,直接在官網下載安裝包即可,安裝完成資料庫後,會有 stackbuilder 安裝嚮導,可以安裝對應的一些外掛等,比較方便;
2、Ubuntu下(我用的伺服器),在 18.04 及以上,可以使用 PostgreSQL Apt Repository ,這樣可以安裝需要的版本;
2.1、PostgreSQL Apt Repository 使用
3、安裝及設定參考
2)、PostGIS
這部分有兩塊,一個是 PostgreSQL 的擴充套件,一個是 PostGIS的GUI(需要單獨安裝,主要用於匯入空間資料)。
3)、資料匯入
1、建立資料庫,建立完成後需要進行對資料庫新增空間擴充套件
-- 提供如下空間資訊服務功能:空間物件、空間索引、空間操作函數和空間操作符 CREATE EXTENSION postgis; -- 用於網路分析的擴充套件模組 CREATE EXTENSION pgrouting; -- gis 拓撲 CREATE EXTENSION postgis_topology; -- 提供了幾個函數來確定字串之間的相似性和距離 CREATE EXTENSION fuzzystrmatch; CREATE EXTENSION postgis_tiger_geocoder; CREATE EXTENSION address_standardizer;
2、使用工具匯入空間資料,最新版本在Windows下名字比較長,如下圖:
到這裡就完成了空間資料的匯入,在這個過程中會遇到一些問題,可以參考:PostgreSQL 與 PostGIS 安裝使用注意坑
這一塊主要是在資料庫中使用 SQL 完成,建立對應的 source、target、length、reverse_cost 欄位並賦值。
-- 新增起點id ALTER TABLE public.roads ADD COLUMN source integer; -- 新增終點id ALTER TABLE public.roads ADD COLUMN target integer; -- 新增道路權重值 ALTER TABLE public.roads ADD COLUMN length double precision; -- 建立拓撲結構 -- 為roads表建立拓撲佈局,即為source和target欄位賦值 SELECT pgr_createTopology('roads',0.00001, 'geom','id'); -- 建立索引 -- 為source和target欄位建立索引 CREATE INDEX source_idx ON roads ("source"); CREATE INDEX target_idx ON roads ("target"); -- 為length賦值,這裡在計算的時候用 ST_Transform 進行了轉換 UPDATE roads SET length =st_length(ST_Transform(geom,3857)); -- 為 roads 表新增 reverse_cost 欄位並用length的值賦值 ALTER TABLE roads ADD COLUMN reverse_cost double precision; UPDATE roads SET reverse_cost =length;
pgRouting 提供的最佳路徑演演算法比較多,具體可以參考:pgRouting 最短路徑演演算法查詢
這裡用 Shortest Path Dijkstra(狄克斯特拉)演演算法進行計算。
最新的 pgr_dijkstra 演演算法,支援多種方式,一對一、一對多、多對一、多對多等。
1)、用例分析
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, Combinations SQL , [directed]) RETURNS SET OF (seq, path_seq, [start_vid], [end_vid], node, edge, cost, agg_cost) OR EMPTY SET
傳入的引數:
1、Edges SQL
a、id,建立拓撲的標識,名稱不同用 as
b、source,邊起點識別符號,拓撲後新增的欄位
c、target,邊終點識別符號,拓撲後新增的欄位
d、cost,邊權重(長度)
e、reverse_cost,回程權重
2、start vid:路徑起始點標識
3、end vid:路徑終點標識
4、directed:ture 時,圖被認為是有向的
返回引數:
1、seq:查詢結果排序值
2、path_seq:一個路徑下的排序值,新的路徑重新從1開始
3、start_vid:多對一、多對,有這個欄位,路徑的起始點標識
4、end_vid:一對多、多對多,有這個欄位,路徑的終點標識
5、node:路徑中個個邊連線點的標識(上一個邊的 end,下一個邊的 start)
6、edge:路徑中邊的標識
7、cost:當前邊的成本(長度)
8、reverse_cost:總成本(總長度)
2)、具體使用
-- 最短路徑分析 -- 直接使用,返回的是演演算法預設資料 SELECT * from public.pgr_dijkstra( 'SELECT id, source::integer, target::integer, length::double precision AS cost, reverse_cost FROM roads', 1, 20, false ); -- edge 是建立拓撲時的 id 標識欄位,所以可以通過這個在 roads 中篩選,並通過資料庫自帶的視覺化檢視結果 SELECT * from roads where "id" in ( SELECT edge from public.pgr_dijkstra( 'SELECT id, source::integer, target::integer, length::double precision AS cost, reverse_cost FROM roads', 1, 20, false ) );
第二個SQL效果如下: