PHP MySQL从GPS获取半径用户位置的位置

时间:2010-07-28 03:54:20

标签: php mysql location coordinates

例如,我在我的数据库中发生汽车事故。这些事件具有纬度和经度。在使用GPS的手机上,我用坐标获取用户的位置。如果他周围有事件,用户可以选择他想知道的半径。所以,让我们说他想知道身边2英里的事件。

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

你知道怎么做吗?

5 个答案:

答案 0 :(得分:3)

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

我会使用启发式方法,例如通过简单的加法和减法近似距离。

  

1分钟= 1.86公里= 1.15   英里

只搜索数据库中包含该范围内的事件(实际上是一个正方形,而不是一个圆圈),然后您可以使用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) 

来源:http://www.meridianworlddata.com/Distance-Calculation.asp


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

  • 3种算法的准确度差异很小,特别是在短距离
  • 最慢的算法(具有整串trig函数的算法)比其他两个算法慢4倍。

绝对不值得。只需要近似值。

代码在这里:http://pastebin.org/424186

答案 1 :(得分: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
    }
  }

它可以更快地获取所有数据并通过函数运行它,而不是在数据库不是太大时使用查询。

它也适用于Kilos和Nautical里程。 ;)

答案 2 :(得分:0)

有一个公式来计算两个纬度/经度坐标之间的距离。但要注意 - 它的计算成本相当昂贵,所以如果你有很多事件,你就会想要聪明一些。首先,read about the maths involved

对于PHP代码,快速谷歌出现了this link,看起来它可能有效。

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

我对此没有任何特别的了解,但如果没有其他人带来一些聪明的东西,我会在时间允许的情况下尝试自己提出一些事情。

答案 3 :(得分:0)

 SELECT 3963 * ACOS(
    SIN(RADIANS($pointAlat)) * SIN(RADIANS($pointAlat)) + COS(RADIANS($pointAlat))  * COS(RADIANS($pointBlat)) * COS(RADIANS($pointAlong) - RADIANS($pointBlong)))
 AS
 distance;

另外,如果您正在寻找一个好的阅读/教程..请点击此处 http://www.phpfreaks.com/forums/index.php/topic,208965.0.html

答案 4 :(得分:0)

我做了一个快速搜索并调高了this blog post,这给出了一个很好的解释和SQL来选择给定半径内的记录。

在评论中,他建议“对于大型数据集的速度,您可能首先要在原点附近抓取一个方块,然后在纬度和纬度上添加一英里左右的原点,然后使用上面的内容作为从中间分开工作“这对我来说就像是要走的路。”