terrestres puntos por metros medir longitud latitudes latitud geograficos entre distancia coordenadas calcular calculadora php coordinates geocoding haversine

php - puntos - distancia entre latitudes



Medición de la distancia entre dos coordenadas en PHP (9)

Hola, tengo la necesidad de calcular la distancia entre dos puntos que tienen latitud y longitud.

Me gustaría evitar cualquier llamada a API externa.

Intenté implementar la fórmula Haversine en PHP:

Aquí está el código:

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

Probándolo con algunos puntos dados que tienen distancias públicas, no obtengo un resultado confiable.

No entiendo si hay un error en la fórmula original o en mi implementación


Aquí el código simple y perfecto para calcular la distancia entre dos latitudes y longitudes. El siguiente código se ha encontrado desde aquí: codexworld.com

$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'';


El multiplicador se cambia en cada coordenada debido a la gran teoría de la distancia circular que se escribe aquí:

http://en.wikipedia.org/wiki/Great-circle_distance

y puede calcular el valor más cercano usando esta fórmula que se describe aquí:

http://en.wikipedia.org/wiki/Great-circle_distance#Worked_example

la clave es convertir cada grado - minuto - segundo valor en todos los valores de grado:

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''


Encontré geodatasource.com/developers/php que me está dando resultados confiables.

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

resultados:

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


Es solo una adición a las @martinstoeckli de @martinstoeckli y @Janith Chinthana . Para aquellos que tienen curiosidad sobre qué algoritmo es el más rápido, escribí la prueba de rendimiento . El mejor resultado de rendimiento muestra la función optimizada de 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; }

Aquí están los resultados de las pruebas:

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%


Hola aquí Código para obtener distancia y tiempo usando dos Lat y Long diferentes

$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);

Puede comprobar el ejemplo a continuación Enlace obtener tiempo entre dos ubicaciones diferentes utilizando latitud y longitud en php


No hace mucho escribí un ejemplo de la fórmula de haversine y la publiqué en mi sitio web:

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

➽ Tenga en cuenta que recupera la distancia en la misma unidad que $earthRadius con el parámetro $earthRadius . El valor predeterminado es 6371000 metros, por lo que el resultado será en [m] también. Para obtener el resultado en millas, podría, por ejemplo, pasar 3959 millas como $earthRadius y el resultado sería en [mi]. En mi opinión, es una buena costumbre quedarse con las unidades del SI, si no hay una razón particular para hacer lo contrario.

Editar:

Como correctamente señaló TreyA, la fórmula de Haversine tiene debilidades con los puntos antipodales debido a los errores de redondeo (aunque es estable para distancias pequeñas). Para evitarlos, podrías usar la fórmula de Vincenty .

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


Para los que les gusta más corto y más rápido (sin llamar a 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 }


Para valores exactos, hazlo así:

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

Hmm, creo que debería hacerlo ...

Editar:

Para los formuladores y al menos las implementaciones de JS, pruebe: http://www.movable-type.co.uk/scripts/latlong.html

Atrévete ... me olvidé de deg2rad todos los valores en las funciones del círculo ...


Prueba esto da resultados increíbles

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