【问题标题】:How to calculate distance from lat/long in php?如何在php中计算纬度/经度的距离?
【发布时间】:2011-12-02 03:11:19
【问题描述】:

我想要做的是我在数据库中有条目,其中存储了纬度/经度。我想计算用户 lat/long 和条目 lat/long 之间的距离(在 DB 中)。之后,我想回应距离小于 500 米的那些。到目前为止,我可以使用 foreach 来做到这一点。

<?php
mysql_connect("localhost", "beepbee_kunwarh", "kunwar") or die('MySQL Error.');
mysql_select_db("beepbee_demotest") or die('MySQL Error.');

$Lat = $_REQUEST['Lat'];
$long = $_REQUEST['long'];

$query = mysql_query("SELECT a.*, 3956 * 2 * ASIN(SQRT( POWER(SIN(($Lat - Lat) * pi()/180 / 2), 2) + COS($Lat * pi()/180) * COS(Lat * pi()/180) *POWER(SIN(($long - long) * pi()/180 / 2), 2) )) as distance FROM userResponse GROUP BY beepid HAVING distance <= 500 ORDER by distance ASC;");
$data = array();
while ($row = mysql_fetch_array($query)) {
    $data[] = $row;
}
echo json_encode($data);
?>

【问题讨论】:

  • 你的代码有什么问题?
  • 它为所有条目计算相同的距离,基本上我不知道 wat 值正在传入 $lon2 = $data[$to]["long"]; $lat2 = $data[$to]["Lat"];
  • 您完全更改了问题中的代码...它现在是在 SQL 中计算,而不是在 PHP 中。你能解释一下为什么/现在有什么问题吗?
  • 它给了我在线错误 while ($row = mysql_fetch_array($query))

标签: php latitude-longitude


【解决方案1】:

我不建议在你的 sql 语句中转储距离计算,即使我承认 'denil' 提出的解决方案是巧妙的。

有 3 个缺点:代码维护、sql server 过载和(最重要的是)地球不是对称的(它就像一个被卡车碾过的有凹痕的旧棒球)。这意味着您将来可能想要更改代码(那里有一些非常复杂的算法 - http://en.wikipedia.org/wiki/Geographical_distance)。

我建议使用一个单独的函数,该函数使用简单的通用算法计算距离(如果与 denil 算法不同,则类似)。我提交的是纯 php 代码(无需使用 googlemaps api):

<?php

function distanceGeoPoints ($lat1, $lng1, $lat2, $lng2) {

    $earthRadius = 3958.75;

    $dLat = deg2rad($lat2-$lat1);
    $dLng = deg2rad($lng2-$lng1);


    $a = sin($dLat/2) * sin($dLat/2) +
       cos(deg2rad($lat1)) * cos(deg2rad($lat2)) *
       sin($dLng/2) * sin($dLng/2);
    $c = 2 * atan2(sqrt($a), sqrt(1-$a));
    $dist = $earthRadius * $c;

    // from miles
    $meterConversion = 1609;
    $geopointDistance = $dist * $meterConversion;

    return $geopointDistance;
}

// YOUR CODE HERE
echo distanceGeoPoints(22,50,22.1,50.1);

?>

有许多免费软件(试试 gps trackmaker)可以让您检查您所在地区的误差范围(如果您需要精确度)。对于上述纬度/经度对,误差在 +/- 0.1% 以内(根据当地地形学家)。

注意:此公式为您提供制图距离(海平面距离),而不是地形距离(不考虑地形)。

【讨论】:

  • @ErichBSchulz 是的,米。我的坏:(
【解决方案2】:

几周前我做了这个。

这个链接是你最好的选择:

http://code.google.com/apis/maps/articles/phpsqlsearch.html

即使您不使用他们的 API,他们的 PHP 和 SQL 查询也很有帮助。

【讨论】:

  • 我有查询 wat 是目标纬度/经度,而 wat 是数据库经度/纬度中的条目,未提及
【解决方案3】:

试试这个查询。我在谷歌上搜索时发现了这个,但忘记了它是谁创建的

SELECT a.*,
            3956 * 2 * ASIN(SQRT( POWER(SIN(($lat - lat) * pi()/180 / 2), 2) + COS($lat * pi()/180) * COS(lat * pi()/180) *
            POWER(SIN(($long - longi) * pi()/180 / 2), 2) )) as
            distance FROM table
            GROUP BY id HAVING distance <= 500 ORDER by distance ASC

$lat 和 $long 变量是用户的当前位置。 lat 和 longi 是条目的经纬度

【讨论】:

    【解决方案4】:

    http://www.geodatasource.com/developers/php

    <?php
    
    /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
    /*::                                                                         :*/
    /*::  This routine calculates the distance between two points (given the     :*/
    /*::  latitude/longitude of those points). It is being used to calculate     :*/
    /*::  the distance between two locations using GeoDataSource(TM) Products    :*/
    /*::                                                                         :*/
    /*::  Definitions:                                                           :*/
    /*::    South latitudes are negative, east longitudes are positive           :*/
    /*::                                                                         :*/
    /*::  Passed to function:                                                    :*/
    /*::    lat1, lon1 = Latitude and Longitude of point 1 (in decimal degrees)  :*/
    /*::    lat2, lon2 = Latitude and Longitude of point 2 (in decimal degrees)  :*/
    /*::    unit = the unit you desire for results                               :*/
    /*::           where: 'M' is statute miles                                   :*/
    /*::                  'K' is kilometers (default)                            :*/
    /*::                  'N' is nautical miles                                  :*/
    /*::  Worldwide cities and other features databases with latitude longitude  :*/
    /*::  are available at http://www.geodatasource.com                          :*/
    /*::                                                                         :*/
    /*::  For enquiries, please contact sales@geodatasource.com                  :*/
    /*::                                                                         :*/
    /*::  Official Web site: http://www.geodatasource.com                        :*/
    /*::                                                                         :*/
    /*::         GeoDataSource.com (C) All Rights Reserved 2014                  :*/
    /*::                                                                         :*/
    /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
    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;
          }
    }
    
    echo distance(32.9697, -96.80322, 29.46786, -98.53506, "M") . " Miles<br>";
    echo distance(32.9697, -96.80322, 29.46786, -98.53506, "K") . " Kilometers<br>";
    echo distance(32.9697, -96.80322, 29.46786, -98.53506, "N") . " Nautical Miles<br>";
    
    ?>
    

    【讨论】:

      【解决方案5】:

      测试了 3 个函数和 3 个查询,只有一个显示出良好的距离:

      以米为单位:

      SELECT *,
      (
          (((acos(sin((".$latitude."*pi()/180)) * sin((`latitude`*pi()/180))+cos((".$latitude."*pi()/180))    * cos((`latitude`*pi()/180)) * cos(((".$longitude."- `longitude`)*pi()/180))))*180/pi())*60*1.1515*1.609344) 
          * 1000
      ) as `distance`
      FROM `table`
      ORDER BY `distance` ASC
      

      以公里为单位:

      SELECT *,
      (
          (((acos(sin((".$latitude."*pi()/180)) * sin((`latitude`*pi()/180))+cos((".$latitude."*pi()/180))    * cos((`latitude`*pi()/180)) * cos(((".$longitude."- `longitude`)*pi()/180))))*180/pi())*60*1.1515*1.609344) 
      ) as `distance`
      FROM `table`
      ORDER BY `distance` ASC
      

      【讨论】:

        【解决方案6】:

        这个查询非常适合我:

        $latitude = "23.139422";  //your current lat
        $longitude = "-82.382617"; //your current long
        
        SELECT ( 3959 * acos( cos( radians( '.$latitude.' ) ) * cos( radians( latitude ) ) * 
         cos( radians( longitude ) - radians( '.$longitude.' ) ) + sin( radians( '.$latitude.' )
         ) * sin( radians( latitude ) ) ) ) AS distance from TABLE 
         HAVING distance <= 100 ORDER BY distance ASC
        

        【讨论】:

          【解决方案7】:

          简单易行的方法

          <?php
              $lat1 = Yourstart_latitude;
              $lon1 = Yourstart_longitude;
              $lat2 = Yourend_latitude;
              $lon2 = Yourend_longitude;
              $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 = 'K';
                                          $km   = $miles*1.609344;
                                        echo number_format($km,1);
                                      ?>
          

          【讨论】:

            【解决方案8】:

            使用 distance-matrix google api 计算经纬度之间的距离。

            $ch = curl_init();
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_URL, 
                'https://maps.googleapis.com/maps/api/distancematrix/json?origins='.$prev_add.'&destinations='.$curr_add.'&key=keyyouhavetogenerate'
            );
            $content = curl_exec($ch);
            $array = json_decode($content);
            $obj = json_decode($content, TRUE);
            
            $distance = $obj['rows'][0]['elements'][0]['distance']['text'];
            

            要使用这个api,你需要key,了解更多关于如何生成key的信息请访问https://developers.google.com/maps/documentation/distance-matrix/intro

            【讨论】:

              【解决方案9】:

              对于那些试图远离 Google(和其他)API 的人,我已经使用这个 API 有一段时间了。

              因为地球是圆的,所以对于大范围半径提交会有一些奇怪的结果。它适用于彼此相距约 500 英里的位置。

              /**
               * The max Latitude and Longitude coordinates within a specified milage radius.
               * 
               * @param int $miles
               * @param float $longitude
               * @param float $latitude
               *
               * @return array
               */
              public function getMaxCoordinates($miles = 50, $longitude, $latitude) {
                  $oneDegree = 69; // 69 Miles = 1 degree
              
                  // Calculate the minimum/maximum possible coordinates.
                  $lng_min = $longitude - $miles / abs(cos(deg2rad($latitude)) * $oneDegree);
                  $lng_max = $longitude + $miles / abs(cos(deg2rad($latitude)) * $oneDegree);
                  $lat_min = $latitude  - ($miles / $oneDegree);
                  $lat_max = $latitude  + ($miles / $oneDegree);
              
                  return ([
                      'lat_max' => $lat_max,
                      'lat_min' => $lat_min,
                      'lng_max' => $lng_max,
                      'lng_min' => $lng_min,
                      'miles'   => $miles,
                  ]);
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2017-05-19
                • 2013-04-16
                • 2015-08-14
                • 1970-01-01
                • 2012-10-13
                • 2012-01-26
                • 1970-01-01
                • 2023-03-08
                相关资源
                最近更新 更多