使用 PHP 和 MySQL 计算地理位置距离
Posted
技术标签:
【中文标题】使用 PHP 和 MySQL 计算地理位置距离【英文标题】:Using PHP and MySQL to calculate geolocation distance 【发布时间】:2012-01-31 17:50:02 【问题描述】:我有一个 php 脚本和一个地理位置数据库。
目前我的用户可以输入他们的邮政编码,使用 Yahaa 我得到他们的地理位置。
现在我有了他们的地理位置,我想编写一个脚本,按距离顺序加载他们的本地业务。我猜要做到这一点,我需要从数据库中加载与用户当前地理位置具有最相似坐标的记录。我试过这段代码:
$sql = "SELECT * FROM dirlistings WHERE ABS(latitude - $lat) AND ABS(longitude - $long)";
但它只是按正常顺序显示结果。
我错过了什么吗?
【问题讨论】:
警告您的代码容易受到 sql 注入攻击。 我正在做类似这样的事情,它存储在家里的电脑中,我现在不在,我可以提供你需要的所有信息。因为地球是一个球体,所以不仅仅是减法。 【参考方案1】:我想你想在某处添加一个ORDER
子句。
但您真正想要的是Haversine 公式:mysql Great Circle Distance (Haversine formula)
【讨论】:
在短距离内(小于约 50 英里),您可以将地球视为一个平面来计算距离(至少在这个域中)。【参考方案2】:这比你想象的要复杂。
这是一篇很棒的文章,对我帮助很大。虽然它是用 javascript 编写的,但您很容易将其更改为 php。
http://www.movable-type.co.uk/scripts/latlong.html
【讨论】:
【参考方案3】:请注意,如果您谈论的是大距离(例如数千英里),则圆距离不够精确,因为地球表面并不平坦。如果您需要一个更好的地理距离计算公式,您可以使用以下公式:
$dlat = ((double)$lat) / 57.29577951;
$dlon = ((double)$lon) / 57.29577951;
$sql = "SELECT *
FROM dirlistings
WHERE 3963.0 * acos(sin(latitude / 57.29577951) * sin($dlat) + cos(latitude / 57.29577951) * cos($dlat) * cos($dlon - longitude / 57.29577951)) < MAX_DIST
ORDER BY acos(sin(latitude / 57.29577951) * sin($dlat) + cos(latitude / 57.29577951) * cos($dlat) * cos($dlon - longitude / 57.29577951))
";
这里的距离以英里为单位 - 确保指定正确的最大距离 - 这个公式将给出非常接近的结果,即使是一万英里的距离。请注意,尽管这样的计算非常耗费时间和功率,如果您不处理大距离(即不超过几百英里),那么您应该使用更快的近似值。
【讨论】:
我已经指定了最大距离并且什么都没有出现? 在这种情况下,我建议您实际检查您的数据。多年来,我们一直在将这个公式与我们的(有效)数据结合使用,并取得了巨大成功。 抱歉,过了一段时间才回复。在一些乱七八糟的情况下,我得到了它的工作。我可以问我应该将 max_dist 设置为什么吗?它只在它处于高值时才有效,当我只寻找最大 40 英里的位置时,该值应该是多少。 如果您正在寻找 40 英里的半径,那么您应该将 max_distance 设置为 40。不过,请确保您在距离测试点 40 英里范围内拥有数据。【参考方案4】:你错过了很多东西。为了做你想做的事,你需要计算(使用勾股定理)两点之间的距离,然后按该距离排序。
您可以通过以下方式计算距离( (lat - $lat)^2 + (lon - $lon)^2 )^0.5
:
SQRT(
POW(latitude - ' . $lat . ',2)
+
POW(longitude - ' . $lon . ',2)
) AS distance
那么就这么简单:
ORDER BY distance ASC
【讨论】:
【参考方案5】:最后尝试ORDER BY latitude, longitude
。应该这样做或差不多这样做。
【讨论】:
我认为这不会有任何用处。排序必须通过使用纬度和经度的公式的结果来完成,而不是分别单独进行。 你完全正确。哇。我已经有几年没有这样做了,我忘记了公式。以上是关于使用 PHP 和 MySQL 计算地理位置距离的主要内容,如果未能解决你的问题,请参考以下文章