PHP MySQL从GPS获取radius用户位置中的位置

PHP MySQL从GPS获取radius用户位置中的位置,php,mysql,location,coordinates,Php,Mysql,Location,Coordinates,例如,我的数据库中有汽车事故。这些事件有纬度和经度。在使用GPS的手机上,我通过用户的坐标获取其位置。用户可以选择一个半径,他想知道他周围是否有事故。假设他想知道他周围2英里的事情 因此,我将用户选择的纬度、经度和半径从手机发送到网络服务。我需要进行SQL查询,以获取用户周围2英里处的事件 你知道怎么做吗 function distance($lat1,$lon1,$lat2,$lon2,$unit) { $theta=$lon1-$lon2; $dist=sin(deg2rad($

例如,我的数据库中有汽车事故。这些事件有纬度和经度。在使用GPS的手机上,我通过用户的坐标获取其位置。用户可以选择一个半径,他想知道他周围是否有事故。假设他想知道他周围2英里的事情

因此,我将用户选择的纬度、经度和半径从手机发送到网络服务。我需要进行SQL查询,以获取用户周围2英里处的事件

你知道怎么做吗

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;
    }
  } // end function

$x_lat=center_of_serach;
$x_lon=center_of_serach;
$_distance=some_distance_in_miles;
$query1 = "SELECT * FROM `location_table` WHERE somefield=somefilter";
$result=mysql_db_query($db_conn, $query1);
$max_rows=mysql_num_rows($result); 
if ($max_rows>0)
  {
while ( $data1=mysql_fetch_assoc($result) )
  {
  if ( distance($x_lat,$x_lon,$data1['lat'],$data1['lng'],'m')<$_distance )
    {
    //do stuff
    }
  }
获取所有数据并通过函数运行比在数据库不太大的情况下使用查询更快


它也适用于千克和海里

有一个公式可以计算两个lat/lon坐标之间的距离。不过要小心——这在计算上相当昂贵,所以如果你有很多事故,你会想聪明一点。首先

至于PHP代码,一个快速的google出现了,看起来它可能会工作

现在,您可能想使用一些更有效的方法将事件点分为两组:可能在范围内的点(希望是较小的点集),以及可以完全贴现的点。检查几十个以上的事件坐标可能是一个性能问题

我对这一点没有什么特别的见解,但如果没有其他人提出一些聪明的建议,我会在时间允许的情况下尝试自己提出一些建议

 SELECT 3963 * ACOS(
    SIN(RADIANS($pointAlat)) * SIN(RADIANS($pointAlat)) + COS(RADIANS($pointAlat))  * COS(RADIANS($pointBlat)) * COS(RADIANS($pointAlong) - RADIANS($pointBlong)))
 AS
 distance;
另外,如果你想找一本关于这方面的好读物/教程。。检查这里

正如其他人所说,计算距离在计算上非常昂贵。返回巨大的数据集也不是一个好主意——特别是考虑到PHP的性能不是很好

我会使用启发式,比如用简单的加法和减法来近似距离

1分钟=1.86公里=1.15公里 迈尔斯

只需在db中搜索该范围内的事件(实际上是正方形,而不是圆形),然后就可以使用PHP处理这些事件

编辑:这里有一个替代方案;计算成本更低的近似值:

近似距离(英里):

sqrt(x * x + y * y)

where x = 69.1 * (lat2 - lat1) 
and y = 53.0 * (lon2 - lon1) 
sqrt(x * x + y * y)

where x = 69.1 * (lat2 - lat1) 
and y = 69.1 * (lon2 - lon1) * cos(lat1/57.3) 
通过添加余弦数学函数,可以提高此近似距离计算的精度:

改进的近似距离(以英里为单位):

sqrt(x * x + y * y)

where x = 69.1 * (lat2 - lat1) 
and y = 53.0 * (lon2 - lon1) 
sqrt(x * x + y * y)

where x = 69.1 * (lat2 - lat1) 
and y = 69.1 * (lon2 - lon1) * cos(lat1/57.3) 
资料来源:

编辑2:我使用随机生成的数据集运行了一系列测试

3种算法的精度差异最小,尤其是在短距离内 最慢的算法——包含一整串trig函数的算法——比其他两个算法慢4倍。 绝对不值得。用一个近似值


代码在这里:

我做了一个快速搜索,找到了一个很好的解释和SQL来选择给定半径内的记录


在评论中,他建议为了提高大型数据集的速度,你可能想先在原点周围抓取一个正方形块,在两个纬度/经度之间添加一英里左右的距离作为原点,然后使用上面的作为子选择,从中间开始工作,我觉得这是一种方式。

LOL我刚刚注意到你的链接。。是的,这很有效;我也推荐这个。我会考虑对数据集进行两次传递。第一次通过将只检查事件经度是否在位置经度的X英里范围内,以及事件经度是否在位置经度的X英里范围内。这是一个非常简单的查询,将返回一个较小的数据集来处理。使用这个较小的数据集,开始执行一些trig来确定事件到用户位置的线性距离,这需要更复杂的数学,但您现在至少正在使用一个较小的数据集。@Jakobud您可以在同一个查询中运行该过滤器:WHERE Latyah,诸如此类。要可视化Jackobud的方法,首先要检查是否有任何候选点位于4平方英里16平方英里的区域内,用户坐标位于中心。如果是的话,那么你需要进行更昂贵的计算,以确定它是否与正方形内的圆有关[@Talvi Watia-huh?这似乎不对-单位不匹配。@timedev哇。是的。我发布的太快了。添加$distance/69.1以粗略转换为度。没有用,因为你不能在WHERE子句中使用别名-这会迫使他计算一组超越函数两次。哎哟。在一个潜在的巨大数据集上。Double哎哟。另一个很好的启发。使用一分钟或其相关细分的最小可能距离,并使用该距离排除明显超过两英里的任何候选点。当然,您可以更聪明地了解这一点,并根据用户的位置使用各种近似值。链接页面存档于