2011-02-02 13 views
5

me sale latitud y longitud de Google Maps API Reverse-geocodificación y luego necesito algo como esto:¿Cómo medir la distancia usando la fórmula de 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} "; 

} 

ACTUALIZACIÓN no puedo ge que esto funcione

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

¿Qué tan lejos están sus cálculos? ¿Están MUY BIEN o solo un poco fuera? – anon

Respuesta

2

Aquí es la fórmula Yo suelo. Recuerda que la Tierra no es una esfera perfecta, por lo que los resultados nunca serán perfectos.

 
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

Tenga en cuenta que ACOS es numéricamente inestable para puntos que están muy juntos. Consulte http://en.wikipedia.org/wiki/Haversine_formula para obtener una fórmula que evite este problema. – btilly

+0

Bueno saberlo. ¡Gracias! – anon

+1

¡esto da resultados realmente inexactos! – Neo

1

Supongo que está intentando usar http://en.wikipedia.org/wiki/Haversine_formula.

Esta es la ligera a prueba, pero creo que su fórmula debe ser: (. Quité las llamadas 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

Lo usé y muestra al mismo usuario 4708.0 millas de themselve. – Neo

+0

@Neo: He probado esto y me di cuenta de que mis ediciones a la fórmula eran incorrectas. Creo que el error en su fórmula se debe a los abs que estaba haciendo en $ defaultLatitudeColumn. Como resultado, las ubicaciones en el hemisferio sur se comparaban con la ubicación equivalente en el hemisferio norte, que está muy lejos. Lo siento por equivocarte la primera vez. – 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 

Así es como lo uso en 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

Hola Tengo un procedimiento simple que puede usarlo para su trabajo.

El procedimiento es muy simple y calcula la distancia entre dos ciudades. Puede modificarlo en su camino.

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 

Devoluciones millas o KM?

Cuestiones relacionadas