[PHP/SQL] Géolocalisation et distance entre des villes
- Par
- Le Mer 24 sept 2008
- Dans Développement web
- 50 commentaires
J'ai besoin pour un développement spécifique mais aussi pour Agenda Culturel de pouvoir lister dans un script PHP les villes à proximité d'une ville donnée. Concrètement, cela signifie afficher les villes situées à l'intérieur d'un périmètre d'une distance de X kilomètres de la ville de référence.
J'ai longuement cherché sur le web, et je n'ai trouvé que peu d'infos à ce sujet. Je vous livre ici le résultat de mes recherches et de mes multiples tests, de l'intégration des coordonnées de latitude/longitude à l'aide des API de géolocalisation google map et yahoo map jusqu'à la requête sql finale qui inclue la formule de calcul de distance à partir des coordonnées géolocalisées.
Une base de donnée fiable des villes associées à leurs coordonnées de latitude/longitude
En premier lieu, il s'agit d'avoir une base de données de villes. Il en existe de nombreuses sur le net, celle-ci intègre même les coordonnées de latitude et de longitude.
Dans mon cas, je possédais déjà une base de données de villes françaises mais sans ces coordonnées. La meilleure méthode pour y intégrer la latitude et la longitude de chaque ville est d'utiliser l'API de Yahoo ou de google.
Ces deux API permettent de récupérer un flux XML correspondant à la recherche (ex : Amiens, France) contenant la latitude et la longitude.
Par exemple, voici le résultat de la recherche de la ville d'Amiens avec l'API de Yahoo :
<ResultSet xsi:schemaLocation="urn:yahoo:maps http://api.local.yahoo.com/MapsService/V1/GeocodeResponse.xsd">
<Result precision="zip">
<Latitude>49.896309</Latitude>
<Longitude>2.279720</Longitude>
<City>80000 Amiens</City>
<State>France</State>
<Country>FR</Country>
</Result>
</ResultSet>
Il n'y a donc plus qu'à faire une boucle sql sur la table des villes en parsant le flux de yahoo ou google correspondant (en indiquant la ville, le code postal et le pays) et intégrer à l'enregistrement de la ville la latitude et la longitude. Un vrai jeu d'enfant avec simplexml en php5 ! Cependant, même si ces API sont puissantes, il se peut que parfois la ville ne soit pas trouvée, que la ville retournée ne soit pas la bonne ou que plusieurs résultats soient retournés. Pour plus d'informations, et pour choisir entre les API de Yahoo et de Google, je vous invite à lire cet article sur la géolocalisation via yahoo et google map très bien fait et qui m'a bien aidé.
Vous avez à présent une table contenant les villes associées à leurs coordonnées géographique de latitude et de longitude.
Il ne reste plus qu'à exploiter cela dans une requête SQL et afficher le tout en PHP.
J'ai d'abord tenté une conversion des données latitude/longitude en points de coordonnées lambert 2 étendue (norme française) grâce à la fonction geos2lambert() disponible sur google code mais son exploitation s'est révélé compliquée et imprécise (ou alors c'est moi qui suis vraiment nul en maths !).
Je suis donc reparti sur les données de latitude/longitude. Grâce à une formule mathématique complexe trouvée sur le net je suis arrivé au résultat suivant.
Je reçois en variable GET les coordonnées de ma ville de référence :
$latitude=$_GET[lat];
$longitude=$_GET[lon];
La fameuse formule utilisant les colonnes lat et lon de ma table sql et les données de latitude et longitude de ma ville de référence :
$formule="(6366*acos(cos(radians($latitude))*cos(radians(`lat`))*cos(radians(`lon`) -radians($longitude))+sin(radians($latitude))*sin(radians(`lat`))))";
Et la requête SQL prête à être exécutée :
$sql="SELECT ville,$formule AS dist FROM ville WHERE $formule<='$_GET[distance]' ORDER by dist ASC";
- le SELECT $formule AS dist permet de classer les villes de la plus proche à la plus éloignée avec ORDER by dist ASC
- le WHERE $formule<='$_GET[distance]' permet de définir un rayon en km ($_GET[distance]) à partir de la ville de référence
Je vous laisse coder l'éxécution de la requête sql et l'affichage des données en php, ce n'est pas vraiment le plus dur !
En guise de conclusion...
Il faut savoir que ce calcul et le résultat ne sont pas précis pour plusieurs raisons :
- Le calcul ne tient pas compte de l'altitude, qui, dans certains endroits peut influer sur les distances
- La formule a été simplifiée au maximum par souci de simplicité et d'efficacité.
- La distance est "à vol d'oiseau" et non pas une distance routière
- La localisation latitude/longitude d'une ville repose sur un point (généralement la mairie de la ville en question), donc la distance ne commence pas à la sortie de la ville mais du centre de la ville. Ainsi, par exemple, pour Paris cela ne sert à rien de vouloir localiser les villes à 5km...
Cependant, malgré l'imprécision cela fonctionne, car l'intérêt premier est d'afficher les villes proches et non de concurrencer google map ! Il convient juste de ne pas forcément afficher les distances en km qui sont souvent fausses (à quelques kilomètres près).
L'utilisation de cette technique qui est finalement assez simple à mettre en place peut être très utile sur du web local afin d'élargir les recherches sur une ville aux villes à proximité (dans le cas où aucune réponse n'est disponible pour la ville concernée par exemple) ou proposer d'autres villes ou contenus (ou publicités géolocalisées !) à l'internautes en rapport avec sa requête.
Si vous avez des questions sur la mise en place d'une recherche de proximité ou si cet article vous a aidé, n'hésitez pas, les commentaires sont fait pour ça !
Commentaires
-
- 1. Aymen Le Lun 20 mars 2017
un grand merci pour ce tuto, ce que je cherche vraiment.
merci -
- 2. charles Le Jeu 05 nov 2015
Impeccable ! Merci beaucoup. -
- 3. Vince Le Ven 04 avr 2014
Top ! Merci bcp, j'ai gagné un peu pres 2 ans de dév :)) -
- 4. tom_over Le Mar 21 mai 2013
Bonjour,
J'utilise depuis 2 ans votre requête sql pour définir périmètre sur googlemap et je rencontre un problème depuis quelques mois. Certainement suite à une mise à jour de SQL :
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '))*cos(radians(`cm_membergooglemaps_lat`))*cos(radians(`cm_membergooglemaps_lng`' at line 1
Avez-vous rencontré le même problème ? Avez-vous une astuce pour contourner le problème ?
Merci pour votre aide -
- 5. oam Le Jeu 16 mai 2013
6366 = rayon sphère terrestre -
- 6. Beta test Le Lun 04 mars 2013
pour les distances routiere, il est possible de le faire via l'api de google mais cela deviens compliqué et lourd a gérer.
Voici l'astuce.
tu fais la recherche de ta ville (la meme que celle ici plus haut par exemeple.) on peut conciderer que chaque ville est située a un parcour plus long par la route qu'a vole d'oiseau. il te reste a faire (apres avoir recu la reponse de ton calcul) un passage de chaque ville/village dans l'appli googlemaps pour savoir la distance entre ces 2 points tu pourra meme proposer a tes internautes la distance a pied ou en bus.
Mais attention, comme dis plus haut c'est lourd. A la campagne ca va encore mais une recherche sur les grandes villes prend des plombes -
- 7. Nicolas Le Sam 29 déc 2012
Ouaah !!
Un grand merci pour ce tuto avec en plus des explications très claires.
Super ! -
- 8. Webbax Le Jeu 13 déc 2012
Hello,
Un très grand merci pour cette formule, je viens de tester ça sur mon projet... ça fonctionne nickel. On dira ce qu'on veut... mais sans formule... ben on est mal pris ;)
Bonne continuation ! -
- 9. wiloooo Le Jeu 25 oct 2012
Je crois qu'il y a une erreur dans la démonstration :-/ non ? -
- 10. Prdo Le Jeu 04 oct 2012
Bonjour,
Depuis plusieurs jours je recherche un système de ce genre mais plus complet. Je voudrais que les distance soit prise à échelle routière.
Exemple : J'envoie Amiens, j'ai toutes les villes se situant à 10 kilomètre d'Amiens par voie routière et non d'oiseau qui sorte.
Quelqu'un aurait quelque chose qui va dans ce sens ?
Je vous remercie
Ajouter un commentaire