2011-02-02 62 views
5

我從谷歌地圖反向地理編碼API獲得緯度和經度,然後我需要的是這樣的:如何用MySQL的Haversine公式測量距離?

mysql_query("SELECT users.*, ".mysql_distance_column($lat,$lng)." FROM users ORDER BY DISTANCE"; 

function mysql_distance_column($lat=40 , $lng=-73) { 

    $defaultLatitudeColumn = 'user_lat'; 
    $defaultLongitudeColumn='user_lng'; 
    $defaultColumnName='user_distance'; 
    return "(( 
(3956 * 2 * ASIN(SQRT(POWER(SIN(({$lat} - abs({$defaultLatitudeColumn})) 
* pi()/180/2), 2) + COS({$lat} * pi()/180) 
* COS(abs({$defaultLatitudeColumn}) * pi()/180) 
* POWER(SIN(({$lng} - {$defaultLongitudeColumn}) * pi()/180/2), 2))) 
))) as {$defaultColumnName} "; 

} 

UPDATE 我不能GE這個工作

delimiter // 
CREATE FUNCTION `GeoDistMiles`(lat1 FLOAT (10,6), lon1 FLOAT (10,6), lat2 FLOAT (10,6), lon2 FLOAT (10,6)) 
RETURNS FLOAT 
DETERMINISTIC 
NO SQL 
BEGIN 
    DECLARE pi, q1, q2, q3 FLOAT (10,6); 
    DECLARE rads FLOAT (10,6) DEFAULT 0; 
    SET pi = PI(); 
    SET lat1 = lat1 * pi/180; 
    SET lon1 = lon1 * pi/180; 
    SET lat2 = lat2 * pi/180; 
    SET lon2 = lon2 * pi/180; 
    SET q1 = COS(lon1-lon2); 
    SET q2 = COS(lat1-lat2); 
    SET q3 = COS(lat1+lat2); 
    SET rads = ACOS(0.5*((1.0+q1)*q2 - (1.0-q1)*q3)); 
    RETURN 3963.346 * rads; 
END 
+1

你的計算有多遠?他們是走了還是稍微離開一點? – anon 2011-02-02 18:39:45

回答

2

這裏是公式我用。請記住,地球不是一個完美的領域,所以結果永遠不會是完美的。

 
CREATE DEFINER=`root`@`localhost` FUNCTION `GeoDistMiles`(lat1 FLOAT, lon1 FLOAT, lat2 FLOAT, lon2 FLOAT) RETURNS float 
BEGIN 
    DECLARE pi, q1, q2, q3 FLOAT; 
    DECLARE rads FLOAT DEFAULT 0; 
    SET pi = PI(); 
    SET lat1 = lat1 * pi/180; 
    SET lon1 = lon1 * pi/180; 
    SET lat2 = lat2 * pi/180; 
    SET lon2 = lon2 * pi/180; 
    SET q1 = COS(lon1-lon2); 
    SET q2 = COS(lat1-lat2); 
    SET q3 = COS(lat1+lat2); 
    SET rads = ACOS(0.5*((1.0+q1)*q2 - (1.0-q1)*q3)); 
    RETURN 3963.346 * rads; 
END 
+2

請注意,對於靠近在一起的點,ACOS在數值上不穩定。請參閱http://en.wikipedia.org/wiki/Haversine_formula,以獲取避免此問題的公式。 – btilly 2011-02-02 18:49:33

+0

很高興知道。謝謝! – anon 2011-02-02 18:56:15

1

我假定您正在嘗試使用http://en.wikipedia.org/wiki/Haversine_formula

這是輕輕地測試,但我認爲你的公式應該是:(我去掉了ABS話費)

(ROUND((3956 * 2 * ASIN(SQRT(POWER(SIN(({$lat} - {$defaultLatitudeColumn}) * pi()/180/2), 2) + COS({$lat} * pi()/180) * COS({$defaultLatitudeColumn} * pi()/180) *POWER(SIN(({$lng} - {$defaultLongitudeColumn}) * pi()/180/2), 2))))*{$magicNumber}))/{$magicNumber} 

0
SELECT ACOS(COS(RADIANS(lat)) * 
COS(RADIANS(lon)) * COS(RADIANS(34.7405350)) * COS(RADIANS(-92.3245120)) + 
COS(RADIANS(lat)) * SIN(RADIANS(lon)) * COS(RADIANS(34.7405350)) * 
SIN(RADIANS(-92.3245120)) + SIN(RADIANS(lat)) * SIN(RADIANS(34.7405350))) * 
3963.1 AS Distance 
FROM Stores 
WHERE 1 
HAVING Distance <= 50 

下面是我如何使用它在PHP:

// Find rows in Stores within 50 miles of $lat,$lon 
$lat = '34.7405350'; 
$lon = '-92.3245120'; 

$sql = "SELECT Stores.*, ACOS(COS(RADIANS(lat)) * 
COS(RADIANS(lon)) * COS(RADIANS($lat)) * COS(RADIANS($lon)) + 
COS(RADIANS(lat)) * SIN(RADIANS(lon)) * COS(RADIANS($lat)) * 
SIN(RADIANS($lon)) + SIN(RADIANS(lat)) * SIN(RADIANS($lat))) * 
3963.1 AS Distance 
FROM Stores 
WHERE 1 
HAVING Distance <= 50"; 
1

嗨我有一個簡單的程序,您可以使用它爲您的工作。

程序非常簡單,可以計算出兩個城市之間的距離,你可以用自己的方式進行修改。

drop procedure if exists select_lattitude_longitude; 


delimiter // 

create procedure select_lattitude_longitude(In CityName1 varchar(20) , In CityName2 varchar(20)) 

begin 

declare origin_lat float(10,2); 

declare origin_long float(10,2); 

declare dest_lat float(10,2); 

declare dest_long float(10,2); 

if CityName1 Not In (select Name from City_lat_lon) OR CityName2 Not In (select Name from City_lat_lon) then 

select 'The Name Not Exist or Not Valid Please Check the Names given by you' as Message; 


else 

select lattitude into origin_lat from City_lat_lon where Name=CityName1; 

select longitude into origin_long from City_lat_lon where Name=CityName1; 

select lattitude into dest_lat from City_lat_lon where Name=CityName2; 

select longitude into dest_long from City_lat_lon where Name=CityName2; 


select origin_lat as CityName1_lattitude, 
origin_long as CityName1_longitude, 
dest_lat as CityName2_lattitude, 
dest_long as CityName2_longitude; 


SELECT 3956 * 2 * ASIN(SQRT(POWER(SIN((origin_lat - dest_lat) * pi()/180/2), 2) + COS(origin_lat * pi()/180) * COS(dest_lat * pi()/180) * POWER(SIN((origin_long-dest_long) * pi()/180/2), 2))) * 1.609344 as Distance_In_Kms ; 


end if; 

end ; 

// 

delimiter ; 
0
3956 * 2 * ASIN(SQRT(POWER(SIN(($latitude -(cp.latitude)) * pi()/180/2),2) + COS($latitude * pi()/180) * COS(abs(cp.latitude) * pi()/180) * POWER(SIN(($longitude - cp.longitude) * pi()/180/2), 2))) as distance 

返回英里或公里?