我在WebGIS最佳實踐-2 在WebGIS程序中實現路徑分析中提到過pgRouting,現在來看看這頭小象能給我們帶來些什么。
先上效果圖給大家鼓鼓勁。:》
為了實現以上效果我用jsp和openlayers編寫了服務端和客戶端,但是本文的重點是介紹pgRouting所以不在這里詳細介紹這些這些代碼了,大家可以從下載包中找到這兩個文件。要使用pgRouting得先安裝,我假設大家已經安裝了Postgresql和PostGIS。
從這里下載合適的二進制包,我下的是Windows版本,解壓縮后把Lib下面的動態庫復制到Postgresql的bin目錄下,把Share\Contrib下面的sql文件復制到Postgresql的share\contrib目錄下,然后重新啟動Postgresql(這一步我不確定是否必要)。然后就可以進行路徑搜素了,下面我們從數據准備開始,一步步得創建出完整可用的路網數據表。Let·s rock!
我們先要創建一個新數據庫,就叫routing吧,我們會先讓它支持pgRouting的函數然后給他增加一張表,一張路網表。隨后我們會需要執行一些sql腳本,你可以用postgresql提供的小程序psql.exe來執行也可以用圖形化工具pgAdmin來完成。我選擇用psql。postgresql提供的程序createdb.exe可以幫助我們創建數據庫,我們假設用戶是postgres:
createdb -U postgres routing
然后讓數據庫支持PostGIS和pgRouting的函數和基礎表
psql –U postgres –d routing –f postgis.sql psql –U postgres –d routing –f spatial_ref_sys.sql psql –U postgres –d routing –f routing_core.sql psql –U postgres –d routing –f routing_core_wrappers.sql psql –U postgres –d routing –f routing_topology.sql
其中,“postgis.sql,spatial_ref_sys.sql”可以在“<Postgresql的安裝路徑>\<version>\share\contrib\postgis<-1.4>”下面找到,到此數據庫創建完成。
為了創建路網表,我們需要一些道路數據。可以從OpenStreetMap上免費獲得XML格式的道路數據。由於我們平時更容易獲得Shapefile格式的數據,所以我決定用shp來完成數據導入。從Geobase下載道路數據。這個網站提供加拿大全國的道路數據,選擇British Columbia , Edition 8.0的Shapefile格式(nrn_rrn_bc_shp_en.zip)。解壓縮,我們要使用的數據就在“NRN_BC_8_0_ROADSEG”中。這個表的字段很多,大家可以用熟悉的GIS數據處理工具刪掉一些字段,當然不處理也沒關系。
先用shp2psql.exe程序把shp文件裝換成sql腳本
shp2pgsql -s 4326 NRN_BC_8_0_ROADSEG public.street_bc > street_bc.sql
如果一切順利的話,我們會得到文件“street_bc.sql”,這是一個很大的文件。然后我們執行這個文件:
psql -U postgres -d routing -f street_bc.sql
下面創建路網的拓撲結構
psql –U postgres –d routing –c “alter table street_bc add “source” integer” psql –U postgres –d routing –c “alter table street_bc add “target” integer” psql –U postgres –d routing –c “select assign_vertex_id(“street_bc”,0.001,”the_geom”,”gid”)” psql –U postgres –d routing –c “alter table street_bc add “length” double precision” psql –U postgres –d routing –c “update routing set length=st_length(the_geom)”
到這里路網數據就做好了。來測試一下:
SELECT astext(st_transform(the_geom,900913)),l_stname_c as name FROM shortest_path('SELECT gid as id,source::integer,target::integer,length::double precision as cost FROM street_bc',158390, 63634, false, false),street_bc where edge_id = gid;