PHP MySql 和地理定位
我正在编写一个网站,基本上使用 php 和 mysql 查找纬度和经度 25 英里半径内的地方。
我想知道这样的事情是如何运作的?
我会将纬度和经度传递给票据,并让它从我的位置数据库中仅提取纬度和经度 25 英里以内的位置。
最好的方法是什么?
编辑: 我发现这个代码用于计算两点之间的距离。
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;
}
}
有没有办法在 MYSQL 查找中执行此计算,这样我只能在 Miles =< 时返回25?
I am writing a site that basically looks for places within a 25 mile radius of a lat and long using php and mysql.
I am wondering how something like this would work?
I would pass a lat and long to the scrip and have it pull out only locations that are within 25 miles of the lat and long from my Database of locations.
What is the best way to do this?
EDIT:
I found this code for calculating the distance between 2 points.
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;
}
}
Is ther a way to do this calc in the MYSQL look up so I can only return if miles =< 25?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
使用该函数计算距离的计算成本相当高,因为它涉及一大堆超越函数。当您有大量的行需要过滤时,这将会出现问题。
这是一种替代方案,一种计算成本较低的近似值:
以英里为单位的近似距离:
您可以通过添加余弦数学函数来提高此近似距离计算的准确性:
改进以英里为单位的近似距离:
来源:http://www.meridianworlddata.com/Distance-Calculation.asp
我使用随机生成的数据集进行了一系列测试。
绝对不值得。只需进行近似即可。
代码在这里: http://pastebin.org/424186
要在 MySQL 上使用它,请创建一个 存储过程接受坐标参数并返回距离,那么你可以做类似的事情:
Calculating the distance using that function there is pretty computationally expensive, because it involves a whole bunch of transcendental functions. This is going to be problematic when you have a large number of rows to filter on.
Here's an alternative, an approximation that's way less computationally expensive:
Approximate distance in miles:
You can improve the accuracy of this approximate distance calculation by adding the cosine math function:
Improved approximate distance in miles:
Source: http://www.meridianworlddata.com/Distance-Calculation.asp
I ran a bunch of tests with randomly generated datasets.
Definitely not worth it. Just go with an approximation.
Code is here: http://pastebin.org/424186
To use this on MySQL, create a stored procedure that takes coordinate arguments and returns the distance, then you can do something like:
您可能想看看此解决方案 - 一个有点聪明的解决方法。
You may want to take a look at this solution - a somewhat brilliat workaround.
您只需两步即可轻松完成:
查找该点各个方向 25 英里范围内的所有位置。这看起来像:
WHERE lat BETWEEN $lat1 AND $lat2 AND lng BETWEEN $lng1 AND $lng2
然后循环遍历每个结果并使用您的代码检查它是否确实在 25 英里之内。 (即,过滤掉正方形角落中的那些位置。)
对于第一部分,这是我放置的一些代码(不记得来源):
基本上只使用
($lat - $lat_range 、$lat + $lat_range)
和($lng - $lng_range, $lng + $lng_range)
半径以英里为单位。显然你可以稍微清理一下数学。
编辑:我忘了提到,如果您需要支持赤道、国际日期变更线等附近的位置,则需要稍微调整一下。显然对于北美来说,按原样就可以了。
You can do it easily in two steps:
Find all locations within 25 miles in each direction of the point. This will look like:
WHERE lat BETWEEN $lat1 AND $lat2 AND lng BETWEEN $lng1 AND $lng2
Then loop through each result and check to see if it really is within 25 miles using your code. (i.e., Filter out those locations that are in the corners of the square.)
For the first part, here's some code I have laying around (don't remember the source):
Basically just use
($lat - $lat_range, $lat + $lat_range)
and($lng - $lng_range, $lng + $lng_range)
Radius is in miles.Obviously you can clean up the math a bit.
Edit: I forgot to mention that you would need to tweak it a bit if you need to support locations near the equator, international date line, etc. Obviously for North America, it would be fine as-is.