如何仅使用 PHP 检查特定坐标是否在另一个坐标的半径内?

25

我看过许多函数,但它们只适用于 MySQL 或 Postgresql。我想要 PHP 的等效逻辑。我正在做一些比较,例如,当创建时生成这些数据。

Lat: 56.130366
Long: -106.34677099999

稍后,我想检查这些坐标是否落在另一个坐标的半径内。

Lat: 57.223366
Long: -106.34675644699
radius: 100000 ( meters )

提前感谢!


1
请搜索“Haversine公式”或“Vincenty公式”计算两个纬度/经度位置之间的距离。 - Mark Baker
5个回答

55

谢谢您的帮助。下面是一个示例函数,它接受两组经度和纬度坐标,并返回两者之间的距离。

function getDistance($latitude1, $longitude1, $latitude2, $longitude2) {  
  $earth_radius = 6371;

  $dLat = deg2rad($latitude2 - $latitude1);  
  $dLon = deg2rad($longitude2 - $longitude1);  

  $a = sin($dLat/2) * sin($dLat/2) + cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * sin($dLon/2) * sin($dLon/2);  
  $c = 2 * asin(sqrt($a));  
  $d = $earth_radius * $c;  

  return $d;  
}

$distance = getDistance(56.130366, -106.34677099999, 57.223366, -106.34675644699);
if ($distance < 100) {
  echo "Within 100 kilometer radius";
} else {
  echo "Outside 100 kilometer radius";
}

8
因为我花了太长时间寻找它,所以这是等效的Javascript代码。 - MoshMage
@AamirR 是的,但那时候完全不同了。我进行了修改并将其发布为答案。为什么现在才问呢?已经过去5年了,朋友,继续前进吧哈哈 - Kenneth P.
为什么地球半径是6371? - Newbie 123

9

您应该使用Haversine公式来计算两点之间的距离。这里有PHP版本

然后只需检查distance < 100000


你写的代码很不错。但是距离确实是以米或千米为单位吗? - Kenneth P.
它取决于地球半径。如果您像我提供的代码中使用6371,那么单位是公里 :) - Guillaume Poussel
我看过一些算法使用6367作为地球半径,但大多数都是6371,这是否重要呢?不管怎样,谢谢 :) - Kenneth P.
我需要使用什么半径以获得距离(在米)?是6371000吗? - MrEduar

1

这应该会有所帮助,

$lat_origin = 56.130366;
$long_origin = -106.34677099999;

$lat_dest = 57.223366;
$long_dest = -106.34675644699;

$radius      = 3958;      # Earth's radius (miles, convert to meters)
$deg_per_rad = 57.29578;  # Number of degrees/radian (for conversion)

$distance = ($radius * pi() * sqrt(
            ($lat_origin - $lat_dest)
            * ($lat_origin - $lat_dest)
            + cos($lat_origin / $deg_per_rad)  # Convert these to
            * cos($lat_dest / $deg_per_rad)    # radians for cos()
            * ($long_origin - $long_dest)
            * ($long_origin - $long_dest)
    ) / 180);

这里的$deg_per_rad有什么作用? - Murtaza Bharmal

1
//  Vincenty formula to calculate great circle distance between 2 locations
//      expressed as Lat/Long in KM 

function VincentyDistance($lat1,$lat2,$lon1,$lon2){ 
    $a = 6378137 - 21 * sin(lat); 
    $b = 6356752.3142; 
    $f = 1/298.257223563; 

    $p1_lat = $lat1/57.29577951; 
    $p2_lat = $lat2/57.29577951; 
    $p1_lon = $lon1/57.29577951; 
    $p2_lon = $lon2/57.29577951; 

    $L = $p2_lon - $p1_lon; 

    $U1 = atan((1-$f) * tan($p1_lat)); 
    $U2 = atan((1-$f) * tan($p2_lat)); 

    $sinU1 = sin($U1); 
    $cosU1 = cos($U1); 
    $sinU2 = sin($U2); 
    $cosU2 = cos($U2); 

    $lambda = $L; 
    $lambdaP = 2*PI; 
    $iterLimit = 20; 

    while(abs($lambda-$lambdaP) > 1e-12 && $iterLimit>0) { 
        $sinLambda = sin($lambda); 
        $cosLambda = cos($lambda); 
        $sinSigma = sqrt(($cosU2*$sinLambda) * ($cosU2*$sinLambda) + ($cosU1*$sinU2-$sinU1*$cosU2*$cosLambda) * ($cosU1*$sinU2-$sinU1*$cosU2*$cosLambda)); 

        //if ($sinSigma==0){return 0;}  // co-incident points 
        $cosSigma = $sinU1*$sinU2 + $cosU1*$cosU2*$cosLambda; 
        $sigma = atan2($sinSigma, $cosSigma); 
        $alpha = asin($cosU1 * $cosU2 * $sinLambda / $sinSigma); 
        $cosSqAlpha = cos($alpha) * cos($alpha); 
        $cos2SigmaM = $cosSigma - 2*$sinU1*$sinU2/$cosSqAlpha; 
        $C = $f/16*$cosSqAlpha*(4+$f*(4-3*$cosSqAlpha)); 
        $lambdaP = $lambda; 
        $lambda = $L + (1-$C) * $f * sin($alpha) * ($sigma + $C*$sinSigma*($cos2SigmaM+$C*$cosSigma*(-1+2*$cos2SigmaM*$cos2SigmaM))); 
    } 

    $uSq = $cosSqAlpha*($a*$a-$b*$b)/($b*$b); 
    $A = 1 + $uSq/16384*(4096+$uSq*(-768+$uSq*(320-175*$uSq))); 
    $B = $uSq/1024 * (256+$uSq*(-128+$uSq*(74-47*$uSq))); 

    $deltaSigma = $B*$sinSigma*($cos2SigmaM+$B/4*($cosSigma*(-1+2*$cos2SigmaM*$cos2SigmaM)- $B/6*$cos2SigmaM*(-3+4*$sinSigma*$sinSigma)*(-3+4*$cos2SigmaM*$cos2SigmaM))); 

    $s = $b*$A*($sigma-$deltaSigma); 
    return $s/1000; 
} 


echo VincentyDistance($lat1,$lat2,$lon1,$lon2); 

1

这个函数接受两组纬度和经度,并给出以指定单位表示的两者之间的距离。

function distance($lat1, $lon1, $lat2, $lon2, $unit) {
  if (($lat1 == $lat2) && ($lon1 == $lon2)) {
    return 0;
  } else {
    $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;
    }
  }
}

来源:https://www.geodatasource.com/developers/php

用法:

distance(32.9697, -96.80322, 29.46786, -98.53506, "M");

最后一个参数是距离的单位。

  • M 表示 英里
  • K 表示 千米
  • N 表示 海里

1
这段代码可以通过添加一个 epsilon 值来检查两个点是否“足够接近”,而不是完全相同的浮点值来进行改进。将 lat1 === lat2 的条件替换为类似以下的内容:if (abs($lat1 - $lat2) < 0.02 && abs($long1 - $long2) < 0.02) return 0; - Elly Post

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接