设计问题:如何确定多个纬度/长点之间的距离?

时间:2011-06-21 20:41:50

标签: php mysql google-maps

规划开发允许用户指定其位置的LAMP Web应用程序。我可以使用Google Map API将其位置转换为纬度/经度坐标。假设每个用户都有纬度/经度坐标,我该怎么做:

  • 显示2个用户之间的距离?
  • 搜索给定半径范围内的用户?

更新 解决方案使用MySQL:MySQL Great Circle Distance (Haversine formula)

6 个答案:

答案 0 :(得分:1)

http://en.wikipedia.org/wiki/Haversine_formula

这可以在存储过程或代码中实现,具体取决于您将拥有的数据量以及应用程序的具体情况。

我在一段时间后创建了一个存储过程,将此计算实现为DistanceBetween()函数,并且运行良好。

答案 1 :(得分:1)

在php中,这就像

function getDistance($latitude1, $longitude1, $latitude2, $longitude2) {
   $radius = 6371; //For Earth, the mean radius is 6,371.009 km

    $dLat = deg2rad($latitude2 - $latitude1);
    $dLon = deg2rad($longitude2 - $longitude1); 

    $a = sin($dLat/2) * sin($dLat/2) + cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * sin($dLon/2) * sin($dLon/2);

    $c = 2 * asin(sqrt($a));

    $d = $radius * $c; 

    return $d;
}

我已经看到这在sql中实现了

答案 2 :(得分:1)

您认为您的用户愿意输入他们的邮政编码吗?如果是这样,您可以完全删除Google Map API,只需查询mySQL表即可获得其经度和纬度。我找到了一些免费的邮政编码表(使用谷歌),其中包含lat,lon值。好吧,实际上它们是.csv文件,但mySQL可以很好地导入它们。

使用PHP,您可以像这样显示给定半径内的用户。根据需要修改它。

<?
// Define your parameters. Usually, you'd get these from a db or passed in from a form.
$zip = "80233";
$distance = 10; // In miles

// Open up a connection to the poc database
$dbh = mysql_connect ("localhost", "zipcodeDB", "YourDBPassword");
$db = mysql_select_db ("zipcodeDB", $dbh);

// Get the latitude and longitude of the zipcode that was passed
$query = "SELECT * FROM zipcodes WHERE zip=$zip LIMIT 1";
$result = mysql_query($query);
$row = mysql_fetch_object($result);
$knownLat = $row->latitude;
$knownLon = $row->longitude;

// Get a range of latitudes and longitudes to limit the search by 
// so we don't have to search the entire zipcodes table
$latRange = $distance / 69.0499;
$longRange = $distance / (69.0499 * COS(deg2rad($knownLat)));
$latMinRange = $knownLat - $latRange; 
$latMaxRange = $knownLat + $latRange; 
$longMinRange = $knownLon - $longRange; 
$longMaxRange = $knownLon + $longRange; 

// Get all of the users within the passed distance
$query = "SELECT * FROM users 
        JOIN zipcodes ON users.zip=zipcodes.zip 
         AND ((latitude >= $latMinRange AND latitude <= $latMaxRange AND longitude >= $longMinRange AND longitude <= $longMaxRange) AND 
         ((2*3960*ASIN(SQRT(POWER(SIN((RADIANS($knownLat-latitude))/2),2)+COS(RADIANS(latitude))*COS(RADIANS($knownLat))*POWER(SIN((RADIANS($knownLon-longitude))/2),2))))) < $distance)";

$result = mysql_query($query);

// Display the users that are within the set distance
while($row = mysql_fetch_object($result)) {
echo $row->UserName . "<br>";
}

// Close the database
mysql_close($dbh);

exit;

?>

答案 3 :(得分:1)

这是MySQL存储的函数,我前几天只写了计算Haversine距离:

在这个问题中:

Why does this MySQL stored function give different results than to doing the calculation in the query?

用法:

SELECT haversine(lat1,lng1,lat2,lng2,units);

答案 4 :(得分:1)

您可以将Haversine公式用于第一个项目符号点。

在给定半径内查找用户的第二个问题更有趣。这是因为您可能不希望将该公式应用于世界上的每个其他用户,以查看它们是否在您的半径范围内,因为这将非常耗时。相反,我会使用近似值。

一种近似方法是:

  1. 找出半径中最大可能的最小纬度点(确保考虑到极点)。让我们说你最终得到20-30度的纬度。
  2. 将该纬度分成n个部分。假设你选择n = 4,这将给出纬度范围20-22.5,22.5-25,25-27.5,27.5-30。
  3. 对于每个范围,找到最高和最低可能的经度值。例如,在22.5-25范围内可能是45-60经度,在25-27.5纬度范围内可能是42-63经度。
  4. 检查用户是否属于其中一个范围。例如,26 lat的用户。 42 lon。会落在我们的半径范围内,但用户是23 lat。 43 lon。会超出我们的范围。
  5. 注意:通过使用更高的n值,您可以使用此方法获得所需的准确度,但是您必须在准确性与您正在执行的性能影响之间取得平衡。

答案 5 :(得分:0)

如果使用的是MySQL 5.7,则可以使用内置功能Spatial Distance:ST_Distance_Sphere 这样最快,最方便。

https://dev.mysql.com/doc/refman/5.7/en/spatial-convenience-functions.html#function_st-distance-sphere

示例:

SELECT ST_Distance_Sphere( point(lon1, lat1), point(lon2, lat2) )

请记住,如果您使用MariaDB而不是MySQL,则此功能不可用。