本文是對參考文章《無人機航線規劃思路剖析,基於凸多邊形地塊往復式運動》算法實現的一個優化,優化內容點:
- 航線間隔的優化
- 航線外擴
注:接下來的內容,請務必掌握參考文章內容的知識點。
航線間隔計算的優化
優化前寫法:
作者使用了一個非常簡單粗暴的寫法,即用多邊形外接矩形計算出最北方向和最南方向的距離,然後除以航線間隔距離,得出規劃航線的數量:
function distance(p1,p2){
/**leaflet提供的方法*/
return L.latLng(p1.lat,p1.lng).distanceTo(L.latLng(p2.lat,p2.lng))
}
/** nw到sw的距離*/
var dist = distance(nw,sw);
/** 得出答案*/
var lines = parseInt(dist / 20)
然後再用最北方向的緯度減去最南方向的緯度,除以已知的航線數量,即可得到每條航線之間的緯度差,以此從上往下計算出每條航線的緯度:
var N=[];
var stepLat=(nw.lat-sw.lat)/lines;
for(var i=0;i<lines;i++){
N.push(nw.lat - i * stepLat)
}
我們可以舉個簡單的例子來表明此方法的弊端,假設北緯與南緯之間的間隔距離爲 100 米,並且要求航線間隔是 30 米,按照上述代碼可計算出 lines = 3,然後再計算出緯度差畫出航線,我們所期望的間隔 30 米,在此平均算法後,實際的每條間隔卻變成了 33.33 米,如圖:
導致了旁向重疊率一直不準確。
優化後寫法
使用方位角算法:已知一點經緯度,方位角,距離,求另一點經緯度。
public static MapLatLng getBearingLatLng(MapLatLng latLng, int distance, double bearing) {
double R = 6371.393 * 1000;
double δ = distance / R;
double θ = toRadius(bearing);
double φ1 = toRadius(latLng.getLatitude());
double λ1 = toRadius(latLng.getLongitude());
double sinφ2 = Math.sin(φ1) * Math.cos(δ) + Math.cos(φ1) * Math.sin(δ) * Math.cos(θ);
double φ2 = Math.asin(sinφ2);
double y = Math.sin(θ) * Math.sin(δ) * Math.cos(φ1);
double x = Math.cos(δ) - Math.sin(φ1) * sinφ2;
double λ2 = λ1 + Math.atan2(y, x);
double lat = toDegree(φ2);
double lng = toDegree(λ2);
return new MapLatLng(lat, lng);
}
private static double toRadius(double value) {
return value * Math.PI / 180;
}
private static double toDegree(double value) {
return value * 180 / Math.PI;
}
具體實現是,以最北緯度爲基準點,在航線間隔距離下,計算出 180 度方向(正北爲0度)的一個點,該點則是第一條航線上的點,然後再通過該點爲基準點,一直反覆計算出下一個點,直到下一個航點的位置小於最南緯度爲止,仍是上述的例子,計算後的航線效果如圖:
航線外擴
航線外擴功能主要是爲了無人機能更好的拍攝地塊邊界,在合成三維模型中有更好的展現。在參考文章中,作者並未對航線的外擴進行實現,我們在分析競品時,可以看見 DJI Pilot 是有該功能的實現的:
具體實現:
仍是利用方位角算法,對航線中的兩點進行向左外擴和向右外擴,示意圖如下:
紅線是我們外擴的距離,該距離爲航線間隔距離即可。我們知道線是由兩點構成的,也即意味着,航點集是一個偶數,那麼我們可以每次以步長爲 2 進行循環遍歷航點集,每次取兩個點進行經度的比較,如果 點1
的經度大於 點2
的經度,那麼 點1
就要向右進行外擴, 點2
就要向左進行外擴,外擴算出來的點需要替換原集合位置的點,以此類推下去,即可實現所有點的外擴,實現效果如下:
參考文章
1、方位角的計算
最後
如果有開發者對無人機相關內容感興趣的話,可以聯繫作者,微信號:codelang94