2012-07-20 56 views
20

更新2012年11月16日

我想再次提出這個問題,提供一個新的獎勵以獲得一個堅實的,良好的解決方案。看來只有解決方案(shubhansh's answer)現在不能有效工作。我會解釋爲什麼。獲取落在數據庫標記半徑內的結果

首先,這是現場地圖我有半徑和人民,半徑在red和人民都在blue

enter image description here

正如你所看到的,有two人在這個地圖eight半徑,基本上我只得到這是Person A的人,但我沒有得到Person B ,我猜測SQL沒有正確地拾取它,我需要它從人的半徑和標記半徑精確而準確。

它看起來像拾取的是在半徑內,而不是那些重疊半徑,我需要它能夠獲取任何半徑相互重疊的任何結果。

我在尋找一個精確而準確的SQL比shubhansh的答案。您可以閱讀以下內容,瞭解我如何確切地查詢查詢並採集準確的人員。

的數據,PEOPLE

+-----------+-----------+--------+ 
| latitude | longitude | radius | 
+-----------+-----------+--------+ 
| 51.517395 | -0.053129 | 5.6 | 
| 51.506607 | -0.116129 | 0.7 | 
+-----------+-----------+--------+ 

請注意:radius是以千米。

+-----------+-----------+-----+ 
| latitude | longitude | km | 
+-----------+-----------+-----+ 
| 51.502117 | -0.103340 | 0.3 | 
| 51.498913 | -0.120850 | 0.7 | 
| 51.496078 | -0.108919 | 0.7 | 
| 51.496506 | -0.095873 | 0.7 | 
| 51.503399 | -0.090723 | 0.7 | 
| 51.508049 | -0.100336 | 0.7 | 
| 51.508797 | -0.112610 | 0.7 | 
| 51.505535 | -0.125227 | 0.7 | 
| 51.502331 | -0.108061 | 0.7 | 
+-----------+-----------+-----+ 

當前的SQL我使用:

SELECT ppl.latitude, 
     ppl.longitude, 
     ppl.radius 
FROM 
(
    people ppl 
), 
(
    SELECT latitude, longitude 
    FROM radiuses 
) AS radius 
WHERE (POW((ppl.longitude - radius.longitude) * 111.12 * COS(ppl.latitude), 2) + POW((ppl.longitude - radius.longitude) * 111.12, 2)) <= 4 
GROUP BY ppl.id 

數據爲MySQL,你可以用它來測試您的查詢,

INSERT INTO radiuses (id, latitude, longitude, km) VALUES ('1', '51.502117', '-0.103340', '0.3'), ('2', '51.498913', '-0.120850', '0.7'), ('3', '51.496078', '-0.108919', '0.7'), ('4', '51.496506', '-0.095873', '0.7'), ('5', '51.503399', '-0.090723', '0.7'), ('6', '51.508049', '-0.100336', '0.7'), ('7', '51.508797', '-0.112610', '0.7'), ('8', '51.505535', '-0.125227', '0.7'), ('9', '51.502331', '-0.108061', '0.7'); 

INSERT INTO people (id, latitude, longitude, radius) VALUES ('1', '51.517395', '-0.053129', '5.6'), ('2', '51.506607', '-0.116129', '0.7'); 

舊總結

注意:所有的經度和緯度都是隨機產生的。

我有一個地圖applet,用戶可以將他的半徑放置在半徑爲1km的經緯度位置。

現在,還有另一個用戶可以在地圖上的任何位置放置他的半徑,每個半徑1km(與上面的用戶相同)。

像這樣用戶A是紅色並且用戶B是藍色。

enter image description here

基本上用戶A店他半徑中,看起來像這樣的表:

+-----------+---------+-----------+-----------+ 
| radius_id | user_id | latitude | longitude | 
+-----------+---------+-----------+-----------+ 
|   1 |  1 | 81.802117 | -1.110035 | 
|   2 |  1 | 81.798272 | -1.144196 | 
|   3 |  1 | 81.726782 | -1.135919 | 
+-----------+---------+-----------+-----------+ 

而且用戶B店他在另一個表看起來像這樣半徑 - (注:他們每個賬戶只能存儲1個座標):

+---------+-----------+-----------+ 
| user_id | latitude | longitude | 
+---------+-----------+-----------+ 
|  6 | 81.444126 | -1.244910 | 
+---------+-----------+-----------+ 

我希望能夠在地圖圖片中選取落在所定義的半徑範圍內的用戶,即使半徑圓正在觸摸。當AB不需要時,只有標記C才能夠拾取單個半徑。

我相信這是可能的,但我不知道如何在MySQL中想出這種系統。

我在Google Developers網站上發現了它,但它並不僅僅是我需要的功能。

編輯:我已經找到一個更好的,這是非常接近,但仍然不是我要找的,因爲它使用了1約束緯度,當我經度座標在一個表中有多個。

+0

這可能是一個答案,給你一個提示http://stackoverflow.com/questions/11502469/find-records-with-lattitude-and-logintude/11502530#11502530你只是添加一個'WHERE距離<1234'到查詢。 – fdomig 2012-07-24 10:35:13

回答

6

幾何圖形的最重要的一點是,兩個圓重疊的,如果他們的中心之間的距離小於其半徑的總和。由於我們正在做比較,所以我們可以使用距離的平方,因爲這樣可以避免平方根操作。在原來,每一個半徑固定爲1,兩個半徑的總和爲2,和的平方是4

有原來的問題和新問題之間有很大的區別。首先你有固定半徑的圓,第二個你有不同半徑的圓。在比較表達[...distance^2...] <= 4需要恆定4要被替換,因爲這是在原有的固定半徑的假象。要實現此目的,請將km字段添加到查詢中。正如你應該檢查的那樣,你並沒有在WHERE過濾器中使用ppl.radius,所以改變這個值並不會改變你的查詢結果並不奇怪。

SELECT ppl.latitude, ppl.longitude, ppl.radius 
FROM 
    (people ppl), 
    (SELECT latitude, longitude, km FROM radiuses) AS B 
WHERE [...distance^2...] <= POW(ppl.radius + B.km, 2) 

我應該說,這個問題花了更長的時間來了解比它應該有,因爲你調用實體that's - 不一個人一個「半徑」,當你真的有一個對兩個不同實體應該稱之爲「半徑」的財產。所以將其他實體命名爲描述性的。

14

爲了解決這一點,你需要理解圓的方程,它是這樣的 對於任何點(x,y)的下降圈子內的中心(X1,Y1)和半徑R單元是

(x-x1)^2 + (y - y1)^2 <= r^2 

where a^b = a to the power b 

在這裏,在您的情況下用戶B的(緯度,經度)的圓的中心,用戶A的(緯度,經度)是點(X,Y)和半徑= 2千米。

但基本問題是緯度對經度的變化,所以這裏是解,1度= 111.12公里。因此,要保持單位同一方程的兩側,我們將其轉換成公里

所以我們最後的公式變爲:

((x-x1)*111.12)^2 + ((y-y1)*111.12)^2 = 4  (=2^2) 

爲相同的SQL語句應該是這個樣子

SELECT A.user_id, A.radius_id, A.latitude, A.logitude 
FROM UserA AS A, 
    (SELECT user_id, latitude, longitude 
     FROM UserB 
     WHERE user_id = 8) AS B 
WHERE (POW((A.latitude-B.latitude)*111.12, 2) + POW((A.longitude - B.longitude)*111.12, 2)) <= 4 
/* **Edit** Here I have used (A.longitude - B.longitude)*111.12, for more accurate results one can replace it with (A.longitude - B.longitude)*111.12*cos(A.latitude)) or (A.longitude - B.longitude)*111.12*cos(B.latitude)) 

And, as i have suggested in the comments that first filter some records based on approximation, so whether one uses A.latitude or B.latitude it will not make much difference */ 

希望這會有所幫助...

+0

你可以分解出111.12^2。然後用這個數量除以雙方。在哪裏(POW((A.latitude-B.latitude),2)+ POW((A.longitude-B.longitude),2))≤4/(111.12^2)。 – walrii 2012-07-20 22:20:35

+0

@walrii是的,這是可以做到的...... – Shubhansh 2012-07-20 22:23:59

+2

僅在赤道一度= 111.12公里;當你朝着兩極移動時,緯度保持相對恆定,但經度接近零,所以這種解決方案在離赤道更遠的地方會變得越來越不準確。 – 2012-07-20 22:44:59

7

問題的核心是「我怎麼知道兩個圓圈重疊」的問題。答案是「如果他們的中心之間的距離小於他們的半徑之和」。所以你要找的是如何確定兩點之間的距離。

另一個答案是將緯度和經度視爲包含笛卡爾平面。他們不這樣做(當你從赤道接近極點時,經度趨於零)。現在,作爲一個近似值,它可能適用於您的解決方案,取決於解決方案所需的準確度。另一方面,如果你需要這個非常準確,你需要Haversine公式。還有如何實現它在MySQL這裏一個偉大的描述:

http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL

從該演示文稿的幻燈片7,您有以下公式:

3956*2*ASIN(SQRT(POWER(SIN((orig.lat-dest.lat)*pi()/180/2),2)+ 
    COS(orig.lat*pi()/180)*COS(dest.lat*pi()/180)* 
    POWER(SIN((orig.lon-dest.lon)*pi()/180/2),2))) 

注意,第一個數字是平均地球半徑英里;改爲6371公里。

如何使用此計算出的距離將取決於未包含在您的帖子中的詳細信息,例如您正在處理的點數,地理分散程度,任何性能要求以及數據是否爲靜態或不斷更新。

我提到這些事情,因爲性能將是一個問題,特別是如果你有任何數據顯著量和/或它的不斷更新(如基於其手機的GPS數據用戶的位置)。您可以使用性能問題幫助

一種方法是使用方形而不是圓形,並使用一個度=111.12公里的逼近。這樣,您可以自動選擇顯然彼此遠離的任何點。然後,您只需計算Haversine公式只適用於感興趣區域內的少數幾個點。

我希望這是在指點你在正確的方向有幫助。