Hay我希望使用lat和long值找到2个位置之间的距离(以英里为单位),并检查它们是否在彼此相差10英里的范围内。
当用户登录时,他们的纬度/经度值将保存在会话中
$_SESSION['lat']
$_SESSION['long']
我有两个功能
这个以英里计算距离并返回舍入值
function distance($lat1, $lng1, $lat2, $lng2){
$pi80 = M_PI / 180;
$lat1 *= $pi80;
$lng1 *= $pi80;
$lat2 *= $pi80;
$lng2 *= $pi80;
$r = 6372.797; // mean radius of Earth in km
$dlat = $lat2 - $lat1;
$dlng = $lng2 - $lng1;
$a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlng / 2) * sin($dlng / 2);
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
$km = $r * $c;
return floor($km * 0.621371192);
}
如果两组lat和long之间的距离小于10,则返回bool。
function is_within_10_miles($lat1, $lng1, $lat2, $lng2){
$d = distance($lat1, $lng1, $lat2, $lng2);
if( $d <= 10 ){
return True;
}else{
return False;
}
}
两个函数都按预期工作,如果我给出两组纬度/长度并且它们之间的距离是20英里,我的is_within_10_miles()函数返回false。
现在,我有一个'locations'数据库(4个字段--ID,name,lat,long)。
我想找到半径10英里范围内的所有位置。
有什么想法吗?
编辑:我可以循环遍历所有并在其上执行is_within_10_miles()
$query = "SELECT * FROM `locations`";
$result = mysql_query($query);
while($location = mysql_fetch_assoc($result)){
echo $location['name']." is ";
echo distance($lat2, $lon2, $location['lat'], $location['lon']);
echo " miles form your house, is it with a 10 mile radius? ";
if( is_within_10_miles($lat2, $lon2, $location['lat'], $location['lon']) ){
echo "yeah";
}else{
echo "no";
}
echo "<br>";
}
示例结果将是
goodison park is 7 miles form your house, is it with a 10 mile radius? yeah
我需要以某种方式在我的查询中执行is_within_10_miles函数。
编辑编辑
http://www.zcentric.com/blog/2007/03/calculate_distance_in_mysql_wi.html的这个传说提出了这个......
SELECT ((ACOS(SIN($lat * PI() / 180) * SIN(lat * PI() / 180) + COS($lat * PI() / 180) * COS(lat * PI() / 180) * COS(($lon - lon) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS distance FROM members HAVING distance<='10' ORDER BY distance ASC
它确实有效。问题是我想选择*行,而不是逐个选择它们。我该怎么做?
答案 0 :(得分:12)
您可能不需要在代码中执行此操作,您可以在数据库中执行此操作。如果您使用spatial index。 MySQL docuemtnation for spatial index
编辑以反映您的修改:
我想你想要这样的东西:
SELECT *, ((ACOS(SIN($lat * PI() / 180) * SIN(lat * PI() / 180) + COS($lat * PI() / 180) * COS(lat * PI() / 180) * COS(($lon - lon) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS distance FROM locations HAVING distance<='10' ORDER BY distance ASC
VIA: http://www.zcentric.com/blog/2007/03/calculate_distance_in_mysql_wi.html:
答案 1 :(得分:1)
在查询之前,计算十英里圆圈的最大和最小纬度和经度。这将给你四个数字,所以你的where子句的第一部分将排除任何超出大约10英里 - 每个方框的行。
然后复杂的实际距离where子句只检查广场内的那些,看看它们是否也在圆圈内。
阅读您的DBMS文档,了解是否会应用延迟评估,或者您是否需要将其安排为
SELECT *
FROM (SELECT *
FROM table
WHERE (simple rough box clause)
)
WHERE (complex clause)
而不是通常的
SELECT * FROM table WHERE (simple clause) AND (complex clause)
答案 2 :(得分:0)
以KM搜索:($LATITUDE
->纬度$LONGITUDE
->经度latitud_fieldname
->纬度数据库字段名称{{1 }}->您的经度数据库字段名)
longitude_fieldname
英里搜索:
SELECT * FROM (
SELECT *,
(
(
(
acos(
sin(( $LATITUDE * pi() / 180))
*
sin(( `latitud_fieldname` * pi() / 180)) + cos(( $LATITUDE * pi() /180 ))
*
cos(( `latitud_fieldname` * pi() / 180)) * cos((( $LONGITUDE - `longitude_fieldname`) * pi()/180)))
) * 180/pi()
) * 60 * 1.1515 * 1.609344
)
as distance FROM `myTable`
) myTable
WHERE distance <= $DISTANCE_KILOMETERS;
答案 3 :(得分:-1)
这应该指向正确的方向 - 没有双关语。
使用lat / long
查找两个地方之间距离的Mysql函数有时我们需要找到距离中心位置在某个半径范围内的地点列表,其中地点坐标保存在数据库中。现在我们有两个解决方案 - 循环遍历所有位置找到距离中心点的距离并保持距离小于或等于半径的位置,或者使用sql函数找到两个位置的距离,然后选择距离小于或等于半径的地方。显然第二种选择比第一种选择更好。所以我编写了一个Mysql函数来完成这项工作。 在我的例子中,坐标在数据库中保存为“10.1357002,49.9225563,0”形式的字符串。这是许多人使用的标准坐标格式(例如Google地图)。第一个元素是经度,第二个元素是纬度,我们可以忽略第三个元素(总是0)。所以这里是Mysql函数,它返回Miles中2个坐标之间的距离。
DELIMITER $$
DROP FUNCTION IF EXISTS `GetDistance`$$
CREATE FUNCTION `GetDistance`(coordinate1 VARCHAR(120), coordinate2 VARCHAR(120))
RETURNS VARCHAR(120)
BEGIN
DECLARE pos_comma1, pos_comma2 INT;
DECLARE lon1, lon2, lat1, lat2, distance DECIMAL(12,8);
select locate(',', coordinate1) into pos_comma1;
select locate(',', coordinate1, pos_comma1+1) into pos_comma2;
select CAST(substring(coordinate1, 1, pos_comma1-1) as DECIMAL(12,8)) into lon1;
select CAST(substring(coordinate1, pos_comma1+1, pos_comma2-pos_comma1-1) as DECIMAL(12,8)) into lat1;
select locate(',', coordinate2) into pos_comma1;
select locate(',', coordinate2, pos_comma1+1) into pos_comma2;
select CAST(substring(coordinate2, 1, pos_comma1-1) as DECIMAL(12,8)) into lon2;
select CAST(substring(coordinate2, pos_comma1+1, pos_comma2-pos_comma1-1) as DECIMAL(12,8)) into lat2;
select ((ACOS(SIN(lat1 * PI() / 180) * SIN(lat2 * PI() / 180) + COS(lat1 * PI() / 180) * COS(lat2 * PI() / 180) * COS((lon1 - lon2) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) into distance;
RETURN distance;
END$$
DELIMITER ;
示例用法:
假设您必须找到距离坐标为“10.1357002,49.9225563,0”的地方40英里半径范围内的所有邮政编码。你有一个表POSTCODES表有字段ID,邮政编码,坐标。所以你的sql应该是这样的:
select id, postcode from POSTCODES where GetDistance("10.1357002, 49.9225563, 0", coordinates) <= 40;
答案 4 :(得分:-1)
纬度和经度的原点
$orig_lat=23.04988655049843;
$orig_lon= 72.51734018325806;
$dist=10; // Radius;
//Latitude = database field name;
//Longitude = database field name;
$query = SELECT *, 3956 * 2 * ASIN(SQRT( POWER(SIN(($orig_lat -abs(dest.Latitude)) * pi()/180 / 2),2) + COS($orig_lat * pi()/180 ) * COS( abs(dest.Latitude) * pi()/180) * POWER(SIN(($orig_lon - dest.Longitude) * pi()/180 / 2), 2) )) as distance FROM tbl_name dest having distance < 10 ORDER BY distance limit 10
查找半径为10英里的所有位置 工作正常!
答案 5 :(得分:-1)
我只想离开这里:
https://gist.github.com/899413
这是一个关于如何在一个正方形(BETWEEN)内查询整数并使用SQRT()减少结果以使输出返回圆形结果半径的示例。 (它还以公里为单位返回距离)
要执行此操作,您需要在插入时将所有点转换为公里,以便将它们放置在平面地图上。 (参见php函数)
结果是一个令人难以置信的快速整数查找 - 比查询中的所有计算要快得多,就像这里所说的每个答案一样。
(我在10年前建立了这个...似乎它仍然是mysql最智能的解决方案)