最近公司有個專案需要計算6000個點之間的駕車距離,第一時間想到的是利用Google的Distance Matrix API,但是免費Key每天只能計算2500個元素(元素 = 起點數量 * 終點數量),收費的話每1000個元素需要0.5刀,6000個點(接近3600w條邊)基本就是1.8w刀。。。而且限制頗多,資料只允許本地快取一個月,QPS限定100,每天查詢元素上限10w,計算完客戶早走了,基本不可用。

然後就想到了開(免)源(費)的OpenStreetMap(簡稱OSM),OSM是一個開源的地相簿,可以在http://download.geofabrik.de/下載各國家地圖包,資料還是比較全的。

有了地圖資料,還需要一個尋路計算框架,找到了一個免費的庫osm2po(http://osm2po.de/)

下載osm2po以後修改demo.sh或demo.bat的地圖路徑為你自己的pbf檔案地址:

執行以後會啟動一個Http伺服器,預設地址http://localhost:8888/Osm2poService,開啟就能看見地圖介面了:

 
隨便尋個路,效果還可以,國內路線看起來和高德地圖差不多
 
Http訪問方式只提供了這麼些引數可以使用,並不是很完善,沒有distance的選項,而且http的訪問方式效率也不高,最好還是用Java API
 
計算兩點間距離可以直接用官網示例的DefaultRouter,很簡單。
多點距離在gis.stackexchange.com發現作者說有提供Distance Matrix API,emmm不錯,看了下jar包的確是有一個TspDefaultMatrix的類,直接上程式碼:
public static void main(String[] args) throws Exception {
File graphFile = new File(args[0]);
Graph graph = new Graph(graphFile); // Somewhere in Graph
LatLon source = new LatLon(32.0452460989,118.8318873038);
LatLon target = new LatLon(31.8870800000,118.8300200000); // additional params for DefaultRouter
Properties params = new Properties();
params.setProperty("findShortestPath", "true");
params.setProperty("ignoreRestrictions", "false");
params.setProperty("ignoreOneWays", "false");
params.setProperty("heuristicFactor", "0.0"); // 0.0 Dijkstra, 1.0 good A* int[] vertexIds = findClosestVertexIds(graph, source, target);
Log log = new Log(Log.LEVEL_DEBUG).addLogWriter(new LogConsoleWriter());
TspDefaultMatrix matrix = new TspDefaultMatrix(graph, vertexIds, Float.MAX_VALUE, log, params); float[][] distances = matrix.getCosts();
for (int i = 0; i < distances.length; i++) {
for (int j = 0; j < distances.length; j++) {
System.out.println(distances[i][j]);
}
} graph.close();
} public static int[] findClosestVertexIds(Graph graph, LatLon... latLons) {
int[] vertexIds = new int[latLons.length];
for (int i = 0; i < latLons.length; i++) {
// if failed, return -1
vertexIds[i] = graph.findClosestVertexId(
(float) latLons[i].getLat(), (float) latLons[i].getLon());
}
return vertexIds;
}

算出來的結果21.01734公里,和高德地圖完全吻合

公司專案第一個使用的地方是一個鳥不拉屎的非洲小國家,除了主幹道基本都是人踩出來的小路,固定地點尋路成功率也達到了83%以上,失敗的情況一般谷歌地圖也沒路。國內道路好太多,估計95%成功率是OK的。

實際測試1700個點,地圖大小30M,生成有效資料240w條,堆記憶體使用6.5g,只用了60秒。
 
ps:距離相近的點,得到的地圖塊id可能相同,傳入TspDefaultMatrix會error,要做一個去重的對映處理。