2016-08-25 163 views
0

我有一項服務可以從用戶指定的地點查找附近的位置(300米)。獲取經度和緯度的限制

我使用haversine公式檢查一個位置點附近 https://en.wikipedia.org/wiki/Haversine_formula

我的問題是,它是緩慢的,因爲它的檢查,對所有在我的DB之分。

我想要做的是限制初始查詢並將半正定公式應用於較小邊界區域中的點列表 例如,

results = (SELECT * FROM location WHERE location.latitude BETWEEN 14.223 AND 14.5) 
AND location.longitude BETWEEN 121.5 AND 122 

haversine(results, user_point) 

是否有從給定點獲得邊界的鬆散方式? 或基本上經緯度/米長轉換爲米?

回答

1

如果你可以修改你的數據庫結構,有一個超級簡單的方法來做到這一點:代替(或除了)存儲經度和緯度,將你的位置座標轉換爲三維空間,列爲x,y,和以米爲單位的z。那麼你可以做

SELECT * FROM location 
    WHERE location.x BETWEEN center.x - 300 AND center.x + 300 
    AND location.y BETWEEN center.y - 300 AND center.y + 300 
    AND location.z BETWEEN center.z - 300 AND center.z + 300 

這將減少你的清單非常好,你可以對結果集做正弦計算。


如果您堅持使用只有經度和緯度的數據庫,仍然可以縮小搜索範圍。緯度很容易:只要你忽略了當你接近極點時出現的複雜情況,北向或南向的一個緯度總是相當於111公里的距離。這意味着300米的距離爲0.0027 ...緯度,儘管您可能稍微保守一點,使用0.003或0.004。

經度有點棘手,因爲轉換因子根據你的北方或南方有多遠而變化,但它還不算太複雜:你只需乘以緯度的餘弦。

distance = cos(latitude) * 111.19... km/degree * delta_angle 

在赤道上,它和緯度一樣:赤道經度變化一度爲111公里。在北緯80度或南緯80度處,乘以cos(80 degrees) = 0.17...,結果經度1度變化僅爲19.3公里。出於您的目的,您可以將其反轉並找到經度範圍,以選擇300 m/cos(latitude)/(111.19... km/degree) = (0.0027... degrees)/cos(latitude)。該係數與第一段的數量相同;這不是巧合。

棘手的問題出現在座標系的不連續處附近,例如當你靠近兩極時。你可以看到爲什麼當你開始在緯度堵漏像89.9996度:

0.0027... degrees/cos(89.9996 degrees) = 386... degrees 

嘛,怎麼可能當只有360度的整圈?這是一個指標,你已經達到了你的300米半徑一直延伸到杆的位置,並以一種說話的方式回到你的起始位置。那時候,你可能只需要搜索數據庫中所有的點就足夠接近極點。當然,你應該在89.999度左右開始這樣做,因爲那是你正在搜索的地區的600米直徑完全包圍了杆。

還有另一個問題在(國際日期線附近),或者更確切地說是「反經絡」,與經度從-180跳到+180度有關。即使它們在地理上相距僅幾米,但在赤道上的點爲+179.9999度和在-179.9999度處的點將具有非常不同的座標。由於您只是將其作爲初步過濾器進行更詳細的搜索,因此最簡單的方法是穿過反子午線的0.006度(大致爲300米半徑圓的直徑)內的每個點,然後再通過半胱氨酸計算將確定這些點是否確實接近。總結一下,你可以使用上面提到的經度和緯度的界限,只是爲極點和反子午線添加特殊情況。在某種僞SQL /代碼混合的:

IF abs(center.latitude) > 89.999 
    SELECT * FROM location WHERE abs(location.latitude - center.latitude) < 0.003 
ELSE 
    IF abs(center.longitude) > 179.997 
    SELECT * FROM location 
     WHERE abs(location.latitude - center.latitude) < 0.003 
     AND 180 - abs(location.longitude) < (0.006/cos(center.latitude)) 
    ELSE 
    SELECT * FROM location 
     WHERE abs(location.latitude - center.latitude) < 0.003 
     AND abs(location.longitude - center.longitude) < (0.003/cos(center.latitude)) 
    ENDIF 
ENDIF 

如果你想有潛在的測試兩倍多點,你只能比較經度的絕對值爲代價的精闢語句:

SELECT * FROM location 
    WHERE abs(location.latitude - center.latitude) < 0.003 
    AND abs(abs(location.longitude) - abs(center.longitude)) <= min(0.003/cos(center.latitude), 180) 
0

逼近與球體大地,兩個連續的緯度之間的距離可以通過

dPerLat = pi * r/180°, 

其中r是地球的半徑來計算。這將是約111公里。

所以,如果您的參考點是(lat, long)和搜索半徑爲d,那麼你要在範圍內搜索緯度

lat* \in [lat - d/dPerLat, lat + d/dPerLat] 

然後,對於一個給定的緯度,連續經度的距離是:

dPerLong = pi * r * cos(lat)/180° 

同樣,要搜索的經度範圍是+- d/dPerLong。您應該使用給出您保守(最大)範圍的lat值,即具有最高絕對值的lat值。

小心兩極。