一、軟件安裝
GeoServer下載地址:
http://geoserver.org/download/
PostgreSQL下載地址:
https://www.postgresql.org/download/
paAdmin3下載地址:
https://www.pgadmin.org/download/pgadmin-3-windows/
PostGIS下載地址:
http://postgis.net/windows_downloads/
pgRouting已經包含在安裝程序中。
所有下載程序如下:

安裝過程不再詳述。
二、數據制作
我使用的是ArcMap來繪制路網數據,也可以使用其它的GIS軟件,但好像沒有這么方便,地理坐標系使用GCS_WGS_1984,編號為:4326。

注意:所有線段連接的地方都需要斷開,這樣便於以后的分析。
三、數據處理
使用paAdmin3連接PostgreSQL,並執行以下語句,在新的空間數據庫里添加空間擴展:
CREATE EXTENSION postgis;
CREATE EXTENSION pgrouting;
CREATE EXTENSION postgis_topology;
CREATE EXTENSION fuzzystrmatch;
CREATE EXTENSION postgis_tiger_geocoder;
CREATE EXTENSION address_standardizer;

制作完路網數據后,需要使用
來把路網數據導入到PostgreSQL中去。

點擊“View connection details....”在彈出的窗口中填入PostgreSQL的賬號和密碼,以及Database。
連接成功后,需要設置一下“Optionns...”

需要使用GBK編碼,並勾選最下面一個選項。
添加路網數據,並設置SRID為:4326

導入完成后,會在數據庫中創建一個對應的表:

在查詢表中分別執行下列SQL,對表結構進行修改:
1.修改表結構
--添加起點id
ALTER TABLE public.road_xblk ADD COLUMN source integer;
--添加終點id
ALTER TABLE public.road_xblk ADD COLUMN target integer;
--添加道路權重值
ALTER TABLE public.road_xblk ADD COLUMN length double precis
2.創建拓撲結構
--為sampledata表創建拓撲布局,即為source和target字段賦值
SELECT pgr_createTopology('public.road_xblk',0.0001, 'geom', 'gid');
3.創建索引
--為source和target字段創建索引
CREATE INDEX source_idx ON road_xblk("source");
CREATE INDEX target_idx ON road_xblk("target");
4.給長度賦值
--為length賦值
update road_xblk set length =st_length(geom);
--為road_xblk表添加reverse_cost字段並用length的值賦值
ALTER TABLE road_xblk ADD COLUMN reverse_cost double precision;
UPDATE road_xblk SET reverse_cost =length;
5.創建最短路徑函數
---創建查詢隨意兩點之前的最短路徑的函數
1 DROP FUNCTION pgr_fromAtoB(tbl varchar,startx float, starty float,endx float,endy float); 2 3 CREATE OR REPLACE function pgr_fromAtoB(tbl varchar,startx float, starty float,endx float,endy float) 4 5 returns geometry as 6 7 $body$ 8 9 declare 10 11 v_startLine geometry;--離起點最近的線 12 13 v_endLine geometry;--離終點最近的線 14 15 16 17 v_startTarget integer;--距離起點最近線的終點 18 19 v_startSource integer; 20 21 v_endSource integer;--距離終點最近線的起點 22 23 v_endTarget integer; 24 25 26 27 v_statpoint geometry;--在v_startLine上距離起點最近的點 28 29 v_endpoint geometry;--在v_endLine上距離終點最近的點 30 31 32 33 v_res geometry;--最短路徑分析結果 34 35 v_res_a geometry; 36 37 v_res_b geometry; 38 39 v_res_c geometry; 40 41 v_res_d geometry; 42 43 44 45 v_perStart float;--v_statpoint在v_res上的百分比 46 47 v_perEnd float;--v_endpoint在v_res上的百分比 48 49 50 51 v_shPath_se geometry;--開始到結束 52 53 v_shPath_es geometry;--結束到開始 54 55 v_shPath geometry;--最終結果 56 57 tempnode float; 58 59 begin 60 61 --查詢離起點最近的線 62 63 execute 'select geom, source, target from ' ||tbl|| 64 65 ' where ST_DWithin(geom,ST_Geometryfromtext(''point('|| startx ||' ' || starty||')'',4326),15) 66 67 order by ST_Distance(geom,ST_GeometryFromText(''point('|| startx ||' '|| starty ||')'',4326)) limit 1' 68 69 into v_startLine, v_startSource ,v_startTarget; 70 71 72 73 --查詢離終點最近的線 74 75 execute 'select geom, source, target from ' ||tbl|| 76 77 ' where ST_DWithin(geom,ST_Geometryfromtext(''point('|| endx || ' ' || endy ||')'',4326),15) 78 79 order by ST_Distance(geom,ST_GeometryFromText(''point('|| endx ||' ' || endy ||')'',4326)) limit 1' 80 81 into v_endLine, v_endSource,v_endTarget; 82 83 84 85 --如果沒找到最近的線,就返回null 86 87 if (v_startLine is null) or (v_endLine is null) then 88 89 return null; 90 91 end if ; 92 93 94 95 select ST_ClosestPoint(v_startLine, ST_Geometryfromtext('point('|| startx ||' ' || starty ||')',4326)) into v_statpoint; 96 97 select ST_ClosestPoint(v_endLine, ST_GeometryFromText('point('|| endx ||' ' || endy ||')',4326)) into v_endpoint; 98 99 100 101 -- ST_Distance 102 103 104 105 --從開始的起點到結束的起點最短路徑 106 107 execute 'SELECT st_linemerge(st_union(b.geom)) ' || 108 109 'FROM pgr_kdijkstraPath( 110 111 ''SELECT gid as id, source, target, length as cost FROM ' || tbl ||''',' 112 113 ||v_startSource || ', ' ||'array['||v_endSource||'] , false, false 114 115 ) a, ' 116 117 || tbl || ' b 118 119 WHERE a.id3=b.gid 120 121 GROUP by id1 122 123 ORDER by id1' into v_res ; 124 125 126 127 --從開始的終點到結束的起點最短路徑 128 129 execute 'SELECT st_linemerge(st_union(b.geom)) ' || 130 131 'FROM pgr_kdijkstraPath( 132 133 ''SELECT gid as id, source, target, length as cost FROM ' || tbl ||''',' 134 135 ||v_startTarget || ', ' ||'array['||v_endSource||'] , false, false 136 137 ) a, ' 138 139 || tbl || ' b 140 141 WHERE a.id3=b.gid 142 143 GROUP by id1 144 145 ORDER by id1' into v_res_b ; 146 147 148 149 --從開始的起點到結束的終點最短路徑 150 151 execute 'SELECT st_linemerge(st_union(b.geom)) ' || 152 153 'FROM pgr_kdijkstraPath( 154 155 ''SELECT gid as id, source, target, length as cost FROM ' || tbl ||''',' 156 157 ||v_startSource || ', ' ||'array['||v_endTarget||'] , false, false 158 159 ) a, ' 160 161 || tbl || ' b 162 163 WHERE a.id3=b.gid 164 165 GROUP by id1 166 167 ORDER by id1' into v_res_c ; 168 169 170 171 --從開始的終點到結束的終點最短路徑 172 173 execute 'SELECT st_linemerge(st_union(b.geom)) ' || 174 175 'FROM pgr_kdijkstraPath( 176 177 ''SELECT gid as id, source, target, length as cost FROM ' || tbl ||''',' 178 179 ||v_startTarget || ', ' ||'array['||v_endTarget||'] , false, false 180 181 ) a, ' 182 183 || tbl || ' b 184 185 WHERE a.id3=b.gid 186 187 GROUP by id1 188 189 ORDER by id1' into v_res_d ; 190 191 192 193 if(ST_Length(v_res) > ST_Length(v_res_b)) then 194 195 v_res = v_res_b; 196 197 end if; 198 199 200 201 if(ST_Length(v_res) > ST_Length(v_res_c)) then 202 203 v_res = v_res_c; 204 205 end if; 206 207 208 209 if(ST_Length(v_res) > ST_Length(v_res_d)) then 210 211 v_res = v_res_d; 212 213 end if; 214 215 216 217 218 219 --如果找不到最短路徑,就返回null 220 221 --if(v_res is null) then 222 223 -- return null; 224 225 --end if; 226 227 228 229 --將v_res,v_startLine,v_endLine進行拼接 230 231 select st_linemerge(ST_Union(array[v_res,v_startLine,v_endLine])) into v_res; 232 233 234 235 select ST_Line_Locate_Point(v_res, v_statpoint) into v_perStart; 236 237 select ST_Line_Locate_Point(v_res, v_endpoint) into v_perEnd; 238 239 240 241 if(v_perStart > v_perEnd) then 242 243 tempnode = v_perStart; 244 245 v_perStart = v_perEnd; 246 247 v_perEnd = tempnode; 248 249 end if; 250 251 252 253 --截取v_res 254 255 SELECT ST_Line_SubString(v_res,v_perStart, v_perEnd) into v_shPath; 256 257 258 259 return v_shPath; 260 261 262 263 end; 264 265 $body$ 266 267 LANGUAGE plpgsql VOLATILE STRICT;
四、數據發布
數據准備完成后,就需要用GeoServer來進行發布:
啟動GeoServer,在瀏覽器中輸入,http://localhost:8080/geoserver/web/,登錄到GeoServer。
1.創建工作區

添加xblk名稱的工作區。
2.添加數據存儲:

填入對應的連接信息:

3.添加圖層:

注意紅框中的內容。
4.添加路徑查詢服務,添加圖層,選擇“配置新的SQL視圖”:

視圖名稱:navigation
SQL語句:
SELECT * FROM pgr_fromAtoB('road_xblk', %x1%, %y1%, %x2%, %y2%)
驗證的正則表達式:^-?[\d.]+$
類型:LingString
SRID:4326
點擊保存后,填入SRS,並自動計算范圍:

五、結果展示
使用OpenLayer進行結果展示,代碼請直接下載,結果如下:

說明:這個最短路徑的算法有一定的問題,在特定的條件下,查找的不一定是最短的路徑,需要對數據進行再處理,或者對算法進行優化。
