2010-08-31 33 views
8

J'écris un site qui cherche essentiellement des endroits dans un rayon de 25 mile d'un lat et long en utilisant php et mysql. Je me demande comment quelque chose comme ça fonctionnerait?PHP MySql et la géolocalisation

Je voudrais passer un lat et long à la scrip et le faire retirer seulement les emplacements qui sont dans les 25 miles du lat et long de ma base de données de lieux.

Quelle est la meilleure façon de faire cela?

EDIT: J'ai trouvé ce code pour calculer la distance entre 2 points.

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

est-ther une façon de le faire dans le calc MYSQL ne regarder que pour que je puisse retourner si miles = < 25?

+0

D'où tire-t-il les autres emplacements? Avez-vous tous lat/long stocké dans un tableau ou une base de données? – shamittomar

+0

J'ai modifié la question. Je vais avoir certains endroits dans ma base de données et je verrai si l'un d'entre eux sont dans les 25 miles. Sinon, aucun n'est retourné. – shaneburgess

+0

un peu plus d'informations ici: http://stackoverflow.com/questions/20865747/geolocation-mysql-query – miralong

Répondre

6

Calculer la distance à l'aide de cette fonction est très coûteux en termes de calcul, car il implique tout un tas de fonctions transcendantales. Cela va poser problème lorsque vous avez un grand nombre de lignes à filtrer.

est ici une alternative, une approximation qui est beaucoup moins informatiquement cher:

distance approximative en miles:

sqrt(x * x + y * y) 

where x = 69.1 * (lat2 - lat1) 
and y = 53.0 * (lon2 - lon1) 

Vous pouvez améliorer la précision de ce calcul de la distance approximative en ajoutant la fonction mathématique cosinus:

distance approximative améliorée en miles:

sqrt(x * x + y * y) 

where x = 69.1 * (lat2 - lat1) 
and y = 69.1 * (lon2 - lon1) * cos(lat1/57.3) 

Source: http://www.meridianworlddata.com/Distance-Calculation.asp


J'ai couru un tas de tests avec des jeux de données générés au hasard.

  • La différence de précision pour les 3 algorithmes est minimale, en particulier sur de courtes distances
  • Le plus lent algorithme est, bien sûr, celui avec les fonctions trigonométriques (celui sur votre question). Il est 4x plus lent que les deux autres.

Certainement pas la peine. Juste aller avec une approximation.
code est ici: http://pastebin.org/424186


Pour utiliser sur MySQL, créez un stored procedure qui prend coordonnées arguments et retourne la distance, alors vous pouvez faire quelque chose comme:

SELECT columns 
    FROM table 
WHERE DISTANCE(col_x, col_y, target_x, target_y) < 25 
0

Vous pouvez le faire facilement en deux étapes:

  • Trouver tous les endroits de 25 miles dans chaque direction du point.Cela ressemblera à: WHERE lat BETWEEN $lat1 AND $lat2 AND lng BETWEEN $lng1 AND $lng2

  • Ensuite, bouclez chaque résultat et vérifiez s'il est vraiment dans les 25 miles en utilisant votre code. (.-À-dire, filtrer les endroits qui sont dans les coins du carré)

Pour la première partie, voici un code que j'ai autour de la pose (ne me souviens pas de la source):

$lat_range = $radius/((6076/5280) * 60); 
$lng_range = $radius/(((cos(($city['lat'] * 3.141592653589/180)) * 6076)/5280) * 60); 

Fondamentalement, il suffit d'utiliser ($lat - $lat_range, $lat + $lat_range) et ($lng - $lng_range, $lng + $lng_range) Le rayon est en miles.

Évidemment, vous pouvez nettoyer un peu les maths. Edit: J'ai oublié de mentionner que vous auriez besoin de l'ajuster un peu si vous avez besoin de supporter des emplacements près de l'équateur, de la ligne de date internationale, etc. Évidemment pour l'Amérique du Nord, ce serait bien comme ça.

+0

Cela a bien sûr l'inconvénient de nécessiter deux étapes de filtrage, car il renvoie des lignes inutiles. – NullUserException

+0

Oui, mais cela évite d'effectuer des calculs sur l'ensemble de la base de données. Avec un petit rayon et un grand ensemble de données, cela peut être important. – Matthew

2

Vous pouvez jeter un oeil à this solution - une solution de contournement quelque peu brillante.