Измерение расстояния между двумя координатами в переполнении стека

Привет, у меня есть необходимость рассчитать расстояние между двумя точками, имеющими широту и длину.

Я хотел бы избежать любого вызова внешнего API.

Я пытался реализовать формулу Haversine в 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;

}
}

Тестируя это с некоторыми заданными точками, которые имеют публичные расстояния, я не получаю надежного результата.

Я не понимаю, есть ли ошибка в исходной формуле или в моей реализации

111

Решение

Недавно я написал пример формулы 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, Значение по умолчанию — 6371000 метров, поэтому результат будет также в [м]. Чтобы получить результат в милях, вы можете, например, пройти 3959 миль как $earthRadius и результат будет в [ми]. На мой взгляд, это хорошая привычка придерживаться единиц СИ, если нет особой причины поступать иначе.

Редактировать:

Как правильно указал TreyA, формула Хаверсайна имеет недостатки с антиподальные точки из-за ошибок округления (хотя это является устойчив на небольших расстояниях). Чтобы обойти их, вы можете использовать Винсент формула вместо.

/**
* 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;
}
221

Другие решения

я нашел этот код что дает мне надежные результаты.

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>";
42

Это просто дополнение к @martinstoeckli а также @ Джанит Чинтана ответы. Для тех, кому интересно, какой алгоритм самый быстрый, я написал тест производительности. Лучший результат показывает оптимизированную функцию от 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%
17

Здесь простой и совершенный код для расчета расстояния между двумя широтой и долготой. Следующий код был найден здесь — 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';
10

Для тех, кто любит короче и быстрее (не вызывая 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
}
5

Попробуйте это дает потрясающие результаты

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);
}
2

Для точных значений сделайте это так:

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

Смею меня … я забыл deg2rad все значения в функции круга …

1

Здравствуйте, код для получения расстояния и времени, используя два разных широты и долготы

$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

1
По вопросам рекламы [email protected]