2013-02-07 8 views
16

Chcę użyć tej formuły z php. Mam bazę danych z pewnymi wartościami latitów i długości geograficznej.Formuła Haversine z php

Chcę znaleźć, z określoną wartością szerokości i długości geograficznej na wejściu, wszystkie odległości (w km) od tego punktu z każdym punktem w bazie danych. Aby to zrobić, użyłem wzoru na GoogleMaps API:

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

Oczywiście używając że w php Wymieniłem radiany z wartościami deg2rad .Powierzchnia 37 -122 są moje wartości wejściowych i szer LNG są moje wartości w baza danych.

Poniżej znajduje się mój kod. Problem polega na tym, że coś jest nie tak, ale nie rozumiem co. Wartość odległości jest oczywiście błędna.

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

Dla wartości na przykład: $ ac = +41,9133741000 $ LNG = 12,5203944000

mam wyjście odległości = "+4826,9341106926"

+0

Sprawdzanie wsporniki –

Odpowiedz

43

Formuła, której użyłeś, wydaje się być arccosine zamiast z haversine formuły. Formuła haversine jest rzeczywiście bardziej odpowiednia do obliczenia odległości na kuli, ponieważ nie jest podatna na błędy zaokrąglania z punktami antypodalnymi.

/** 
* 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. Nie mogłem znaleźć błędu w twoim kodzie, więc czy jest to tylko literówka, którą napisałeś $lat= 41.9133741000 $lat= 12.5203944000? Być może właśnie obliczyłeś $ lat = 12.5203944000 i $ long = 0, ponieważ nadpisałeś zmienną $ lat.

Edit:

Testowany kod i powrócił prawidłowy wynik:

$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

Przepraszam, tak, to tylko pomyłka w teście pytania, oczywiście w kodzie użyłem $ lat i $ lng –

+0

Wziąłem formułę [tutaj] (https://developers.google.com/maps/articles/ phpsqlsearch_v3? hl = it # findnearsql). z twoją funkcją mam (z tym samym wejściem powyżej) wynik "4826934.1106926". czemu? –

+0

@ user1938352 - Czy próbowałeś zadeklarować zmienną jako liczbę zamiast ciągu? Twój przykład używa '$ center_lat =" 41.8350 ";' gdzie powinno być '$ center_lat = 41.8350;', może analizuje "." jako separator tysięcy w zależności od ustawień regionalnych. – martinstoeckli

1

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

Jak widać, istnieje wiele różnic między tym kodem. Nie wiem, czy masz inne podejście do formuły, czy może jakiś krok, gdy konwersja do PHP poszła źle, ale powyższa formuła powinna działać.

+0

to dać mi ten sam wynik mojej metody, więc myślę, że problem tkwi w wartościach wejściowych. ale gdzie jest błąd? –

1

obliczyć odległości prosto wewnątrz zapytań, stosując następującą procedurę przechowywaną:

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| 

Wystarczy wykonać powyższe jako instrukcja SQL z poziomu phpMyAdmin stworzyć procedurę. Zwróć uwagę na zakończenie |, więc w twoim oknie wejściowym SQL wybierz dla | zarejestruj jako ogranicznik.

Następnie w zapytaniu, nazwać tak:

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

I okazało się, że o wiele szybciej niż jej obliczenia w PHP po kwerenda jest prowadzony.

+0

Nawiasem mówiąc, to oblicza odległość w metrach, więc możesz podzielić ją przez 1000 lub zaokrąglić ją w jakiś sposób, aby obliczyć 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

I czyni klasę haversign który posiadającej statyczną fuction getDistance mający cztery paramters i zwróci odległość od punktów lokalizacji botów:

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

powyżej klasy są przechowywane w katalogu głównym i katalog główny zawiera folder klas połączenia to za pomocą poniższego sposób na dowolnej stronie 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; 

wyjściowa jest następująca

4.7676529976827 
Powiązane problemy