在現實生活中,我們每天都要考慮無數個路徑規劃的問題,只是可能大部分在您的大腦內就完成了。而大腦無法完成的部份,有時候並不是要真的知道怎麼走,在哪邊轉彎等等,而是會至少需要知道我多久會到、大概距離多遠,這部份就需要 HERE Routing API。
HERE Routing API 的功能相當的強大,以最「基本」的路徑規劃功能來說,就具有以下特色:
您可以到 HERE 地圖官方網站:https://wego.here.com/ 來體驗一下路徑規劃的功能,在左上角的輸入框可以輸入目的地,並且規劃路徑。
例如我們可以規劃出一個從台北市政府到新北市政府的路徑如下(https://bit.ly/2ZCl8SC):
畫面的左方是各個交通工具的選項,例如我們點進去汽車的路線之後,就會出現詳細的轉彎指引:
我們也可以在畫面上拖動路徑的任何一個點,來改變路線經過的地點:
我們也可以指定路線的出發時間,立即出發或是一個特定的時間點:
以大眾運輸來說,也可以查到轉乘資訊以及詳細的指引:
這些功能與資訊都來自 HERE Routing API。
HERE Routing API Reference Client (http://refclient.ext.here.com/)是一個把 Routing API 用網頁介面呈現出來的工具,因為 Routing API 的參數非常眾多,一時之間要熟悉會有點困難,因此用這個工具提供的 GUI 來搭配實際 HTTP Request 的解說會更有效率。
打開 HERE Routing API Reference Client 之後,您會看到一個中心為德國柏林的地圖,左邊有一些表單跟文字框。HERE Routing API 分成 V7 與 V8 兩個版本,V7 比較舊,但功能比較豐富;V8 比較新,但目前功能還在逐步完善中。HERE Routing API Reference Client 預設使用的是 V8,但我們目前就先用 V7 來體驗。
請先按下左上角的「New Tab +」,選擇「Caculate Route」,您會看到畫面上面多了一個「Route 1」的標籤頁,這個標籤頁就是 Routing API V7;而旁邊的「 OLS 1」則是 Routing API V8。
接著我們把地圖移動到台灣,您可以直接在地圖畫面上拖動,也可以使用畫面上方的搜尋功能,輸入字串後按下「Enter」就會移動到搜尋結果。
可以看到畫面已經在台北市了,接著我們可以在地圖上面隨意的按下滑鼠右鍵試試看,會出現一個功能表,可以進行相關的一些操作。
接著我們就在地圖上隨意的兩處按下右鍵,分別選擇「Route from」與「Route to」,這兩個動作就會把相關的經緯度填到下方的「API CALL」文字框中。接著按下右下角的「Send」,就會完成一個路徑規劃。
地圖上的 A 或 B 分別代表起點與終點,而這兩個點都可以透過滑鼠拖曳來改變位置與路徑規劃的結果。
我們在右側的「SUMMARY」下面可以看到這個路徑的幾個屬性:
另外「MANEUVERS」中可以看到每個轉彎的指示,包含轉彎方向、道路名稱、距離等等,這部份如果沒有特別設定的話會是英文,如果要改成中文的話請在左邊的輸入欄往下拉到「LANGUAGE」的部份,選擇「Chinese - Traditional Taiwan」,再按下右下角的「Send」就會回傳中文。
「RESPONSE」中可以看到幾個屬性:
{
"response": {
"metaInfo": {
"timestamp": "2020-09-15T05:05:44Z",
"mapVersion": "8.30.112.153",
"moduleVersion": "7.2.202036-7797",
"interfaceVersion": "2.6.76",
"availableMapVersion": ["8.30.112.153"]
},
"route": [{
"waypoint": [{
"linkId": "-1075002419",
"mappedPosition": {
"latitude": 25.03873,
"longitude": 121.5518288
},
"originalPosition": {
"latitude": 25.0387309,
"longitude": 121.551791
},
"type": "stopOver",
"spot": 0.6,
"sideOfStreet": "right",
"mappedRoadName": "仁愛路四段151巷",
"label": "仁愛路四段151巷",
"shapeIndex": 0,
"source": "user"
}, {
"linkId": "+988824709",
"mappedPosition": {
"latitude": 25.0628125,
"longitude": 121.5797749
},
"originalPosition": {
"latitude": 25.062841,
"longitude": 121.5797539
},
"type": "stopOver",
"spot": 0.5319149,
"sideOfStreet": "left",
"mappedRoadName": "新湖二路",
"label": "新湖二路",
"shapeIndex": 52,
"source": "user"
}],
"mode": {
"type": "fastest",
"transportModes": ["car"],
"trafficMode": "disabled",
"feature": []
},
"shape": [25.03873, 121.5518288, 25.0384855, 121.5518224, 25.0384855, 121.5527344, 25.0384748, 121.5527558, 25.0384963, 121.5529811, 25.0389469, 121.5529704, 25.0394189, 121.5529811, 25.0403416, 121.552949, 25.0414252, 121.5529704, 25.0413823, 121.5555453, 25.0412428, 121.5609956, 25.0411892, 121.5628517, 25.0411248, 121.5642893, 25.0411248, 121.5645576, 25.0417471, 121.5649652, 25.0433779, 121.5659308, 25.0434637, 121.5659845, 25.0434852, 121.5658879, 25.0435817, 121.5659416, 25.0447297, 121.5666282, 25.045706, 121.5672398, 25.0462747, 121.5675616, 25.0476265, 121.568377, 25.0476587, 121.5684199, 25.048281, 121.5687847, 25.0484526, 121.5689027, 25.0488281, 121.5691173, 25.0490749, 121.5692353, 25.0498366, 121.5697181, 25.0499547, 121.5697718, 25.0504375, 121.5700614, 25.0509202, 121.5704048, 25.0510919, 121.5705657, 25.0514352, 121.5709949, 25.0519931, 121.5719819, 25.0527763, 121.5734732, 25.0531948, 121.574235, 25.0534308, 121.574707, 25.0536132, 121.5748787, 25.0541067, 121.5758336, 25.054493, 121.5765309, 25.0558341, 121.5790522, 25.0561452, 121.5795672, 25.0571108, 121.5813911, 25.0571537, 121.5814662, 25.0572073, 121.5814447, 25.0581944, 121.5808547, 25.0588918, 121.5803397, 25.0591385, 121.5801358, 25.0607049, 121.5789449, 25.0618422, 121.5781081, 25.0620246, 121.5784729, 25.0628125, 121.5797749],
"leg": [{
"start": {
"linkId": "-1075002419",
"mappedPosition": {
"latitude": 25.03873,
"longitude": 121.5518288
},
"originalPosition": {
"latitude": 25.0387309,
"longitude": 121.551791
},
"type": "stopOver",
"spot": 0.6,
"sideOfStreet": "right",
"mappedRoadName": "仁愛路四段151巷",
"label": "仁愛路四段151巷",
"shapeIndex": 0,
"source": "user"
},
"end": {
"linkId": "+988824709",
"mappedPosition": {
"latitude": 25.0628125,
"longitude": 121.5797749
},
"originalPosition": {
"latitude": 25.062841,
"longitude": 121.5797539
},
"type": "stopOver",
"spot": 0.5319149,
"sideOfStreet": "left",
"mappedRoadName": "新湖二路",
"label": "新湖二路",
"shapeIndex": 52,
"source": "user"
},
"length": 5024,
"travelTime": 657,
"maneuver": [{
"position": {
"latitude": 25.03873,
"longitude": 121.5518288
},
"instruction": "沿著 <span class=\"street\">仁愛路四段151巷</span> 朝 <span class=\"toward_street\">安和路一段49巷</span> 行駛, <span class=\"distance-description\">直行 <span class=\"length\">27 公尺</span></span>",
"travelTime": 16,
"length": 27,
"firstPoint": 0,
"lastPoint": 1,
"direction": "forward",
"action": "depart",
"id": "M1",
"_type": "PrivateTransportManeuverType"
}, {
"position": {
"latitude": 25.0384855,
"longitude": 121.5518224
},
"instruction": "<span class=\"direction\">左轉</span>駛入 <span class=\"next-street\">安和路一段49巷</span>, <span class=\"distance-description\">直行 <span class=\"length\">117 公尺</span></span>",
"travelTime": 29,
"length": 117,
"firstPoint": 1,
"lastPoint": 4,
"direction": "left",
"action": "leftTurn",
"id": "M2",
"_type": "PrivateTransportManeuverType"
}, {
"position": {
"latitude": 25.0384963,
"longitude": 121.5529811
},
"instruction": "<span class=\"direction\">左轉</span>駛入 <span class=\"next-street\">忠孝東路四段216巷</span>, <span class=\"distance-description\">直行 <span class=\"length\">324 公尺</span></span>",
"travelTime": 62,
"length": 324,
"firstPoint": 4,
"lastPoint": 8,
"direction": "left",
"action": "leftTurn",
"id": "M3",
"_type": "PrivateTransportManeuverType"
}, {
"position": {
"latitude": 25.0414252,
"longitude": 121.5529704
},
"instruction": "<span class=\"direction\">右轉</span>駛入 <span class=\"next-street\">忠孝東路四段</span> <span class=\"number\">(台5線)</span>, <span class=\"distance-description\">直行 <span class=\"length\">1.1 公里</span></span>",
"travelTime": 140,
"length": 1141,
"firstPoint": 8,
"lastPoint": 12,
"direction": "right",
"action": "rightTurn",
"id": "M4",
"_type": "PrivateTransportManeuverType"
}, {
"position": {
"latitude": 25.0411248,
"longitude": 121.5642893
},
"instruction": "<span class=\"direction\">左轉</span>駛入 <span class=\"next-street\">基隆路一段</span>, <span class=\"distance-description\">直行 <span class=\"length\">312 公尺</span></span>",
"travelTime": 49,
"length": 312,
"firstPoint": 12,
"lastPoint": 15,
"direction": "left",
"action": "leftTurn",
"id": "M5",
"_type": "PrivateTransportManeuverType"
}, {
"position": {
"latitude": 25.0433779,
"longitude": 121.5659308
},
"instruction": "繼續沿著 <span class=\"next-street\">環東大道匝道</span>, <span class=\"distance-description\">直行 <span class=\"length\">31 公尺</span></span>",
"travelTime": 27,
"length": 31,
"firstPoint": 15,
"lastPoint": 18,
"direction": "forward",
"action": "continue",
"id": "M6",
"_type": "PrivateTransportManeuverType"
}, {
"position": {
"latitude": 25.0435817,
"longitude": 121.5659416
},
"instruction": "沿匝道行駛, <span class=\"distance-description\">直行 <span class=\"length\">513 公尺</span></span>",
"travelTime": 50,
"length": 513,
"firstPoint": 18,
"lastPoint": 22,
"direction": "forward",
"action": "continue",
"id": "M7",
"_type": "PrivateTransportManeuverType"
}, {
"position": {
"latitude": 25.0476265,
"longitude": 121.568377
},
"instruction": "靠<span class=\"direction\">右</span>駛入 <span class=\"next-street\">市民大道高架道路</span> 朝 <span class=\"sign\"><span lang=\"zh-Hant\">環東大道</span>/<span lang=\"zh-Hant\">3</span>/<span lang=\"zh-Hant\">1</span>/<span lang=\"zh-Hant\">南港經貿園區</span></span> 行駛, <span class=\"distance-description\">直行 <span class=\"length\">296 公尺</span></span>",
"travelTime": 21,
"length": 296,
"firstPoint": 22,
"lastPoint": 29,
"direction": "bearRight",
"action": "rightFork",
"id": "M8",
"_type": "PrivateTransportManeuverType"
}, {
"position": {
"latitude": 25.0499547,
"longitude": 121.5697718
},
"instruction": "靠<span class=\"direction\">右</span>駛入 <span class=\"next-street\">環東大道</span>, <span class=\"distance-description\">直行 <span class=\"length\">644 公尺</span></span>",
"travelTime": 47,
"length": 644,
"firstPoint": 29,
"lastPoint": 37,
"direction": "bearRight",
"action": "rightFork",
"id": "M9",
"_type": "PrivateTransportManeuverType"
}, {
"position": {
"latitude": 25.0534308,
"longitude": 121.574707
},
"instruction": "從<span class=\"direction\">左側</span>出口離開朝 <span class=\"sign\"><span lang=\"zh-Hant\">內湖</span>/<span lang=\"zh-Hant\">1</span></span> 行駛, <span class=\"distance-description\">直行 <span class=\"length\">789 公尺</span></span>",
"travelTime": 77,
"length": 789,
"firstPoint": 37,
"lastPoint": 43,
"direction": "bearLeft",
"action": "leftExit",
"id": "M10",
"_type": "PrivateTransportManeuverType"
}, {
"position": {
"latitude": 25.0571108,
"longitude": 121.5813911
},
"instruction": "<span class=\"direction\">左轉</span>駛入 <span class=\"next-street\">舊宗路一段</span>, <span class=\"distance-description\">直行 <span class=\"length\">631 公尺</span></span>",
"travelTime": 111,
"length": 631,
"firstPoint": 43,
"lastPoint": 50,
"direction": "left",
"action": "leftTurn",
"id": "M11",
"_type": "PrivateTransportManeuverType"
}, {
"position": {
"latitude": 25.0618422,
"longitude": 121.5781081
},
"instruction": "<span class=\"direction\">右轉</span>駛入 <span class=\"next-street\">新湖二路</span>, <span class=\"distance-description\">直行 <span class=\"length\">199 公尺</span></span>",
"travelTime": 28,
"length": 199,
"firstPoint": 50,
"lastPoint": 52,
"direction": "right",
"action": "rightTurn",
"id": "M12",
"_type": "PrivateTransportManeuverType"
}, {
"position": {
"latitude": 25.0628125,
"longitude": 121.5797749
},
"instruction": "抵達 <span class=\"street\">新湖二路</span> 。目的地位於左側",
"travelTime": 0,
"length": 0,
"firstPoint": 52,
"lastPoint": 52,
"direction": "forward",
"action": "arrive",
"id": "M13",
"_type": "PrivateTransportManeuverType"
}]
}],
"summary": {
"distance": 5024,
"trafficTime": 896,
"baseTime": 657,
"flags": ["motorway", "builtUpArea"],
"text": "該行程需要 <span class=\"length\">5.0 公里</span>, 大約 <span class=\"time\">11 分鐘</span>",
"travelTime": 657,
"_type": "RouteSummaryType"
},
"maneuverGroup": [{
"firstManeuver": "M1",
"lastManeuver": "M13",
"mode": "car",
"summaryDescription": "開車前往 <span class=\"street\">新湖二路</span>",
"arrivalDescription": "抵達 <span class=\"street\">新湖二路</span>"
}]
}],
"language": "zh-tw"
}
}
您也可以把下方的「API CALL」文字框中的 URL 複製出來,在別的地方使用,不過使用前請把裡面的「app_code」參數與「app_id」移除,換成自己的 APIKEY ,並把 Routing API 的 URL 換掉就好了,例如以下這個 URL 套用了 Reference Client 的預設參數。
例如這是原始的 URL:
https://route.api.here.com/routing/7.2/calculateroute.json
?routeattributes=sh,gr
&mode=fastest;car
&maneuverattributes=po,ti,pt,ac,di,fj,ix
&apikey=d4QjdTHec41hIeTo2RC6_L0LxcrJVB8_JVxtUo373JE
&language=zh-tw&jsonattributes=41
&metricsystem=metric
&waypoint0=geo!stopOver!25.038731,121.551791
&waypoint1=geo!stopOver!25.062841,121.579754
&app_code=pxIXqdtgOSwQDXSDfjLQpw
&app_id=cgZPrYfgRePXzXC3PbBp
這是修改過的 URL 與參數的大概說明:
https://route.ls.hereapi.com/routing/7.2/calculateroute.json // Routing API 的 URL
?routeattributes=sh,gr // 回傳路徑的形狀(sh)與 Maneuver Groups(gr)
&mode=fastest;car // 模式為計算最快路徑(fastest)使用汽車模式(car)
&maneuverattributes=po,ti,pt,ac,di,fj,ix // 轉彎提示屬性分別為位置(po)、時間(ti)、大眾運輸路線(pt)、動作(ac)、方向(di)、高快速公路出口(fj)、索引編號(ix)
&language=zh-tw // 語言為 zh-TW,也就是台灣正體中文
&jsonattributes=41 // 41 = 1(屬性首字元小寫)+8(在物件中加入「_type」屬性)+32(回傳路徑的形狀為 double 而非字串),
&metricsystem=metric // 使用公制單位
&waypoint0=geo!stopOver!25.038731,121.551791 // 第 0 個路徑點,代表起點
&waypoint1=geo!stopOver!25.062841,121.579754 // 第 1 個路徑點,此為終點
&apikey={APIKEY} // 您的 APIKEY
※ 關於如何取得 APIKEY,可參閱:
※ 關於計算路徑的詳細參數可參閱:https://developer.here.com/documentation/routing/dev_guide/topics/resource-calculate-route.html
當然,其實第一時間要了解這麼多元的參數確實比較不容易,因此 HERE Routing API Reference Client 就是一個相當好用的工具,畫面左邊分成兩個部份:「INPUT PARAMS / 輸入參數」與「OUTPUT PARAMS / 輸出參數」,我們先講解輸入參數的部份,因為這部份是會影響到路徑規劃的結果。
首先是路徑點設定,可以設定起點、終點與途經點,輸入方式除了經緯度,也可以是 link id 或街道,但最常用的還是經緯度。如果是途經點,還可以選擇「stopOver / 停留」或「passThrough / 經過」。
※ 關於路徑點參數詳情可見:https://developer.here.com/documentation/routing/dev_guide/topics/resource-param-type-waypoint.html
在路徑規劃的模式上,可以選擇不同的車種,選擇最短路徑(shortest)或最快路徑(fastest),以及是否使用即時路況。
另外,也可以針對特殊道路種類進行迴避,例如「TOLLROADS / 收費道路」、「MOTORWAYS / 高快速道路」、「BOAD FERRIES / 渡輪」、「RAIL FERRIES / 鐵路運輸」、「TUNNELS / 隧道」、「DIRT ROADS / 沙土路」、「PARKS / 公園(僅適用於自行車路徑)」。
而各個道路種類也可以選擇「Strict exclude / 嚴格排除」、「Soft exclude / 盡可能排除」、「Avoid / 儘量避免」、「Default / 預設值(不排除)」。
※ 關於路徑模式參數詳情可見:https://developer.here.com/documentation/routing/dev_guide/topics/resource-param-type-routing-mode.html#type-route-feature-weight
「Consumption」就是設定電動車的功耗模型(Consumption Model),這部份屬於比較特殊的需求,您可以設定車輛在不同速度下、上坡與下坡、靜止不動、加速與減速的功耗參數。如果是一般車輛就不需要特別指定。
※ 關於功耗模型參數詳情可見:https://developer.here.com/documentation/routing/dev_guide/topics/resource-param-type-custom-consumption-details.html#type-standard
「Route Time」則是指定路徑的出發時間或抵達時間。可以指定「NOW / 現在出發」、「ANY / 不指定」、「DEPARTURE / 出發時間」、「ARRIVAL / 抵達時間」。
「Advanced Parameters」則是一些更進階的參數,例如符合法規限制的車牌限行、季節性關閉區域、特定車種相關限制等等。一般常用的是「ALTERNATIVE ROUTES
/ 規劃替代路線數量」。
「Avoid Features」指的是迴避特定的道路或區域,您也可以在地圖上畫上希望迴避的區域來規避。
例如在地圖上新增了迴避的區域之後,就會規劃出一個繞路的路徑:
最下方的「EXPORT ROUTE TO XML」可以把您輸入的參數都輸出成 XML 格式的文字檔,之後您可以用「Import Route」這個功能加入這個 XML 檔,就不用重複的輸入相同的參數。
接著來解說「OUTPUT PARAMS / 輸出參數」的部份,這部份的參數不會影響到路徑規劃的結果,但是卻會影響到我們使用 Routing API 回傳結果,因此也需要注意。
「Route attributes」定義的是「整段路徑」的屬性,當然您也可以全部都回傳,但這樣傳輸的時間也會相對拉長。這部份的選項有:
※ 關於路徑回傳參數詳情可見:https://developer.here.com/documentation/routing/dev_guide/topics/resource-type-route.html
另外其他的選項如:
※「Leg attributes」定義的是整段路徑中的分段屬性:https://developer.here.com/documentation/routing/dev_guide/topics/resource-type-route-leg.html
※「Maneuver attributes」定義的是轉彎或轉乘的動作相關的屬性:https://developer.here.com/documentation/routing/dev_guide/topics/resource-type-maneuver.html
※「Link attributes」定義的是每個道路線段的詳細屬性:https://developer.here.com/documentation/routing/dev_guide/topics/resource-type-route-link.html
※「Line attributes」定義的是大眾運輸路線的詳細屬性:https://developer.here.com/documentation/routing/dev_guide/topics/resource-type-public-transport-line.html
※「Json Attributes」可以設定回傳的 JSON 格式:https://developer.here.com/documentation/routing/dev_guide/topics/resource-param-type-json-representation.html
這些您都可以透過一邊使用 HERE Routing API Reference Client 一邊對照文件的方式慢慢熟悉,雖然參數眾多,但是其實用個幾次之後您就會知道自己需要什麼屬性來做出後續的應用。
例如,如果您要把整段路徑畫在地圖上,那麼「shape」就不可少;如果你要把整段路徑的不同分段用不同顏色畫在地圖上,那麼就需要每個「leg」的「shape」;如果您要顯示一個基本的路徑解說,例如距離與時間,那麼整段路徑的「summary」就一定需要;如果你要顯示每個轉彎/轉乘的詳情,那麼就要仔細定義「Maneuver attributes」中的參數。
如果您想要開發的應用程式或是網頁需要包含路徑計算的功能,包括顯示抵達時間或移動所需時間,或是有地圖介面需要顯示路線等,都建議可以先從 HERE Routing API Reference Client 入手,並且使用裡面的 GUI 來調整參數,調整到滿意之後把下方「API CALL」裡面的 URL 複製出來,並且套用在您的應用程式或網頁中,跟一邊看文件一邊手動修改參數比起來,可以大幅的縮短開發時間。
例如下圖就展示了一個使用 Leaflet JS 的地圖框架,結合路徑規劃的功能,把路徑繪製在地圖上,並且顯示路徑的概要,例如路徑長度與需要時間等等。
HERE JavaScript API 也整合了 Routing API 的路徑計算功能,可以算出路徑並繪製在地圖上。
快速建構地圖服務(一) - 認識 HERE Studio / Data Hub
快速建構地圖服務(二) - 認識 HERE Data Hub CLI / API
快速建構地圖服務(三) - 使用 QGIS 玩轉 HERE Data Hub
快速建構地圖服務(四) - 當 Leaflet JS 遇見 Data Hub
快速建構地圖服務(五) - 整合 HERE 地點搜尋 API
快速建構地圖服務(六)- HERE Waypoints Sequence 路徑最佳排序
快速建構地圖服務(七)- 認識 HERE Routing API - 路徑規劃
快速建構地圖服務(八)- 認識 Matrix Routing
快速建構地圖服務(九)- Isoline Routing
快速建構地圖服務(十)- HERE Tour Planning 物流路徑預排與成本精算
快速建構地圖服務(十一)- HERE Route Matching GPS 軌跡分析
快速建構地圖服務(十二)- HERE Custom Locations 地圖資料倉儲與查詢
快速建構地圖服務(十三)- HERE Geofencing 地理圍籬
快速建構地圖服務(十四)- HERE Custom Routes 自建路網 + Vector Tile 向量圖磚 + Map Image API 靜態地圖
快速建構地圖服務(十五)- HERE Positioning 網路定位服務