本文要求讀者具備如下知識和技術背景:
1 熟悉Java開發,知道如何正確的編譯運行Java代碼;
2 知道GIS的基本概念,知道地圖導航的基本概念;
3 對GeoTools有一定的認識。
一開始先來明確我們的任務:在基本的路徑查詢基礎上
1 實現單行道限制
2 實現左右拐彎限制
3 實現動態路況限制
4 選擇最短距離和最短時間
圖和圖的搜索
要想了解路徑查詢的算法,首先得了解一下它的數學模型“圖”。簡而言之,圖就是一系列的點和點之間的連接關系。【Graph】
所謂路徑查詢,可以簡化成對一個圖的搜索。例如:從點6到點1的最短路徑是,6-4-5-1,或者6-4-3-2-1,又或者6-4-5-2-3-4-5-1。如你所見,從6到1之間可以有許多條路徑,其中第一條和第二條我們認為是合理的,第三條是不合理的,因為它有重復路段。所以查詢節點間路徑的算法就顯得至關重要了。經典的查詢算法有:Dijkstra和它的改進版本A*。這兩個算法的實現各種語言都有,也很成熟了,我們不需要自己去寫,但是最為一種訓練,有興趣的讀者可以自己試着實現。
我在這里只介紹一下基本概念。從前面的例子我們看到兩點間可以有多條路徑,但是實際上我們一般只關心一條路徑,就拿開車來說,我們關心駕駛時間最少的路。一般情況下,實際距離短駕駛時間就少,所以我們先從實際距離入手。作為搜索算法如何確定距離最短呢。6-4-5-1一定比6-4-3-2-1距離短嗎。顯然我們不能僅僅根據節點的個數來判斷距離。事實是我們除了擁有點和點之間的連接外,還需要連接的屬性,這里就是距離。用上面的例子我們來指定距離:
6-4距離10
4-5距離7
5-1距離6
4-3距離2
3-2距離4
2-1距離1
6-4-5-1距離10+7+6=23
6-4-3-2-1距離10+2+4+1=17
顯然第二條路雖然節點多但是距離短。這里需要引人一個概念“開銷”,在這個例子中目前我們使用路徑距離來代表開銷。我們總是選擇開銷小的路徑。現實中影響駕駛時間的因素除了距離還有道路擁堵情況,所以我們增加屬性,叫擁堵系數,假設距離乘上系數才是我們需要的開銷:
6-4距離10 擁堵1
4-5距離7 擁堵2
5-1距離6 擁堵1
4-3距離2 擁堵13
3-2距離4 擁堵11
2-1距離1 擁堵11
6-4-5-1距離10*1+7*2+6*1=30
6-4-3-2-1距離10*1+2*13+4*11+1*11=91
可以看到,雖然第二條路的實際距離短,但是由於擁堵情況嚴重,它的開銷遠大於第一條路。在這種情況下我們應該選擇實際距離長的第一條路。我們可以不斷對上面的計算進行完善,增加更多的屬性來應對更復雜的實際情況。
分析任務
有了上面的知識我們來看看我們的任務:
1 實現單行道限制
我們可以給連接增加屬性叫“行駛方向限制”,有三個值,分別是:“正向通行”,“反向通行”,“雙向通行”。然后在計算開銷的時候,判斷當前方向是否與連接節點的方向一致,然后根據“行駛方向限制”的值來決定是否允許通行,如果不允許則返回一個極大值代表開銷。
2 實現左右拐彎限制
在實現單行線的基礎上就可以實現拐彎限制,但是需要在數據制作上做文章:
我們不能用一條線來代表一個路段,而應該用並行且方向相反的兩條線,這樣拐彎的地方也自然變成了單行線的一部分了。
3 實現動態路況限制
這個在上一節介紹圖的時候已經說明了不在贅述。
4 選擇最短距離和最短時間
這個在上一節介紹圖的時候已經說明了不在贅述。
代碼實現
改程序要求:
1 路網數據是Shapfile格式保存的線段數據
2 屬性必須提供兩個:
id 整數
type 整數 只有三個值 1:正向通行;-1:反向通行;0:雙向通行
程序采用Java編寫,利用GeoTools 11軟件包中的graph擴展實現圖的搜索。程序啟動后需要先選擇路網數據,然后可見主界面,在主界面地圖上點擊設置起止位置。不同方向會選擇不同道路,如圖:


