0

首先,我知道有与此功能相关的问题的答案,我浏览了其中的大部分,我可以找到我正在寻找的答案。我想要做的事情可以很简单地用一张图片来解释:

php距离函数图片图http://stokemandevelopment.com/pictures/image1.JPG

现在让我们为这张图片添加一些叙述。我想要做的是,在 MySQL 中,计算从机场到我数据库中所有机场的距离,如果它们位于半径 A 和半径 B 之间,则将它们添加到我的数组中以在晚点。

function distance($lat1, $lon1, $lat2, $lon2, $unit) {
  $theta = $lon1 - $lon2;
  $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +  cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
  $dist = acos($dist);
  $dist = rad2deg($dist);
  $miles = $dist * 60 * 1.1515;
  $unit = strtoupper($unit);

  if ($unit == "K") {
    return ($miles * 1.609344);
  } else if ($unit == "N") {
     return ($miles * 0.8684);
    } else {
        return $miles;
        }
}

这是我目前用来进行计算的方法,但它是在 php 中,而且速度非常慢。我正在寻找升级代码,以便 mysql 服务器进行计算。我也在尝试在 PHP PDO 中完成这一切。如果有人可以帮助我,将不胜感激。

4

2 回答 2

0

选项1:通过切换到支持GeoIP的数据库或使用MySQL的基本GeoIP功能对数据库进行计算。

选项 2:对数据库进行计算:您使用的是 MySQL,因此以下存储过程应该会有所帮助

CREATE FUNCTION distance (latA double, lonA double, latB double, LonB double)
    RETURNS double DETERMINISTIC
BEGIN
    SET @RlatA = radians(latA);
    SET @RlonA = radians(lonA);
    SET @RlatB = radians(latB);
    SET @RlonB = radians(LonB);
    SET @deltaLat = @RlatA - @RlatB;
    SET @deltaLon = @RlonA - @RlonB;
    SET @d = SIN(@deltaLat/2) * SIN(@deltaLat/2) +
    COS(@RlatA) * COS(@RlatB) * SIN(@deltaLon/2)*SIN(@deltaLon/2);
    RETURN 2 * ASIN(SQRT(@d)) * 6371.01;
END//

如果您的数据库中有纬度和经度索引,您可以通过在 PHP 中计算初始边界框($minLat、$maxLat、$minLong 和 $maxLong)来减少需要计算的计算次数,并限制基于此的条目子集的行(WHERE latitude BETWEEN $minLat AND $maxLat AND longitude BETWEEN $minLong AND $maxLong)。然后 MySQL 只需要为该行子集执行距离计算。

如果您只是使用 skv 提供的 SQL 语句(或存储过程来计算距离),那么 SQL 仍然需要查看数据库中的每条记录,并计算数据库中每条记录的距离,然后才能做出决定是返回该行还是丢弃它。

因为计算执行起来相对较慢,所以最好减少需要计算的行集,消除明显超出所需距离的行,这样我们只执行昂贵的计算行数较少。

考虑到您所做的基本上是在地图上画一个圆,以您的初始点为中心,并以距离为半径;那么公式只是确定哪些行落在该圆圈内......但它仍然必须检查每一行。

使用边界框就像首先在地图上绘制一个正方形,左、右、上和下边缘与我们的中心点相距适当的距离。然后,我们的圆圈将在该框内绘制,圆圈上的最北端、最东端、最南端和最西点与框的边界相接触。有些行会落在该框之外,因此 SQL 甚至不会费心尝试计算这些行的距离。它仅计算落在边界框内的那些行的距离,以查看它们是否也落在圆圈内。

在 PHP 中,我们可以使用一个非常简单的计算,根据我们的距离计算出最小和最大纬度和经度,然后在 SQL 语句的 WHERE 子句中设置这些值。这实际上是我们的盒子,任何超出该盒子的东西都会被自动丢弃,而无需实际计算它的距离。

Movable Type 网站上有一个很好的解释(使用 PHP 代码),对于任何计划在 PHP 中进行任何 GeoPositioning 工作的人来说,这应该是必不可少的阅读材料。

于 2013-09-02T18:43:19.487 回答
0

您可以在机场周围使用六边形网格和螺旋搜索。以下是相邻图块的示例:Optimizing search through large list of lat/long coords to find match

于 2013-09-03T00:34:57.050 回答