電子圍欄內外的判別方法
阿新 • • 發佈:2018-03-20
算法最近公司數據庫因為CPU占用過高卡住了,原因是後臺在服務器中計算司機定位坐標點是否在電子圍欄內。
首先這個功能實現的時候就沒有註意一個原則,計算盡量交給程序,吞吐交給數據庫。所以現在需要將這個功能移出來。
簡單來說 該算法就是判斷一個點是否在一個多邊形內。
我們用回轉數法實現。
平面中的閉合曲線關於一個點的回轉數(又叫卷繞數),代表了曲線繞過該點的總次數。下面這張圖動態演示了回轉數的概念:圖中紅色曲線關於點(人所在位置)的回轉數為 2。
回轉數是拓撲學中的一個基本概念,具有很重要的性質和用途。本文並不打算在這一點上展開論述,這需要具備相當的數學知識,否則會非常乏味和難以理解。我們暫時只需要記住回轉數的一個特性就行了:
當回轉數為 0 時,點在閉合曲線外部。
對於給定的點和多邊形,回轉數應該怎麽計算呢?
首先這個功能實現的時候就沒有註意一個原則,計算盡量交給程序,吞吐交給數據庫。所以現在需要將這個功能移出來。
簡單來說 該算法就是判斷一個點是否在一個多邊形內。
我們用回轉數法實現。
平面中的閉合曲線關於一個點的回轉數(又叫卷繞數),代表了曲線繞過該點的總次數。下面這張圖動態演示了回轉數的概念:圖中紅色曲線關於點(人所在位置)的回轉數為 2。
回轉數是拓撲學中的一個基本概念,具有很重要的性質和用途。本文並不打算在這一點上展開論述,這需要具備相當的數學知識,否則會非常乏味和難以理解。我們暫時只需要記住回轉數的一個特性就行了:
對於給定的點和多邊形,回轉數應該怎麽計算呢?
用線段分別連接點和多邊形的全部頂點。
計算所有點與相鄰頂點連線的夾角。
計算所有夾角和。註意每個夾角都是有方向的,所以有可能是負值。
最後根據角度累加值計算回轉數。看過本文開頭的介紹,很容易理解 360°(2π)相當於一次回轉。```
import json import math lnglatlist = [] data = ‘[{"name":"武漢市三環","points":[{"lng":114.193437,"lat":30.513069},{"lng":114.183376,"lat":30.509211},{"lng":114.188191,"lat":30.505291},{"lng":114.187975,"lat":30.504731},{"lng":114.201773,"lat":30.492782},{"lng":114.213559,"lat":30.48855},{"lng":114.239143,"lat":30.484006},{"lng":114.248341,"lat":30.470062},{"lng":114.267888,"lat":30.470062},{"lng":114.286286,"lat":30.46309},{"lng":114.294335,"lat":30.459105},{"lng":114.298934,"lat":30.459105},{"lng":114.305833,"lat":30.459105},{"lng":114.341478,"lat":30.453128},{"lng":114.422613,"lat":30.462591},{"lng":114.424337,"lat":30.453688},{"lng":114.444316,"lat":30.456303},{"lng":114.466809,"lat":30.466078},{"lng":114.473708,"lat":30.549713},{"lng":114.443813,"lat":30.624326},{"lng":114.407593,"lat":30.683478},{"lng":114.388621,"lat":30.703352},{"lng":114.3616,"lat":30.704843},{"lng":114.311582,"lat":30.678466999999998},{"lng":114.241442,"lat":30.64123},{"lng":114.201773,"lat":30.63079},{"lng":114.182226,"lat":30.63427},{"lng":114.165553,"lat":30.626812},{"lng":114.162679,"lat":30.6109},{"lng":114.170153,"lat":30.59598},{"lng":114.167853,"lat":30.552201},{"lng":114.179351,"lat":30.529309}],"type":0}]‘ data = json.loads(data) if ‘points‘ in data[0]: for point in data[0][‘points‘]: #print(str(point[‘lng‘])+" "+str(point[‘lat‘])) lnglat = [] lnglat.append(float(str(point[‘lng‘]))) lnglat.append(float(str(point[‘lat‘]))) lnglatlist.append(lnglat) def windingNumber(point, poly): poly.append(poly[0]) px = point[0] py = point[1] sum = 0 length = len(poly)-1 for index in range(0,length): sx = poly[index][0] sy = poly[index][1] tx = poly[index+1][0] ty = poly[index+1][1] #點與多邊形頂點重合或在多邊形的邊上 if((sx - px) * (px - tx) >= 0 and (sy - py) * (py - ty) >= 0 and (px - sx) * (ty - sy) == (py - sy) * (tx - sx)): return "on" #點與相鄰頂點連線的夾角 angle = math.atan2(sy - py, sx - px) - math.atan2(ty - py, tx - px) #確保夾角不超出取值範圍(-π 到 π) if(angle >= math.pi): angle = angle - math.pi * 2 elif(angle <= -math.pi): angle = angle + math.pi * 2 sum += angle #計算回轉數並判斷點和多邊形的幾何關系 result = ‘out‘ if int(sum / math.pi) == 0 else ‘in‘ return result point = [113.970082,30.672545] print(windingNumber(point,lnglatlist))
電子圍欄內外的判別方法