2011-02-02 14 views
5

Ho ottenere la latitudine e longitudine da Google Maps Reverse-Geocoding API e quindi ho bisogno di qualcosa di simile:Come misurare la distanza usando la formula di Haversine con MySQL?

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 non posso ge questo lavoro

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

Quanto sono lontani i tuoi calcoli? Stanno via o sono solo un po 'fuori? – anon

risposta

2

Ecco la formula Io uso. Ricorda che la Terra non è una sfera perfetta, quindi i risultati non saranno mai perfetti.

 
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

Nota che ACOS è numericamente instabile per i punti vicini. Vedi http://en.wikipedia.org/wiki/Haversine_formula per una formula che evita questo problema. – btilly

+0

Buono a sapersi. Grazie! – anon

+1

questo dà risultati veramente inaccurati! – Neo

1

Presumo che si sta tentando di utilizzare http://en.wikipedia.org/wiki/Haversine_formula.

Questo è leggermente testato, ma penso che la formula dovrebbe essere: (. Ho rimosso le chiamate 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

Ho usato questo e mostra lo stesso utente 4708.0 miglia di distanza da themselve. – Neo

+0

@Neo: l'ho provato e ho capito che le mie modifiche alla formula erano errate. Credo che l'errore nella tua formula sia dovuto agli addominali che stavi facendo a $ defaultLatitudeColumn. Di conseguenza, le posizioni nell'emisfero sud venivano confrontate con la posizione equivalente nell'emisfero settentrionale, che è molto lontano. Mi dispiace per aver sbagliato la prima volta. – btilly

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 

Ecco come lo uso in 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

Ciao, ho una procedura semplice che puoi usare per il tuo lavoro.

La procedura è molto semplice e calcola la distanza tra due città. Puoi modificarla a modo tuo.

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 

Consegne miglia o KM?

Problemi correlati