最新一個小項目,需要用到地圖定義自由區域,並判斷選點是否落在此區域內,思路是通過map的polygons中的points來定義多邊形邊界,通過polygons的fillColor 、 strokeColor、strokeWidth來進行選區顏色的渲染。 然後再通過地圖中心點位的移動來確定需要判斷的選點(因爲小程序地圖目前不支持直接點擊地圖選點獲取座標,只能是觸發一個chooseLocation,而我又不想這麼麻煩用chooseLocation)
最重要的來了,就是這個點位如何判斷是在多邊形裏面或者外面。。。。。其實這就是一個數學問題,經過我多方參考,判斷的數學原理就是:
1、選取目標區域每2個點的y座標y1及y2,如果滿足 y1<y <y2 則記爲有效邊
2、以選取的點爲中心做一條直線, 與上述的有效邊相交,求交點的x值,如果交點的x值大於選取點的x值 ,則記1, 否則記0, 計數全部加起來 ,如果最終得到的計數是單數,則選取點在區域內,如果是雙數,則在區域外
這麼說可能不直觀,我畫幾個圖:
這個屬於所有的點的y值都大於選點的y值,則在區域外,
這個是所有的點的y值都小於選點的y值,也在區域外
這裏滿足y1<y<y2的 有4條邊, 但是滿足多邊形y值大於選點y值的只有3個, 是奇數,所以選點在多邊形區域內
這裏滿足y1<y<y2的 有4條邊,但是滿足多邊形y值大於選點y值的有4個,是偶數,所以選點在多邊形區域外
判斷的函數代碼:
//我這裏用的 x 來判斷 x1<x<x2 用y來判斷相交的點位數 實際上效果一樣
//point爲選取的點座標, polygon爲多邊形的點座標數組
function isPointInPolygon (point, polygon) {
var nCross = 0;
var n = polygon.length
//遍歷多邊形每一條線
for(let i =0 ;i< n;i++){
var p1=polygon[i] //定義第一個點的座標
var p2=polygon[(i+1)%n] //定義下一個點的座標,%n的作用在於讓最後一個點的座標與第一個點座標重合
//如果兩點之間與y軸平行,則進行下一輪循環
if(Number(p1.longitude) == Number(p2.longitude))
continue;
//如果兩點之間的x值都大於選取點的x值 ,則進行下一輪循環
if(Number(point[0]) < Math.min(Number(p1.longitude),Number(p2.longitude)))
continue;
//如果兩點之間的x值都小於或等於選取點的x值 ,則進行下一輪循環
if(Number(point[0]) >=Math.max(Number(p1.longitude),Number(p2.longitude)))
continue;
//如果x1<x<x2 ,且已知x,則通過兩點間直線公式, 算出交點y
var y = (Number(point[0]) - Number(p1.longitude)) *(Number(p2.latitude)-Number(p1.latitude)) / (Number(p2.longitude)-Number(p1.longitude)) + (Number(p1.latitude))
//交點y值大於選點y值 則計數
if (y > Number(point[1]))
nCross ++;
}
//遍歷完了之後求交點y值大於選點y值的數量奇偶,奇數返回true ,偶數返回false
return (nCross%2 === 1)
}
接下來調用此函數, 返回true 就說明選點在多邊形區域內, 否則就是在之外