【问题标题】:How to measure distance using Haversine formula with MySQL?如何使用带有 MySQL 的 Haversine 公式测量距离?
【发布时间】:2011-06-20 04:25:57
【问题描述】:

我从 Google Maps Reverse-Geocoding API 获得纬度和经度,然后我需要这样的东西:

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} ";

}

更新 我不能让这个工作

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

【问题讨论】:

  • 您的计算距离有多远?它们是偏离了还是偏离了一点点?

标签: mysql sql geometry distance haversine


【解决方案1】:

这是我使用的公式。请记住,地球不是一个完美的球体,因此结果永远不会是完美的。

CREATE DEFINER=`root`@`localhost` FUNCTION `GeoDistMiles`( lat1 FLOAT, lon1 FLOAT, lat2 FLOAT, lon2 FLOAT ) 返回 float 开始 声明 pi, q1, q2, q3 浮点数; DECLARE rads FLOAT DEFAULT 0; 设置 pi = PI(); SET lat1 = lat1 * pi / 180; 设置 lon1 = lon1 * pi / 180; 设置 lat2 = lat2 * pi / 180; 设置 lon2 = lon2 * pi / 180; 设置 q1 = COS(lon1-lon2); SET q2 = COS(lat1-lat2); SET q3 = COS(lat1+lat2); 设置弧度 = ACOS( 0.5*((1.0+q1)*q2 - (1.0-q1)*q3) ); 返回 3963.346 * 弧度; 结尾

【讨论】:

【解决方案2】:

我假设您正在尝试使用http://en.wikipedia.org/wiki/Haversine_formula

这是经过轻微测试的,但我认为您的公式应该是:

(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}

(我删除了 abs 调用。)

【讨论】:

  • 我用过这个,它显示同一个用户离他们自己 4708.0 英里。
  • @Neo:我已经对此进行了测试,并意识到我对公式的编辑不正确。我相信您的公式中的错误是由于您对 $defaultLatitudeColumn 所做的绝对值。结果,南半球的位置与北半球的同等位置进行了比较,这相距甚远。很抱歉第一次弄错了。
【解决方案3】:

您好,我有一个简单的程序,您可以将其用于您的工作。

程序很简单,计算两个城市之间的距离。你可以按自己的方式修改。

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 ;

【讨论】:

    【解决方案4】:
    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";
    

    【讨论】:

      【解决方案5】:
      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
      

      返回里程或公里?

      【讨论】:

        猜你喜欢
        • 2010-10-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多