地理圍欄算法解析(Geo-fencing) 深刻淺出空間索引:2 GeoHash核心原理解析

     地理圍欄算法解析

      http://www.cnblogs.com/LBSer/p/4471742.htmlhtml

      地理圍欄(Geo-fencing)是LBS的一種應用,就是用一個虛擬的柵欄圍出一個虛擬地理邊界,當手機進入、離開某個特定地理區域,或在該區域內活動時,手機能夠接收自動通知和警告。以下圖所示,假設地圖上有三個商場,當用戶進入某個商場的時候,手機自動收到相應商場發送的優惠券push消息。地理圍欄應用很是普遍,當今移動互聯網主要app如美團、大衆點評、手淘等均可看到其應用身影。python

圖1 地理圍欄示意圖git

 

       地理圍欄的核心問題就是判斷用戶是否落在某多邊形圍欄內部。本文將介紹實際應用中經常使用的解決方法。github

1 如何判斷點在多邊形內部

      地理圍欄通常是多邊形,如何判斷點在多邊形內部呢?能夠經過射線法來判斷點是否在多邊形內部。以下圖所示,從該點出發沿着X軸畫一條射線,依次判斷該射線與每條邊的交點,並統計交點個數,若是交點數爲奇數,則在多邊形內部(如圖3個交點),若是焦點數是偶數,則在外部,射線法對凸和非凸多邊形都適用,複雜度爲O(N),其它N是邊數。源碼可參考(http://alienryderflex.com/polygon/算法

圖2 射線法判斷點在多邊形內外app

     

       當地理圍欄多邊形數目較少時,咱們能夠依次遍歷每個多邊形(暴力遍歷法),而後用射線法進行判斷,這樣效率也很高。而當多邊形數目較多時,好比有10萬個多邊形,這個時候須要執行10萬次射線法,響應時間達到3.9秒,這在互聯網應用幾乎不可忍受。下表是本人的簡單測試,多邊形邊數均爲7。post

表1 射線法性能測試性能

 

2 R樹索引加速判斷

       暴力遍歷法效率低下的緣由是與每個多邊形都進行了射線法判斷,若是能減小射線法的調用次數性能就能提高。所以咱們的優化思路很直接,首先經過粗篩的方法快速找到符合條件的少許多邊形,而後對粗篩後的多邊形使用射線法判斷,這樣射線法的執行次數大大下降,效率也能大大提升。怎麼粗篩呢?對於一維數據咱們經常使用索引的方法,好比經過B樹索引找到某一個範圍區間段,而後對此範圍區間段進行遍歷查找,對於二維空間數據經常使用空間索引的方法,好比經過R樹找到範圍區間內的多邊形,而後對此範圍內的多邊形進行精確判斷,下面介紹最常使用的空間索引R樹的解決思路。測試

       1)外包矩形表示多邊形

       因爲多邊形形狀各異,咱們須要以一種統一的方式來對多邊形進行近似,最簡單的方式就是用最小外包矩形來表示多邊形。flex

圖3 最小外包矩形(MBR)表達多邊形

 

      2)對最小外包矩形創建R樹索引

 

圖4 對最小外包矩形進行R樹索引

 

        3)查詢

          a)首先經過R樹迅速判斷用戶所在位置(粗紅點)是否被外包矩形覆蓋(圖5,紅色點表明用戶所在位置;R樹平均查詢複雜度爲O(Log(N)),N爲多邊形個數);

          b)若是不被任何外包矩形覆蓋則返回不在地理圍欄多邊形內;

          c)若是被外包矩形覆蓋則還須要進一步判斷是否在此外包矩形的多邊形內部,採用上文提到的射線法判斷(圖2)。

圖5 R樹查詢示例

3 多邊形邊數較多怎麼辦

       大多數應用的地理圍欄多邊形都比較簡單,但有時也會遇到一些特別複雜的多邊形,好比單個多邊形的邊數就超過十幾萬條,這時候對此複雜多邊形執行一次射線法也很是耗時(由於射線法時間複雜度爲O(N),N爲多邊形邊數)。

       如何提升對複雜多邊形執行射線法的計算效率呢?一樣使用R樹索引!筆者在實際應用中對邊數較多(如超過1萬)的多邊形的邊再單獨進行R樹索引,具體如圖6所示,首先對多邊形的每條邊構建最小外包矩形,而後在這些最小外包矩形基礎上構建R樹索引(R樹索引上的外包矩形未畫出),這樣射線法求交點的時候首先經過R樹判斷射線是否與外包矩形相交,最後對R樹粗篩後的邊進行精確求交判斷,時間複雜度從O(N)降到O(Log(N)),大大提升了計算效率。

圖6 對多邊形的邊進行R樹索引

4 實踐

      某線上應用服務有30萬個地理圍欄多邊形,經過在內存中構建R樹索引,使得線上實時地理圍欄查詢平均響應時間在1ms之內,而暴力查詢響應時間是9秒左右。

      

5 R樹相關源碼

https://pypi.python.org/pypi/Rtree/ (Python)

http://jsi.sourceforge.net/ (Java)

https://github.com/leaflet-extras/RTree (Javascript)

http://sourceforge.net/p/cspatialindexrt/code/HEAD/tree/ (C#)

 

空間索引相關博文:

深刻淺出空間索引:爲何須要空間索引

深刻淺出空間索引:2

GeoHash核心原理解析

相關文章
相關標籤/搜索