web-dev-qa-db-fra.com

Formule Haversine avec php

Je veux utiliser cette formule avec php. J'ai une base de données avec des valeurs de latitute et de longitude enregistrées. 

Je veux trouver, avec une certaine valeur de latitude et de longitude en entrée, toutes les distances (en km) à partir de ce point avec chaque point de la base de données. Pour ce faire, j'ai utilisé la formule sur googlemaps api:

( 6371 * acos( cos( radians(37) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) * sin( radians( lat ) ) ) )

Bien sûr, en utilisant cela dans php, j'ai remplacé radians par deg2rad. Les valeurs 37, -122 sont mes valeurs d'entrée et lat, lng sont celles de la base de données.

Ci-dessous, il y a mon code. Le problème est qu'il y a quelque chose qui cloche mais je ne comprends pas quoi. La valeur de la distance est bien sûr fausse.

//values of latitude and longitute in input (Rome - eur, IT)
$center_lat = "41.8350";
$center_lng =  "12.470";

//connection to database. it works
(..)

//to take each value in the database:
    $query = "SELECT * FROM Dati";
    $result = mysql_query($query);
    while ($row = @mysql_fetch_assoc($result)){
        $lat=$row['Lat']);
        $lng=$row['Lng']);
    $distance =( 6371 * acos((cos(deg2rad($center_lat)) ) * (cos(deg2rad($lat))) * (cos(deg2rad($lng) - deg2rad($center_lng)) )+ ((sin(deg2rad($center_lat))) * (sin(deg2rad($lat))))) );
    }

Par exemple, pour les valeurs: $ Lat = 41.9133741000 $ Lng = 12.5203944000

J'ai la sortie de distance = "4826.9341106926"

20
user1938352

La formule que vous avez utilisée semble être la formule arccosine au lieu de la formule haversine . La formule haversine est en effet plus appropriée pour calculer la distance sur une sphère, car elle n’est pas sujette aux erreurs d’arrondi avec les points antipodaux.

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

P.S. Je ne pouvais pas trouver d'erreur dans votre code, est-ce juste une faute de frappe que vous avez écrite $lat= 41.9133741000 $lat= 12.5203944000? Peut-être que vous venez de calculer avec $ lat = 12.5203944000 et $ long = 0 car vous avez écrasé votre variable $ lat.

Modifier:

Testé le code et il a donné un résultat correct:

$center_lat = 41.8350;
$center_lng = 12.470;
$lat = 41.9133741000;
$lng = 12.5203944000;

// test with your arccosine formula
$distance =( 6371 * acos((cos(deg2rad($center_lat)) ) * (cos(deg2rad($lat))) * (cos(deg2rad($lng) - deg2rad($center_lng)) )+ ((sin(deg2rad($center_lat))) * (sin(deg2rad($lat))))) );
print($distance); // prints 9.662174538188

// test with my haversine formula
$distance = haversineGreatCircleDistance($center_lat, $center_lng, $lat, $lng, 6371);
print($distance); // prints 9.6621745381693
48
martinstoeckli
public function getDistanceBetweenTwoPoints($point1 , $point2){
    // array of lat-long i.e  $point1 = [lat,long]
    $earthRadius = 6371;  // earth radius in km
    $point1Lat = $point1[0];
    $point2Lat =$point2[0];
    $deltaLat = deg2rad($point2Lat - $point1Lat);
    $point1Long =$point1[1];
    $point2Long =$point2[1];
    $deltaLong = deg2rad($point2Long - $point1Long);
    $a = sin($deltaLat/2) * sin($deltaLat/2) + cos(deg2rad($point1Lat)) * cos(deg2rad($point2Lat)) * sin($deltaLong/2) * sin($deltaLong/2);
    $c = 2 * atan2(sqrt($a), sqrt(1-$a));

    $distance = $earthRadius * $c;
    return $distance;    // in km
}
4
Tayyab_Hussain

de ce lien :

function getDistance($latitude1, $longitude1, $latitude2, $longitude2) {
    $earth_radius = 6371;

    $dLat = deg2rad($latitude2 - $latitude1);
    $dLon = deg2rad($longitude2 - $longitude1);

    $a = sin($dLat/2) * sin($dLat/2) + cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * sin($dLon/2) * sin($dLon/2);
    $c = 2 * asin(sqrt($a));
    $d = $earth_radius * $c;

    return $d;
}

Comme vous pouvez le constater, il existe de nombreuses différences entre cela et votre code. Je ne sais pas si vous avez une approche différente de la formule ou une étape lors de la conversion en PHP qui a mal tourné, mais la formule ci-dessus devrait fonctionner.

2
Naryl

Je calcule des distances directement à l'intérieur de requêtes, en utilisant la procédure stockée suivante:

CREATE FUNCTION GEODIST (lat1 DOUBLE, lon1 DOUBLE, lat2 DOUBLE, lon2 DOUBLE)
    RETURNS DOUBLE
    DETERMINISTIC
        BEGIN
            DECLARE dist DOUBLE;
            SET dist =  round(acos(cos(radians(lat1))*cos(radians(lon1))*cos(radians(lat2))*cos(radians(lon2)) + cos(radians(lat1))*sin(radians(lon1))*cos(radians(lat2))*sin(radians(lon2)) + sin(radians(lat1))*sin(radians(lat2))) * 6378.8, 1);
            RETURN dist;
        END|

Vous venez d'exécuter ce qui précède comme une instruction SQl à partir de phpMyAdmin pour créer la procédure. Notez juste la fin |, donc dans votre fenêtre de saisie SQL, choisissez pour le | signe comme limiteur.

Ensuite, dans une requête, appelez-le comme ceci:

$sql = "
SELECT `locations`.`name`, GEODIST(`locations`.`lat`, `locations`.`lon`, " . $lat_to_calculate . ", " . $lon_to_calculate . ") AS `distance`
FROM `locations` ";

J'ai trouvé que c'était beaucoup plus rapide que de le calculer dans PHP après l'exécution de la requête.

1
CyberBrain

Je fais la classe de haversign qui ayant la fonction statique GetDistance ayant les quatre paramètres et il renvoie la distance des points de localisation de bot 

class HaverSign {

     public static function getDistance($latitude1, $longitude1, $latitude2, $longitude2) {
        $earth_radius = 6371;

        $dLat = deg2rad($latitude2 - $latitude1);
        $dLon = deg2rad($longitude2 - $longitude1);

        $a = sin($dLat/2) * sin($dLat/2) + cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * sin($dLon/2) * sin($dLon/2);
        $c = 2 * asin(sqrt($a));
        $d = $earth_radius * $c;

        return $d;
}
}

la classe ci-dessus est stockée dans le répertoire racine et le répertoire racine contient le dossier des classes Appelez-le de la manière suivante dans toute page php

include "../classes/HaverSign.php";
$haversign=new HaverSign();

$lat=18.5204;
$lon=73.8567;

$lat1=18.5404;
$lon1=73.8167;

$dist = $haversign->getDistance($lat,$lon,$lat1,$lon1);
echo $dist;

La sortie est comme suit

4.7676529976827
1
Sandip Bhoi