Hallo, ich habe die Notwendigkeit, den Abstand zwischen zwei Punkten mit Lat und Long zu berechnen.
Ich möchte jeden Aufruf an eine externe API vermeiden.
Ich habe versucht, die Haversine-Formel in PHP zu implementieren:
Hier ist der 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;
}
}
Beim Testen mit bestimmten Punkten, die öffentliche Entfernungen haben, erhalte ich kein zuverlässiges Ergebnis.
Ich verstehe nicht, ob in der ursprünglichen Formel oder in meiner Implementierung ein Fehler vorliegt
Vor kurzem habe ich ein Beispiel für die Haversin-Formel geschrieben und es auf meiner Website veröffentlicht:
/**
* 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;
}
➽ Beachten Sie, dass Sie die Distanz in der Einheit zurückerhalten, in der Sie sie mit dem Parameter $earthRadius
übergeben haben. Der Standardwert ist 6371000 Meter, daher wird das Ergebnis auch in [m] angezeigt. Um das Ergebnis in Meilen zu erhalten, könnten Sie z. Übergeben Sie 3959 Meilen als $earthRadius
und das Ergebnis wäre in [mi]. Meiner Meinung nach ist es eine gute Angewohnheit, bei den SI-Einheiten zu bleiben, wenn es keinen besonderen Grund gibt, etwas anderes zu tun.
Bearbeiten:
Wie TreyA richtig hervorhob, weist die Haversine-Formel aufgrund von Rundungsfehlern Schwächen mit Antipodenpunkte auf (obwohl sie für kleine stabil ist Entfernungen). Um sie zu umgehen, können Sie stattdessen die Formel Vincenty verwenden.
/**
* 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;
}
Ich habe diesen Code gefunden, der mir zuverlässige Ergebnisse liefert.
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;
}
}
ergebnisse :
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 ist nur eine Ergänzung zu @martinstoeckli und @Janith Chinthana answers. Für diejenigen, die wissen wollen, welcher Algorithmus am schnellsten ist, habe ich den Leistungstest geschrieben. Das beste Ergebnis zeigt die optimierte Funktion von 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;
}
Hier sind Testergebnisse:
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%
Hier der einfache und perfekte Code zur Berechnung der Entfernung zwischen zwei Breiten- und Längengraden. Der folgende Code wurde von hier aus gefunden - 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';
Für diejenigen, die kürzer und schneller sind (nicht 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
}
Versuchen Sie, dies ergibt fantastische Ergebnisse
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);
}
Für genaue Werte mache es so:
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 ich denke das sollte es tun ...
Bearbeiten:
Für Formulare und mindestens für JS-Implementierungen versuchen Sie: http://www.movable-type.co.uk/scripts/latlong.html
Dare me ... Ich habe vergessen, alle Werte in den Kreisfunktionen zu deg2rad ...
Eine ziemlich alte Frage, aber für diejenigen, die an einem PHP - Code interessiert sind, der dieselben Ergebnisse wie Google Maps liefert, erledigen die folgenden Aufgaben:
/**
* 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;
}
Ich habe mit verschiedenen Koordinaten getestet und es funktioniert perfekt.
Ich denke, es sollte schneller sein als einige Alternativen. Aber das nicht getestet.
Hinweis: Google Maps verwendet als Erdradius 6378137. Die Verwendung mit anderen Algorithmen könnte also auch funktionieren.
Hallo hier Code für Distanz und Zeit mit zwei verschiedenen Lat und 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);
Sie können das Beispiel unter dem Link anzeigen Zeit zwischen zwei verschiedenen Standorten abrufen, indem Sie den Längen- und Breitengrad in php angeben
Der Multiplikator wird an jeder Koordinate aufgrund der hier beschriebenen Großkreisentfernungstheorie geändert:
http://en.wikipedia.org/wiki/Great-circle_distance
und Sie können den nächstgelegenen Wert mithilfe der hier beschriebenen Formel berechnen:
http://en.wikipedia.org/wiki/Great-circle_distance#Worked_example
der Schlüssel konvertiert jeden Grad - Minuten - Sekunden - Wert in jeden Gradwert:
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'
Verwenden Sie diese Funktion, um die Entfernung zwischen den Breiten- und Längenpunkten zu berechnen
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;
}
}
Verwenden Sie dann die Funktion als
echo calculateDistanceBetweenTwoPoints('11.657740','77.766270','11.074820','77.002160','ML',true,5);
Ich hoffe es hilft