Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Matthieu Napoli

blog technique

Géolocalisation et approximations (ou comment simplifier le calcul avec des latitudes et longitudes en PHP)

Bonjour à tous,
Aujourd'hui, un petit article sur la manipulation de coordonnées géographiques dans vos applications, notamment ici dans un site web en PHP.

Cet article fait suite au peu de documentation que j'ai constaté en recherchant le web.

1ère méthode : Calculs précis

Le "calcul précis" présenté ici est déjà une approximation, mais c'est la solution qu'on rencontre le plus souvent dans les forums :

define('RAYON_TERRE', 6378137);

/**
* Retourne la distance précise à vol d'oiseau entre 2 coordonnées
* @param double latitude du point 1
* @param double longitude du point 1
* @param double latitude du point 2
* @param double longitude du point 2
* @return double Distance entre les points 1 et 2
*/

function get_distance_precis($lat1, $long1, $lat2, $long2)
{
  $rlo1 = deg2rad($long1);
  $rla1 = deg2rad($lat1);
  $rlo2 = deg2rad($long2);
  $rla2 = deg2rad($lat2);

  $dlo = ($rlo2 - $rlo1) / 2;
  $dla = ($rla2 - $rla1) / 2;
  $a = (sin($dla) * sin($dla)) + cos($rla1) * cos($rla2) * (sin($dlo) * sin($dlo));
  $d = 2 * atan2(sqrt($a), sqrt(1 - $a));

  return (RAYON_TERRE * $d);
}

Bilan :

  • Calcul compliqué et lent
  • Propre à PHP, s'implémente difficilement dans une requête SQL (pour faire un SELECT en prenant en compte la distance par exemple)

2ème méthode : Approximation

On remarquera que le calcul suivant renvoie un résultat linéaire :

echo get_distance_precis(0.0, 0.0, 0.001, 0);
echo get_distance_precis(0.0, 0.0, 0.01, 0);
echo get_distance_precis(0.0, 0.0, 0.1, 0);
echo get_distance_precis(0.0, 0.0, 1., 0.);

111.31949079327
1113.1949079327
11131.949079327
111319.49079327

On peut donc utiliser le facteur proportionnel get_distance_precis(0.0, 0.0, 1., 0.) ce qui donne la fonction suivante :

define('CONVERSION_LATLONG_METRES', 111319.49079327);

/**
* Retourne la distance approximative à vol d'oiseau entre 2 coordonnées
* @param double latitude du point 1
* @param double longitude du point 1
* @param double latitude du point 2
* @param double longitude du point 2
* @return double Distance entre les points 1 et 2
*/

function get_distance_approx($lat1, $long1, $lat2, $long2)
{
  $delta_lat = $lat2 - $lat1;
  $delta_long = $long2 - $long1;
  $dist_lat = $delta_lat * CONVERSION_LATLONG_METRES;
  $dist_long = $delta_long * CONVERSION_LATLONG_METRES;
  $distance = sqrt($dist_lat * $dist_lat + $dist_long * $dist_long);
  return $distance;
}

Vérification des résultats :

echo get_distance_precis(0.0, 0.0, 0.001, 0);
echo get_distance_precis(0.0, 0.0, 0.01, 0);
echo get_distance_precis(0.0, 0.0, 0.1, 0);
echo get_distance_precis(0.0, 0.0, 1., 0.);
echo get_distance_approx(0.0, 0.0, 0.001, 0);
echo get_distance_approx(0.0, 0.0, 0.01, 0);
echo get_distance_approx(0.0, 0.0, 0.1, 0);
echo get_distance_approx(0.0, 0.0, 1., 0.);

111.31949079327
1113.1949079327
11131.949079327
111319.49079327

111.31949079327
1113.1949079327
11131.949079327
111319.49079327

Bilan :

  • Calcul simple et rapide
  • Peut s'implémenter facilement dans une requête SQL en utilisant le facteur de conversion.

Bonus : Faire l'inverse, décaler une latitude/longitude avec une distance

Au lieu de calculer la distance entre 2 points, on peut vouloir décaler une coordonnées (pour par exemple faire un carré autour d'un point).
Pour cela voici la fonction suivante :

define('CONVERSION_LATLONG_METRES', 111319.49079327);

/**
* Décale la latitude ou la longitude de la distance spécifiée
* @return angle de décalage
*/

function get_angle_decalage_geo($distance)
{
  return $distance / CONVERSION_LATLONG_METRES;
}

Cette fonction renvoie le décalage à appliquer à une latitude ou une longitude pour obtenir un point situé à la distance précisée.

Vérification des résultats :

echo get_angle_decalage_geo(100);
echo get_distance_approx(0.0, 0.0, get_angle_decalage_geo(100), 0.);

0.00089831528411955
100

Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :
Posted: lundi 13 juillet 2009 11:01 par MadMatt
Classé sous : , ,

Commentaires

LeFauve42 a dit :

Solution tres elegante, mais es-tu sur que cela fonctionne dans tous les cas ?

Je remarque que tu ne testes pas les decalages de longitude.

Si tu te deplace de 90 degres de longitude sur l'equateur (lattitude de 0 degres), tu fais (environ) 10000km, mais si tu te deplaces de 90 degres de longitude a partir du pole nord (lattitude de 90 degres), tu ne bouges pas :o)

As-tu regarde l'extension OpenGIS de MySQL ? Je ne suis pas sur que ca reponde entierement a ton probleme, mais ca doit le simplifier un peu(http://dev.mysql.com/doc/refman/5.4/en/gis-introduction.html)

Eric

# juillet 20, 2009 10:42

MadMatt a dit :

Non cela ne fonctionne pas dans tous les cas car le but est d'approximer le calcul, notamment pour des distances de l'ordre du km, en France (du moins pas pour les extrêmes comme le pole Nord ^^).

J'utilise ça pour des calculs de distance de moins de 500m, donc ça marche très bien ;)

En tout cas je ne connaissais pas OpenGIS, merci pour l'info, ça a l'air vraiment intéressant.

# juillet 20, 2009 11:01

LeFauve42 a dit :

OK :o)

Si tu utilises cette formule uniquement pour la France, tu aurais interet a utiliser deux constantes au lieu de CONVERSION_LATLONG_METRES :

- Une pour les lat (celle que tu as est pas mal)

- Une pour les long, que tu pourrais calculer pour une lat de 46.5 degres (a la louche, le milieu de la France (si on ne compte pas la Corse)).

Ton calcul ne serait pas plus lent, mais ton approximation serait bien meilleure :o)

Eric

# juillet 20, 2009 13:52
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- SharePoint 2013: Préparation de la migration - Création des site Templates dans 2010 et 2013 par Blog Technique de Romelard Fabrice le 08-20-2014, 16:31

- [ #Yammer ] How to change interface language ? Comment changer la langue de l’interface ? par Le blog de Patrick [MVP SharePoint] le 08-20-2014, 14:21

- Onedrive Sync Engine Host : CPU à 100% par Le petit blog de Pierre / Pierre's little blog le 08-06-2014, 22:22

- SharePoint : Bug sur la gestion des permissions et la synchronisation Office par Blog Technique de Romelard Fabrice le 07-10-2014, 11:35

- SharePoint 2007 : La gestion des permissions pour les Workflows par Blog Technique de Romelard Fabrice le 07-08-2014, 11:27

- TypeMock: mock everything! par Fathi Bellahcene le 07-07-2014, 17:06

- Coding is like Read par Aurélien GALTIER le 07-01-2014, 15:30

- Mes vidéos autour des nouveautés VS 2013 par Fathi Bellahcene le 06-30-2014, 20:52

- Recherche un passionné .NET par Tkfé le 06-16-2014, 12:22

- [CodePlex] Projet KISS Workflow Foundation lancé par Blog de Jérémy Jeanson le 06-08-2014, 22:25