php - 选择半径内的纬度和经度点

标签 php mysql sql mysqli

我正在使用 forumla 在给定位置和半径的数据库中选择纬度/经度点,但是我的工作还不够。我唯一能让查询正常工作的时间是当我使用 6371 公里的半径(世界的大小)时,我认为 forumla 存在问题,但我似乎无法弄清楚在哪里...

这是我的sql查询

   $latitude = $_POST["latitude"]; // latitude of centre of bounding circle in degrees
   $longitude = $_POST["longitude"];; // longitude of centre of bounding circle in degrees
   $rad = $_POST["radius"]; // radius of bounding circle in kilometers
   $R = 6371;// earth's mean radius, km
   $maxLat = $latitude + rad2deg($rad/$R);
   $minLat = $latitude - rad2deg($rad/$R);
    // compensate for degrees longitude getting smaller with increasing latitude
   $maxLon = $longitude + rad2deg($rad/$R/cos(deg2rad($latitude)));
   $minLon = $longitude - rad2deg($rad/$R/cos(deg2rad($latitude)));



   $con = mysqli_connect("localhost","root","Winter#05");

   if (!$con)
   {
   die('Could not connect: ' . mysql_error());
   }
   mysqli_select_db($con, "appdatabase");


   $result = mysqli_query($con,"select id, PostTitle, SubmitDate, PostVotes, ImagePath, comments, latitude, longitude, acos(sin($latitude)*sin(radians(latitude)) + cos($latitude)*cos(radians(latitude))*cos(radians(longitude)-($longitude))) * $R as D 
   from ( select id, PostTitle, SubmitDate, PostVotes, comments, ImagePath, latitude, longitude 
   from posts where latitude > $minLat and latitude < $maxLat and longitude > $minLon and longitude < $maxLon ) as first_cut 
   where acos(sin($latitude)*sin(radians(latitude)) + cos($latitude)*cos(radians(latitude))*cos(radians(longitude) - ($longitude))) * $R < $rad order by D") or die('Errant query:');

   while($row = mysqli_fetch_assoc($result))
   {
        $output[]=$row;
   }


   print(json_encode($output));

   mysqli_close($con);

最佳答案

一个问题是 $latitude$longitude 似乎以 为单位合并到 SQL 文本中。该公式(在 SQL 查询中实现)看起来期望这些位置的值以弧度为单位。


如果我必须阅读/维护这段代码,那么如果它是这样写的,那么将更容易理解查询:

SELECT p.id
     , p.PostTitle
     , p.SubmitDate
     , p.PostVotes
     , p.ImagePath
     , p.comments
     , p.latitude
     , p.longitude
     , ACOS( SIN(       (  $latitude ))
           * SIN(RADIANS( p.latitude ))
           + COS(       (  $latitude ))
           * COS(RADIANS( p.latitude ))
           * COS(RADIANS( p.longitude ) -        ( $longitude ))
           ) * $R
       AS D
  FROM posts p
 WHERE p.latitude  > $minLat
   AND p.latitude  < $maxLat 
   AND p.longitude > $minLon
   AND p.longitude < $maxLon 
HAVING D < $rad
 ORDER BY D

大圆距离公式看起来不错,只是我想知道为什么 $latitude$longitude 是以弧度为单位而不是度数提供的。

然后我查看 PHP 代码,你瞧,它们实际上是以度为单位的,我发现缺少到弧度的转换。

返回距离“D”的表达式中缺少的只是围绕 $latitude$longitude 的 RADIANS 函数

所以这样:

     , ACOS( SIN(       (  $latitude ))
           * SIN(RADIANS( p.latitude ))
           + COS(       (  $latitude ))
           * COS(RADIANS( p.latitude ))
           * COS(RADIANS( p.longitude ) -        ( $longitude ))
           ) * $R
       AS D

被替换为

     , ACOS( SIN(RADIANS(  $latitude ))
           * SIN(RADIANS( p.latitude ))
           + COS(RADIANS(  $latitude ))
           * COS(RADIANS( p.latitude ))
           * COS(RADIANS( p.longitude ) - RADIANS( $longitude ))
           ) * $R
       AS D

如果我要维护它,我也会将其转换为带有绑定(bind)占位符准备好的语句。至少,我会正确地转义任何被合并到 SQL 文本中的潜在不安全值...... mysqli_real_escape_string

例如

$sql .= "  + COS(RADIANS( " . mysqli_real_escape_string($con,$latitude) . " ))"

我怀疑 $minLat, $maxLat, $minLon, $maxLon 的计算.我一定会测试那些。为了仅测试没有这些的查询,我可以注释掉整个 WHERE 子句,然后为 every 中的翻转行计算距离 D表,然后通过 HAVING 子句过滤这些。

我们确实希望在 WHERE 子句中包含谓词(如果正确完成)会提供一个“边界框”,它会限制我们需要通过大圆计算进行的行数。

消除内联 View 应该会提高性能,因为 MySQL 不会有具体化派生表的开销。

关于php - 选择半径内的纬度和经度点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30085759/

相关文章:

php - 将长数字缩短为 K/M/B?

mysql - 获取错误代码 : 3. 执行大型查询时写入文件时出错(Errcode:28)

php - 每 10 个广告 - 2 个横幅循环

mysql - 通过应用特定过滤器来查询和分组数据

sql - 如何跨子域共享 session 状态

sql - 检索当前和最近的先前值 (Oracle)

php - 使用 php 连接到 mysql 数据库时出现问题

php - 检查 MySQL 表是否为空

phpMyAdmin: "URI too large"

mysql - 如何从mysql表中查找元素的前驱和后继?