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

发布于 2024-11-16 10:18:59 字数 325 浏览 0 评论 0原文

计划开发一个允许用户指定其位置的 LAMP Web 应用程序。我可以使用 Google Map API 将它们的位置转换为纬度/经度坐标。假设每个用户都有纬度/经度坐标,我该如何执行以下操作:

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

更新: 使用 MySQL 的解决方案:MySQL 大圆距离(半正矢公式)

Planning on developing a LAMP web application that allow users to specify their location. I could possibly use Google Map API to convert their location into lat/long coordinates. Assume each user has lat/long coordinates, how do I do the following:

  • display the distance between 2 users?
  • search for users within a given radius?

UPDATE:
SOLUTION USING MySQL: MySQL Great Circle Distance (Haversine formula)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

被你宠の有点坏 2024-11-23 10:18:59

这是我前几天编写的一个 MySQL 存储函数,用于计算半正矢距离:

在这个问题中:

为什么这个 MySQL 存储函数给出的结果与在查询中进行计算的结果不同?

用法:

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

Here is a MySQL stored function I wrote only the other day to calculate Haversine distance:

In this question:

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

Usage:

SELECT haversine(lat1,lng1,lat2,lng2,units);
甚是思念 2024-11-23 10:18:59

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

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

我不久前创建了一个存储过程,将这个计算实现为 DistanceBetween() 函数,并且运行良好。

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

This could be implemented in a stored procedure or in code depending on the amount of data you will have and the specific situation for your application.

I created a stored proc a while back that implemented this calculation as a DistanceBetween() function and it worked well.

绅刃 2024-11-23 10:18:59

在 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 中看到的那样

In php this is something like

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

I have seen this implemented in sql aswell

小兔几 2024-11-23 10:18:59

您认为您的用户愿意输入他们的邮政编码吗?如果是这样,您可以完全消除 Google Map API,只需查询 mySQL 表即可获取其纬度和经度。我找到了一些免费的邮政编码表(使用谷歌),其中包含纬度、经度值。嗯,实际上它们是 .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;

?>

Do you think your users would be willing to type in their zip code? If so, you can eliminate the Google Map API entirely and just query a mySQL table to get their latitude and longitude. I found a few free zip code tables (using google) that had lat, lon values in them. Well, actually they were .csv files, but mySQL can import them just fine.

Using PHP, you can display the users within a given radius like this. Modify this as you wish.

<?
// 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;

?>
楠木可依 2024-11-23 10:18:59

您可以对第一个要点使用半正矢公式。

寻找给定半径内的用户的第二个问题更有趣一些。这是因为您可能不想对世界上的所有其他用户应用该公式来查看他们是否在您的半径内,因为这将非常耗时。相反,我会使用近似值。

一种近似方法是:

  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 长。会落在我们的半径内,但是用户在 23 lat 处。 43 长。会落在我们的半径之外。

注意:通过提高 n 值,您可以使用此方法获得所需的准确度,但您必须平衡该准确度与您所遭受的性能损失。

You can use the Haversine formula for the first bullet point.

The second issue of finding users within a given radius is a bit more interesting. This is because you probably don't want to apply that formula against every other user in the world to see if they are in your radius or not, as that would be very time-consuming. Instead, I would use an approximation.

One approximation method is to:

  1. Find the maximum-minimum possible latitude points in the radius (make sure to account for the poles). Lets say you end up with 20-30 degrees latitude.
  2. Split that latitude into n parts. Let's say you choose n=4, which would give the latitude ranges of 20-22.5, 22.5-25, 25-27.5, 27.5-30.
  3. For each of these ranges, find the highest and lowest possible longitude values. For example, it might be 45-60 longitude in the 22.5-25 range, and 42-63 longitude in the 25-27.5 latitude range.
  4. Check that the users fall into one of the ranges. For example, a user at 26 lat. 42 lon. would fall in our radius, but a user at 23 lat. 43 lon. would fall outside our radius.

Note: you can get as accurate as you want with this method by making a higher value of n, but you must balance that accuracy against the performance hit you are taking.

滿滿的愛 2024-11-23 10:18:59

如果您使用MySQL 5.7,您可以使用内置函数空间距离: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没有这个功能。

If you are using MySQL 5.7 you can use built-in function Spacial Distance: ST_Distance_Sphere
This way is fastest and most convinient.

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

Example:

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

Please bear in mind that if you are using MariaDB instead of MySQL this function is not available.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文