Bonjour, j'ai besoin de calculer la distance entre deux points ayant le lat et le long.
Je voudrais éviter tout appel à l'API externe.
J'ai essayé d'implémenter la formule Haversine en PHP:
Voici le code:
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;
}
}
Le test avec des points donnés ayant des distances publiques, je n’obtiens pas de résultat fiable.
Je ne comprends pas s'il y a une erreur dans la formule originale ou dans ma mise en œuvre
Il n'y a pas si longtemps, j'ai écrit un exemple de la formule haversine et je l'ai publié sur mon site 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;
}
➽ Notez que vous retrouvez la distance dans la même unité que lorsque vous vous y connectez avec le paramètre $earthRadius
. La valeur par défaut est 6371000 mètres, le résultat sera donc également en [m]. Pour obtenir le résultat en miles, vous pouvez par exemple passez 3959 miles en tant que $earthRadius
et le résultat serait dans [mi]. A mon avis, c'est une bonne habitude de rester avec les unités SI, s'il n'y a pas de raison particulière de faire autrement.
Modifier:
Comme le souligne à juste titre TreyA, la formule de Haversine présente des faiblesses avec points antipodaux en raison d’erreurs d’arrondi (bien que soit stable pour de petites distances). Pour les contourner, vous pouvez utiliser la formule 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;
}
J'ai trouvé ce code qui me donne des résultats fiables.
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;
}
}
résultats :
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>";
C'est juste un complément aux réponses @martinstoeckli et @Janith Chinthana . Pour ceux qui sont curieux de savoir quel algorithme est le plus rapide, j’ai écrit le test de performance . Les meilleures performances montrent une fonction optimisée 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;
}
Voici les résultats du test:
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%
Voici le code simple et parfait pour calculer la distance entre deux latitude et longitude. Les codes suivants ont été trouvés à partir d'ici - 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';
Pour ceux qui aiment raccourcir et accélérer (ne pas appeler 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
}
Essayez cela donne des résultats impressionnants
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);
}
Pour les valeurs exactes, faites comme ça:
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 je pense que ça devrait le faire ...
Modifier:
Pour les formulaires et au moins les implémentations JS, essayez: http://www.movable-type.co.uk/scripts/latlong.html
Osez moi ... j'ai oublié de dégrader toutes les valeurs dans les fonctions de cercle ...
Question assez ancienne, mais pour ceux intéressés par un code PHP qui renvoie les mêmes résultats que Google Maps, voici le travail:
/**
* 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;
}
J'ai testé avec différentes coordonnées et cela fonctionne parfaitement.
Je pense que cela devrait être plus rapide que certaines alternatives aussi. Mais n'a pas testé cela.
Astuce: Google Maps utilise 6378137 comme rayon de la Terre. Donc, l'utiliser avec d'autres algorithmes pourrait également fonctionner.
Bonjour ici Code pour obtenir la distance et le temps en utilisant deux lat et long différents
$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);
Vous pouvez vérifier Exemple ci-dessous Lien obtenir l'heure entre deux endroits différents en utilisant la latitude et la longitude en php
Le multiplicateur est changé à chaque coordonnée en raison de la théorie de la distance de grand cercle telle qu'écrite ici:
http://en.wikipedia.org/wiki/Great-circle_distance
et vous pouvez calculer la valeur la plus proche en utilisant cette formule décrite ici:
http://en.wikipedia.org/wiki/Great-circle_distance#Worked_example
la clé convertit chaque valeur de degré, minute, seconde en valeur de degré:
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'
Essayez cette fonction pour calculer la distance entre les points de latitude et de longitude
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;
}
}
Puis utilisez la fonction comme
echo calculateDistanceBetweenTwoPoints('11.657740','77.766270','11.074820','77.002160','ML',true,5);
J'espère que ça aide