python判斷一點是否在帶孔複雜多邊形內部

剛剛入職的小萌新,成長的艱辛之路讓我都睡不安穩,做夢都是工作,尤其是我這種剛剛出了校門沒一點工作經驗,說白了就是菜,上週三接到了bug,背景什麼的就不介紹了。直接上圖

其實看圖大家就明白了,這個多邊形有多複雜,不僅有凸又有凹,而且內部還被挖空,在網上我翻了很久的帖子,大家處理的方法都不錯,但是都只限定與一個沒有被挖空的多邊形,也就是困擾了我許久的問題, 在對問題了解清晰之後,將問題簡化,其實就是判斷一個點是否在多邊形內的過程,途中這個點在程序運行後返回的結果是在多邊形內,這肉眼可見的錯誤。

使用python的好處就是python的封裝功能的強大(其實我還不太會,在接到這個項目之前沒用過python,只聽過他的大名)拿到項目的時候代碼量真的不大,但是我看代碼就需要了差不多兩天,因爲所有的功能都被封裝到一個庫中,幾乎每一個函數都需要自己百度,而且有的經過了層層的封裝。

此多邊形是提取的svg的path,svg的path都爲閉合的,具體的參數大家可以查看svg的官方文檔,在閉合路徑的path中要判斷一點是否在多邊形內外,首先就要把path提取爲多邊形,直接調用的svg第三方庫,提取的多邊形我們設置的步進越短效果越好,步進越大可能就有部分的失真,但是此處步進的大小也影響着後面的效率,我們提取的多邊形頂點越多在後期測試的時候時間會越久。

在進行具體的判斷的時候有很多的方法,大多數的方法都是支持凸多邊形,相對於凸多邊形,凹多邊形就比較複雜,此項目之前使用的方法是

shapely.geometry
 polygon.contains()

此方法是python中的第三方庫,具體的方法我也沒太看懂,但是我們的問題都出現在了複雜路徑並且有問題的都是凹多邊形,後來查資料此庫封裝的方法不適合凹多邊形,因此開始採用射線法進行試驗,找到一個寫的很好的博客,https://www.jianshu.com/p/ba03c600a557

大家看了此文章就應該明白射線法的原理以及簡單的應用,但是實際的項目中總是會有在簡單之外的,在我加上上面的代碼後,檢查那個點的時候居然還是在多邊形內,頭疼了,

射線法以及排除了儘可能多的可能出問題的情景,爲什麼還是判斷錯,這時候就需要從結果推斷原因,既然是畫射線, 就找到它與多邊形的交點,首先獲取它與多邊形的交點個數, 

在圖中的位置居然有五個交點,出乎意料,自己動手畫,可能都不會有五個交點,如果有五個必定是過某個頂點,然而過頂點的情況在下面的代碼中扣掉了。

def isRayIntersectsSegment(poi,s_poi,e_poi): #[x,y] [lng,lat]
    #輸入:判斷點,邊起點,邊終點,都是[lng,lat]格式數組
    if s_poi[1]==e_poi[1]: #排除與射線平行、重合,線段首尾端點重合的情況
        return False
    if s_poi[1]>poi[1] and e_poi[1]>poi[1]: #線段在射線上邊
        return False
    if s_poi[1]<poi[1] and e_poi[1]<poi[1]: #線段在射線下邊
        return False
    if s_poi[1]==poi[1] and e_poi[1]>poi[1]: #交點爲下端點,對應spoint
        return False
    if e_poi[1]==poi[1] and s_poi[1]>poi[1]: #交點爲下端點,對應epoint
        return False
    if s_poi[0]<poi[0] and e_poi[1]<poi[1]: #線段在射線左邊
        return False

    xseg=e_poi[0]-(e_poi[0]-s_poi[0])*(e_poi[1]-poi[1])/(e_poi[1]-s_poi[1]) #求交
    if xseg<poi[0]: #交點在射線起點的左側
        return False
    return True  #排除上述情況之後

 接下來就需要你自己親自去看一下它是怎麼能交到五個點的,,一番努力之後,看到五個點後下巴都驚掉了,放圖嚇嚇你們

 

 看到途中的五個點(最左的是起始點),驚爲天人的操作,這時候就要思考爲什麼出現上圖的情況,左邊的二三點,是怎麼交出來的。交點的計算是通過相似三角形的原理,需要兩個端點的座標進行計算,

xseg = e_poi[0] - (e_poi[0] - s_poi[0]) * (e_poi[1] - poi[1]) / (e_poi[1] - s_poi[1])  # 求交

因此在進一步看看是哪兩個端點惹的禍。

 

 其實看到這裏,大家應該明白了我的主題,對於封閉多邊形,概念侷限了我們的思維,圖中的特點是一個有凹有凸的複雜多邊形的內部是鏤空的,此時大家會說射線法是滿足要求的,的確是,但是計算機並不是這麼想,主要問題還是出現在path中,對於這兩個鏤空的路徑的端點是挨着的,在進行 交點計算的時候,在計算相鄰的挨着的兩個端點,也就是上圖中的情況,因此左三的交點就這樣得到了,大家能想到什麼好的辦法解決嗎?我目前雖說解決了,但是感覺不是最說的通的,感覺會有些特例能夠推翻,希望大家能夠踊躍的發言哦。下面是我處理後的效果

效果還是棒棒噠,感覺鬆了一口氣,這樣的感覺真棒,雖然很累 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章