2010-02-19 8 views
6

Hay Chcę znaleźć odległość (w milach) między 2 lokalizacjami, używając wartości długich i długich, i sprawdzić, czy są one w promieniu 10 mil od siebie.php mysql porównaj długie i długie, zwrotne poniżej 10 mil

Gdy użytkownik loguje się, ich długość/szerokość geograficzna wartości są zapisywane w sesji

$_SESSION['lat'] 
$_SESSION['long'] 

Mam 2 funkcje

Ten odrabia dystans w milach i zwraca wartość zaokrągloną

function distance($lat1, $lng1, $lat2, $lng2){ 
    $pi80 = M_PI/180; 
    $lat1 *= $pi80; 
    $lng1 *= $pi80; 
    $lat2 *= $pi80; 
    $lng2 *= $pi80; 
    $r = 6372.797; // mean radius of Earth in km 
    $dlat = $lat2 - $lat1; 
    $dlng = $lng2 - $lng1; 
    $a = sin($dlat/2) * sin($dlat/2) + cos($lat1) * cos($lat2) * sin($dlng/2) * sin($dlng/2); 
    $c = 2 * atan2(sqrt($a), sqrt(1 - $a)); 
    $km = $r * $c; 
    return floor($km * 0.621371192); 
} 

Ten zwraca wartość bool, jeśli odległość między 2 zestawami szerokości i długości jest mniejsza niż 10.

function is_within_10_miles($lat1, $lng1, $lat2, $lng2){ 
    $d = distance($lat1, $lng1, $lat2, $lng2); 
    if($d <= 10){ 
     return True; 
    }else{ 
     return False; 
    } 
} 

Obie funkcje działają zgodnie z oczekiwaniami, jeśli daję 2 zestawy lat/longów, a odległość między nimi wynosi 20 mil, moja funkcja is_within_10_miles() zwraca wartość false.

Teraz mam bazę danych "lokalizacje" (4 pola - ID, nazwa, lat, długie).

Chcę znaleźć wszystkie lokalizacje w promieniu 10 mil.

Wszelkie pomysły?

Edycja: mogę pętli wszystkich i przeprowadzenia is_within_10_miles() na nich, jak to

$query = "SELECT * FROM `locations`"; 
$result = mysql_query($query); 

while($location = mysql_fetch_assoc($result)){ 
echo $location['name']." is "; 
echo distance($lat2, $lon2, $location['lat'], $location['lon']); 
echo " miles form your house, is it with a 10 mile radius? "; 
if(is_within_10_miles($lat2, $lon2, $location['lat'], $location['lon'])){ 
    echo "yeah"; 
}else{ 
    echo "no"; 
} 
echo "<br>"; 

}

Wynik próbka będzie

goodison park is 7 miles form your house, is it with a 10 mile radius? yeah 

potrzebne jakoś wykonać funkcję is_within_10_miles w moim zapytaniu.

edytuj

Ta legenda z http://www.zcentric.com/blog/2007/03/calculate_distance_in_mysql_wi.html wymyślił ten ...

SELECT ((ACOS(SIN($lat * PI()/180) * SIN(lat * PI()/180) + COS($lat * PI()/180) * COS(lat * PI()/180) * COS(($lon - lon) * PI()/180)) * 180/PI()) * 60 * 1.1515) AS distance FROM members HAVING distance<='10' ORDER BY distance ASC 

To faktycznie działa. Problem polega na tym, że chcę wybrać * wiersze zamiast wybierać je jeden po drugim. Jak mogę to zrobić?

+0

Zobacz moją zmianę. Jest to funkcja MySQL, która zrobi to, czego potrzebujesz. –

Odpowiedz

12

Prawdopodobnie nie musisz tego robić w kodzie, prawdopodobnie możesz zrobić to wszystko w DB. jeśli używasz spatial index. MySQL docuemtnation for spatial index

EDIT, aby odzwierciedlić swoją EDIT:

Myślę, że chcesz coś takiego:

SELECT *, ((ACOS(SIN($lat * PI()/180) * SIN(lat * PI()/180) + COS($lat * PI()/180) * COS(lat * PI()/180) * COS(($lon - lon) * PI()/180)) * 180/PI()) * 60 * 1.1515) AS distance FROM locations HAVING distance<='10' ORDER BY distance ASC 

VIA: http://www.zcentric.com/blog/2007/03/calculate_distance_in_mysql_wi.html:

+0

Uaktualniłem pytanie, mam nadzieję, że będzie jaśniejsze. – dotty

+0

Tak, to działa przyjemność, jak jednak wybrać WSZYSTKIE (*) wiersze? – dotty

+0

srry. edytowane ponownie. To po prostu WYBIERZ *, ......... – easement

-1

To powinno wskazać ci właściwy kierunek - gra słów nie jest przeznaczona.

funkcja MySQL znaleźć odległość między dwoma miejscami stosując lat/long

Czasami musimy dowiedzieć się lista miejsc, które są w pewnym promieniu od miejsca centrum, gdzie współrzędne miejsc są zapisywane w bazie danych. Mamy teraz 2 rozwiązania - albo przeprowadź pętlę przez wszystkie miejsca, znajdź odległość od punktu środkowego i zatrzymaj miejsca, które mają odległość mniejszą lub równą promieniowi, albo wykonaj funkcję sql, aby znaleźć odległość dwóch miejsc i wybierz miejsca mające odległość mniejszą lub równą promieniowi. Oczywiście druga opcja jest lepsza od pierwszej. Napisałem więc funkcję Mysql, która wykonuje pracę za Ciebie. W moim przypadku współrzędne zostały zapisane w bazie danych jako ciąg znaków "10.1357002, 49.9225563, 0". Jest to standardowy format współrzędnych, z którego korzysta wielu (na przykład mapa Google).Pierwszym elementem jest długość geograficzna, druga to szerokość geograficzna i możemy zignorować trzecią (zawsze 0). Oto funkcja Mysql, która zwraca odległość między 2 współrzędnymi w Milach.

DELIMITER $$ 

DROP FUNCTION IF EXISTS `GetDistance`$$ 

CREATE FUNCTION `GetDistance`(coordinate1 VARCHAR(120), coordinate2 VARCHAR(120)) 
    RETURNS VARCHAR(120) 
BEGIN 
    DECLARE pos_comma1, pos_comma2 INT; 
    DECLARE lon1, lon2, lat1, lat2, distance DECIMAL(12,8); 

    select locate(',', coordinate1) into pos_comma1; 
    select locate(',', coordinate1, pos_comma1+1) into pos_comma2; 
    select CAST(substring(coordinate1, 1, pos_comma1-1) as DECIMAL(12,8)) into lon1; 
    select CAST(substring(coordinate1, pos_comma1+1, pos_comma2-pos_comma1-1) as DECIMAL(12,8)) into lat1; 

    select locate(',', coordinate2) into pos_comma1; 
    select locate(',', coordinate2, pos_comma1+1) into pos_comma2; 
    select CAST(substring(coordinate2, 1, pos_comma1-1) as DECIMAL(12,8)) into lon2; 
    select CAST(substring(coordinate2, pos_comma1+1, pos_comma2-pos_comma1-1) as DECIMAL(12,8)) into lat2; 

     select ((ACOS(SIN(lat1 * PI()/180) * SIN(lat2 * PI()/180) + COS(lat1 * PI()/180) * COS(lat2 * PI()/180) * COS((lon1 - lon2) * PI()/180)) * 180/PI()) * 60 * 1.1515) into distance; 
    RETURN distance; 

END$$ 

DELIMITER ; 

Przykład użycia:

Powiedzmy, trzeba znaleźć wszystkie kody pocztowe, które są w promieniu 40 mil od miejsca, mającego koordynować „+10,1357002, +49,9225563, 0”. Masz tabelę POSTCODES posiadającą identyfikator pola, kod pocztowy, współrzędne. Więc twój sql powinien wyglądać tak:

select id, postcode from POSTCODES where GetDistance("10.1357002, 49.9225563, 0", coordinates) <= 40; 
+0

Uaktualniłem pytanie, mam nadzieję, że będzie jaśniejsze. – dotty

+0

Spowoduje to określenie odległości dla każdego wpisu w zbiorze wyszukiwania. Zwróci poprawny wynik, ale będzie bardzo nieefektywny, jeśli zbiór wyszukiwania stanie się duży. – VoidPointer

+0

Poprosił o rozwiązanie SQL. –

1

Przed zapytaniu obliczyć maksymalną i minimalną szerokość i długość geograficzną swojego dziesięciomilowego kręgu. To da ci cztery cyfry, więc pierwsza część twojego zdania where wykluczy wszystkie wiersze, które nie mieszczą się w przybliżeniu po 10 milach w każdym polu.

Następnie skomplikowana klauzula rzeczywistej odległości, gdzie klauzula sprawdza tylko te wewnątrz kwadratu, aby sprawdzić, czy są one również wewnątrz kręgu.

Czytaj docs DBMS, aby sprawdzić, czy ocena leniwy zastosuje lub jeśli trzeba będzie zorganizować go jako

SELECT * 
FROM (SELECT * 
     FROM table 
     WHERE (simple rough box clause) 
    ) 
WHERE (complex clause) 

zamiast zwykłego

SELECT * FROM table WHERE (simple clause) AND (complex clause) 
+0

Świetnie, -1 bez komentarza w 2,5 letniej odpowiedzi. – Emyr

+0

Masz +1, ponieważ nie jest to złe pierwsze cięcie. :-) –

-1

punktu pochodzenia do szerokości i długości geograficznej

$orig_lat=23.04988655049843; 
$orig_lon= 72.51734018325806; 
$dist=10; // Radius; 

//Latitude = database field name; 
//Longitude = database field name; 

$query = SELECT *, 3956 * 2 * ASIN(SQRT(POWER(SIN(($orig_lat -abs(dest.Latitude)) * pi()/180/2),2) + COS($orig_lat * pi()/180) * COS(abs(dest.Latitude) * pi()/180) * POWER(SIN(($orig_lon - dest.Longitude) * pi()/180/2), 2))) as distance FROM tbl_name dest having distance &lt; $dist ORDER BY distance limit 10 

Znajdź wszystkie lokalizacje, które znajdują się w promieniu 10 mil.
Dobra robota!

-1

Idę tylko zostawić to tutaj:

https://gist.github.com/899413

jest przykładem, w jaki sposób kwerendy w obrębie kwadratu (między) na całkowite i obniżyć wyniki z sqrt(), aby mieć wyjście zwraca okrągły promień wyników. (Zwraca także odległość w kilometrze). Aby uzyskać ten efekt, musisz przekonwertować wszystkie punkty, wstawiając, na kilometry, aby ułożyć je na płaskiej mapie. (zobacz funkcje php)

wynikiem jest niewiarygodne szybkie wyszukiwanie liczb całkowitych - DUŻO szybsze niż wykonywanie wszystkich obliczeń w zapytaniu, tak jak tutaj zaznacza każda odpowiedź.

(Zbudowałem to dokładnie 10 lat temu ... wydaje się, że nadal jest najmądrzejszym rozwiązaniem z mysql)