PHP에서 두 좌표 사이의 거리 측정
안녕하세요, 저는 위도와 위도가 있는 두 지점 사이의 거리를 계산해야 합니다.
외부 API 호출은 피하고 싶습니다.
Haversine Formula를 PHP로 구현하려고 했습니다.
코드는 다음과 같습니다.
class CoordDistance
{
public $lat_a = 0;
public $lon_a = 0;
public $lat_b = 0;
public $lon_b = 0;
public $measure_unit = 'kilometers';
public $measure_state = false;
public $measure = 0;
public $error = '';
public function DistAB()
{
$delta_lat = $this->lat_b - $this->lat_a ;
$delta_lon = $this->lon_b - $this->lon_a ;
$earth_radius = 6372.795477598;
$alpha = $delta_lat/2;
$beta = $delta_lon/2;
$a = sin(deg2rad($alpha)) * sin(deg2rad($alpha)) + cos(deg2rad($this->lat_a)) * cos(deg2rad($this->lat_b)) * sin(deg2rad($beta)) * sin(deg2rad($beta)) ;
$c = asin(min(1, sqrt($a)));
$distance = 2*$earth_radius * $c;
$distance = round($distance, 4);
$this->measure = $distance;
}
}
공공 거리가 있는 특정 포인트로 테스트하면 신뢰할 수 있는 결과를 얻을 수 없습니다.
원래 공식 또는 구현에 오류가 있는지 알 수 없습니다.
얼마 전, 저는 Haversine 공식의 예를 써서 제 웹사이트에 공개했습니다.
/**
* Calculates the great-circle distance between two points, with
* the Haversine formula.
* @param float $latitudeFrom Latitude of start point in [deg decimal]
* @param float $longitudeFrom Longitude of start point in [deg decimal]
* @param float $latitudeTo Latitude of target point in [deg decimal]
* @param float $longitudeTo Longitude of target point in [deg decimal]
* @param float $earthRadius Mean earth radius in [m]
* @return float Distance between points in [m] (same as earthRadius)
*/
function haversineGreatCircleDistance(
$latitudeFrom, $longitudeFrom, $latitudeTo, $longitudeTo, $earthRadius = 6371000)
{
// convert from degrees to radians
$latFrom = deg2rad($latitudeFrom);
$lonFrom = deg2rad($longitudeFrom);
$latTo = deg2rad($latitudeTo);
$lonTo = deg2rad($longitudeTo);
$latDelta = $latTo - $latFrom;
$lonDelta = $lonTo - $lonFrom;
$angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) +
cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2)));
return $angle * $earthRadius;
}
② 파라미터로 통과했을 때 같은 단위로 거리를 되돌리는 것에 주의해 주십시오.$earthRadius
6371000m입니다. 단위로할 수 .$earthRadius
[미]미]미하다특별한 이유가 없다면 SI 유닛을 고수하는 것이 좋은 습관이라고 생각합니다.
편집:
TreyA가 정확하게 지적했듯이 Haversine 공식은 반올림 오류로 인해 대척점에 약점이 있습니다(단, 짧은 거리에 대해서는 안정적입니다).그들을 피하려면, 대신 빈센트 공식을 사용할 수 있습니다.
/**
* Calculates the great-circle distance between two points, with
* the Vincenty formula.
* @param float $latitudeFrom Latitude of start point in [deg decimal]
* @param float $longitudeFrom Longitude of start point in [deg decimal]
* @param float $latitudeTo Latitude of target point in [deg decimal]
* @param float $longitudeTo Longitude of target point in [deg decimal]
* @param float $earthRadius Mean earth radius in [m]
* @return float Distance between points in [m] (same as earthRadius)
*/
public static function vincentyGreatCircleDistance(
$latitudeFrom, $longitudeFrom, $latitudeTo, $longitudeTo, $earthRadius = 6371000)
{
// convert from degrees to radians
$latFrom = deg2rad($latitudeFrom);
$lonFrom = deg2rad($longitudeFrom);
$latTo = deg2rad($latitudeTo);
$lonTo = deg2rad($longitudeTo);
$lonDelta = $lonTo - $lonFrom;
$a = pow(cos($latTo) * sin($lonDelta), 2) +
pow(cos($latFrom) * sin($latTo) - sin($latFrom) * cos($latTo) * cos($lonDelta), 2);
$b = sin($latFrom) * sin($latTo) + cos($latFrom) * cos($latTo) * cos($lonDelta);
$angle = atan2(sqrt($a), $b);
return $angle * $earthRadius;
}
나는 이 코드를 발견했고, 그것은 나에게 신뢰할 수 있는 결과를 준다.
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>";
@martinstockli와 @Janith Chinthana의 답변에 추가될 뿐입니다.어떤 알고리즘이 가장 빠른지 궁금하신 분들을 위해 성능 테스트를 작성했습니다.최고의 퍼포먼스 결과는 codexworld.com의 최적화된 기능을 보여줍니다.
/**
* Optimized algorithm from http://www.codexworld.com
*
* @param float $latitudeFrom
* @param float $longitudeFrom
* @param float $latitudeTo
* @param float $longitudeTo
*
* @return float [km]
*/
function codexworldGetDistanceOpt($latitudeFrom, $longitudeFrom, $latitudeTo, $longitudeTo)
{
$rad = M_PI / 180;
//Calculate distance from latitude and longitude
$theta = $longitudeFrom - $longitudeTo;
$dist = sin($latitudeFrom * $rad)
* sin($latitudeTo * $rad) + cos($latitudeFrom * $rad)
* cos($latitudeTo * $rad) * cos($theta * $rad);
return acos($dist) / $rad * 60 * 1.853;
}
테스트 결과는 다음과 같습니다.
Test name Repeats Result Performance
codexworld-opt 10000 0.084952 sec +0.00%
codexworld 10000 0.104127 sec -22.57%
custom 10000 0.107419 sec -26.45%
custom2 10000 0.111576 sec -31.34%
custom1 10000 0.136691 sec -60.90%
vincenty 10000 0.165881 sec -95.26%
여기 두 위도와 경도 사이의 거리를 계산하기 위한 간단하고 완벽한 코드가 있습니다.http://www.codexworld.com/distance-between-two-addresses-google-maps-api-php/ 에서 다음 코드를 찾을 수
$latitudeFrom = '22.574864';
$longitudeFrom = '88.437915';
$latitudeTo = '22.568662';
$longitudeTo = '88.431918';
//Calculate distance from latitude and longitude
$theta = $longitudeFrom - $longitudeTo;
$dist = sin(deg2rad($latitudeFrom)) * sin(deg2rad($latitudeTo)) + cos(deg2rad($latitudeFrom)) * cos(deg2rad($latitudeTo)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
$distance = ($miles * 1.609344).' km';
꽤 오래된 질문이지만 Google Maps와 동일한 결과를 반환하는 PHP 코드에 관심이 있는 사람은 다음과 같은 작업을 수행할 수 있습니다.
/**
* Computes the distance between two coordinates.
*
* Implementation based on reverse engineering of
* <code>google.maps.geometry.spherical.computeDistanceBetween()</code>.
*
* @param float $lat1 Latitude from the first point.
* @param float $lng1 Longitude from the first point.
* @param float $lat2 Latitude from the second point.
* @param float $lng2 Longitude from the second point.
* @param float $radius (optional) Radius in meters.
*
* @return float Distance in meters.
*/
function computeDistance($lat1, $lng1, $lat2, $lng2, $radius = 6378137)
{
static $x = M_PI / 180;
$lat1 *= $x; $lng1 *= $x;
$lat2 *= $x; $lng2 *= $x;
$distance = 2 * asin(sqrt(pow(sin(($lat1 - $lat2) / 2), 2) + cos($lat1) * cos($lat2) * pow(sin(($lng1 - $lng2) / 2), 2)));
return $distance * $radius;
}
다양한 좌표를 사용해 테스트해 봤는데 완벽하게 작동합니다.
다른 대안보다 더 빨라야 할 것 같아요.하지만 그건 테스트 안 했어
힌트: Google 지도는 지구 반지름으로 6378137을 사용합니다.따라서 다른 알고리즘에서도 사용할 수 있습니다.
짧고 빠른(deg2rad()를 호출하지 않음)을 원하는 사용자에게 적합합니다.
function circle_distance($lat1, $lon1, $lat2, $lon2) {
$rad = M_PI / 180;
return acos(sin($lat2*$rad) * sin($lat1*$rad) + cos($lat2*$rad) * cos($lat1*$rad) * cos($lon2*$rad - $lon1*$rad)) * 6371;// Kilometers
}
이것을 사용해 보면, 놀라운 결과를 얻을 수 있다.
function getDistance($point1_lat, $point1_long, $point2_lat, $point2_long, $unit = 'km', $decimals = 2) {
// Calculate the distance in degrees
$degrees = rad2deg(acos((sin(deg2rad($point1_lat))*sin(deg2rad($point2_lat))) + (cos(deg2rad($point1_lat))*cos(deg2rad($point2_lat))*cos(deg2rad($point1_long-$point2_long)))));
// Convert the distance in degrees to the chosen unit (kilometres, miles or nautical miles)
switch($unit) {
case 'km':
$distance = $degrees * 111.13384; // 1 degree = 111.13384 km, based on the average diameter of the Earth (12,735 km)
break;
case 'mi':
$distance = $degrees * 69.05482; // 1 degree = 69.05482 miles, based on the average diameter of the Earth (7,913.1 miles)
break;
case 'nmi':
$distance = $degrees * 59.97662; // 1 degree = 59.97662 nautic miles, based on the average diameter of the Earth (6,876.3 nautical miles)
}
return round($distance, $decimals);
}
위도와 경도 지점 사이의 거리를 계산하려면 이 함수를 사용해 보십시오.
function calculateDistanceBetweenTwoPoints($latitudeOne='', $longitudeOne='', $latitudeTwo='', $longitudeTwo='',$distanceUnit ='',$round=false,$decimalPoints='')
{
if (empty($decimalPoints))
{
$decimalPoints = '3';
}
if (empty($distanceUnit)) {
$distanceUnit = 'KM';
}
$distanceUnit = strtolower($distanceUnit);
$pointDifference = $longitudeOne - $longitudeTwo;
$toSin = (sin(deg2rad($latitudeOne)) * sin(deg2rad($latitudeTwo))) + (cos(deg2rad($latitudeOne)) * cos(deg2rad($latitudeTwo)) * cos(deg2rad($pointDifference)));
$toAcos = acos($toSin);
$toRad2Deg = rad2deg($toAcos);
$toMiles = $toRad2Deg * 60 * 1.1515;
$toKilometers = $toMiles * 1.609344;
$toNauticalMiles = $toMiles * 0.8684;
$toMeters = $toKilometers * 1000;
$toFeets = $toMiles * 5280;
$toYards = $toFeets / 3;
switch (strtoupper($distanceUnit))
{
case 'ML'://miles
$toMiles = ($round == true ? round($toMiles) : round($toMiles, $decimalPoints));
return $toMiles;
break;
case 'KM'://Kilometers
$toKilometers = ($round == true ? round($toKilometers) : round($toKilometers, $decimalPoints));
return $toKilometers;
break;
case 'MT'://Meters
$toMeters = ($round == true ? round($toMeters) : round($toMeters, $decimalPoints));
return $toMeters;
break;
case 'FT'://feets
$toFeets = ($round == true ? round($toFeets) : round($toFeets, $decimalPoints));
return $toFeets;
break;
case 'YD'://yards
$toYards = ($round == true ? round($toYards) : round($toYards, $decimalPoints));
return $toYards;
break;
case 'NM'://Nautical miles
$toNauticalMiles = ($round == true ? round($toNauticalMiles) : round($toNauticalMiles, $decimalPoints));
return $toNauticalMiles;
break;
}
}
그런 다음 기능을 다음과 같이 사용합니다.
echo calculateDistanceBetweenTwoPoints('11.657740','77.766270','11.074820','77.002160','ML',true,5);
도움이 되었으면 좋겠다
정확한 값은 다음과 같이 합니다.
public function DistAB()
{
$delta_lat = $this->lat_b - $this->lat_a ;
$delta_lon = $this->lon_b - $this->lon_a ;
$a = pow(sin($delta_lat/2), 2);
$a += cos(deg2rad($this->lat_a9)) * cos(deg2rad($this->lat_b9)) * pow(sin(deg2rad($delta_lon/29)), 2);
$c = 2 * atan2(sqrt($a), sqrt(1-$a));
$distance = 2 * $earth_radius * $c;
$distance = round($distance, 4);
$this->measure = $distance;
}
흠, 그걸로 충분할 것 같은데...
편집:
자세한 내용 및 적어도 JS 구현에 대해서는 http://www.movable-type.co.uk/scripts/latlong.html를 참조하십시오.
감히...원 함수의 모든 값을 지우는 걸 깜빡했어
승수는 다음과 같이 큰 원거리 이론 때문에 모든 좌표에서 변경됩니다.
http://en.wikipedia.org/wiki/Great-circle_distance
여기서 설명하는 공식을 사용하여 가장 가까운 값을 계산할 수 있습니다.
http://en.wikipedia.org/wiki/Great-circle_distance#Worked_example
키는 각 degree - minute - second 값을 모든 degree 값으로 변환하는 것입니다.
N 36°7.2', W 86°40.2' N = (+) , W = (-), S = (-), E = (+)
referencing the Greenwich meridian and Equator parallel
(phi) 36.12° = 36° + 7.2'/60'
(lambda) -86.67° = 86° + 40.2'/60'
Hello here Lat와 Long을 사용한 거리와 시간 취득 코드
$url ="https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&origins=16.538048,80.613266&destinations=23.0225,72.5714";
$ch = curl_init();
// Disable SSL verification
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
// Will return the response, if false it print the response
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Set the url
curl_setopt($ch, CURLOPT_URL,$url);
// Execute
$result=curl_exec($ch);
// Closing
curl_close($ch);
$result_array=json_decode($result);
print_r($result_array);
아래 링크 예제를 선택하면 위도와 경도를 사용하여 두 위치 사이의 시간을 php로 얻을 수 있습니다.
가장 쉬운 방법 중 하나는 다음과 같습니다.
$my_latitude = "";
$my_longitude = "";
$her_latitude = "";
$her_longitude = "";
$distance = round((((acos(sin(($my_latitude*pi()/180)) * sin(($her_latitude*pi()/180))+cos(($my_latitude*pi()/180)) * cos(($her_latitude*pi()/180)) * cos((($my_longitude- $her_longitude)*pi()/180))))*180/pi())*60*1.1515*1.609344), 2);
echo $distance;
소수점 2점까지 반올림합니다.
언급URL : https://stackoverflow.com/questions/10053358/measuring-the-distance-between-two-coordinates-in-php
'programing' 카테고리의 다른 글
마리아DB 삽입 위치...선택...0 행에 영향을 주는 중복 키 업데이트 켜기 (0) | 2023.01.13 |
---|---|
PyTorch가 GPU를 사용하고 있는지 어떻게 확인합니까? (0) | 2023.01.13 |
'mariadb 다운로드 중'에서 도커 빌드에 실패했습니다. (0) | 2023.01.13 |
DOM parentNode와 parentElement의 차이점 (0) | 2023.01.13 |
텍스트 입력 기록 사용 안 함 (0) | 2023.01.13 |