2013-02-07 14 views
16

Voglio usare questa formula con php. Ho un database con alcuni valori di latitudine e longitudine salvati.Formula Haversine con php

Voglio trovare, con un determinato valore di latitudine e longitudine in ingresso, tutte le distanze (in km) da questo punto con ogni punto nel database. Per fare questo, ho usato la formula su GoogleMaps api:

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

Naturalmente usando che in php ho sostituito radianti con valori deg2rad .Il 37, -122 sono miei valori di input e lat, lng sono miei valori il database.

Sotto c'è il mio codice. Il problema è che c'è qualcosa di sbagliato ma non capisco cosa. Il valore della distanza è ovviamente sbagliato.

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

Per i valori, ad esempio: $ lat = 41,9,133741 miliardi $ lng = 12,5203944000

ho l'uscita della distanza = "4826,9341,106926 millions"

+0

Controllare le staffe –

risposta

43

La formula si è utilizzato, sembra essere il arcocoseno al posto del haversine formula. La formula haversine è davvero più appropriata per calcolare la distanza su una sfera, perché non è incline agli errori di arrotondamento con punti antipodali.

/** 
* 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. Non sono riuscito a trovare un errore nel codice, quindi è solo un errore di battitura che hai scritto $lat= 41.9133741000 $lat= 12.5203944000? Forse hai appena calcolato con $ lat = 12.5203944000 e $ long = 0 perché hai sovrascritto la tua variabile $ lat.

Edit:

testato il codice e ha restituito un risultato corretto:

$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 
+0

scusa, sì è solo un errore nel test della domanda, ovviamente nel codice che ho usato $ lat e $ lng –

+0

ho preso la formula [qui] (https://developers.google.com/maps/articles/ phpsqlsearch_v3? hl = it # findnearsql). con la tua funzione ho (con lo stesso input sopra) l'output di "4826934.1106926". perché? –

+0

@ user1938352 - Hai provato a dichiarare la variabile come numero anziché come stringa? Il tuo esempio usa '$ center_lat =" 41.8350 ";' dove dovrebbe essere '$ center_lat = 41.8350;', forse analizza '.' come separatore delle migliaia in base alle impostazioni locali. – martinstoeckli

1

da this link:

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

Come puoi vedere ci sono molte differenze tra questo come il tuo codice. Non so se hai un approccio diverso alla formula o forse qualche passaggio quando la conversione in PHP è andata storta, ma la formula sopra dovrebbe funzionare.

+0

questo dare ho la stessa resa del mio metodo, quindi penso che il problema sia nei valori di input. ma dov'è l'errore? –

1

ho calcolare le distanze di scala ad incastro query, utilizzando la seguente stored procedure:

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| 

Basta eseguire quanto sopra come un'istruzione SQL dall'interno di phpMyAdmin per creare la procedura. Basta notare il finale |, quindi nella finestra di input SQL, scegliere per il | firmare come limitatore.

Poi in una query, lo chiamano così:

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

ho trovato questo di essere molto più veloce di calcolo è in PHP dopo che la query è stato eseguito.

+0

A proposito, calcola la distanza in metri, quindi puoi dividerlo per 1000 o arrotondarlo in qualche modo per calcolare i KM. – CyberBrain

2
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 
} 
0

ho rendendo la classe di haversign che avendo il fuction statica getDistance avere i quattro paramters ed è di ritorno la distanza dai punti di ubicazione del 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; 
} 
} 

sopra classe viene memorizzato nella directory principale e la directory radice contiene cartella classi chiamata questo utilizzando il seguente percorso in qualsiasi pagina 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; 

uscita è come seguire

4.7676529976827