La géolocalisation sur mobile avec HTML 5

Publié par Vincent Crépin le mercredi 8 mai 2013 à 20:43

Une des nouvelles fonctionnalités intéressantes que HTML 5 fournit  est la capacité de géo-localiser l’utilisateur peu importe la plateforme sur laquelle l’application s’exécute. Par exemple, dans un navigateur standard, l’adresse IP sera utilisée (ce qui est souvent très imprécis) mais sur un téléphone intelligent, le GPS sera utilisé s’il est disponible et activé. Cela se fait de façon transparente. Dans cet article, je m’attarderai à la géo-localisation sur les plateformes mobiles qui utilisent le GPS.

HTML 5 fournit deux fonctionnalités de géo-localisation : soit obtenir la position actuelle ou effectuer un suivi de la position dans le cas où la personne se déplace (watch). Dans les 2 cas, les données retournées sont sous la forme d’une position qui comprend les coordonnées géo-spatiales (longitude et latitude), la vitesse de déplacement, l’altitude et une précision de la position obtenue en mètres. Les exemples de code suivants illustrent la simplicité de cet API :

function getLocation() {
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(showPosition);
    } 
    else {
        x.innerHTML="Geolocation is not supported by this browser.";
    }
}

function showPosition(position) {
    x.innerHTML="Latitude: " + position.coords.latitude + "<br />Longitude: " + position.coords.longitude;
}

function getWatchLocation() {
    if (navigator.geolocation) {
        navigator.geolocation.watchPosition(showWatchPosition);
    } else {
        x.innerHTML="Geolocation is not supported by this browser.";
    }
}
function showWatchPosition(position) {
    x.innerHTML="Latitude: " + position.coords.latitude + "<br />Longitude: " + position.coords.longitude;  
}

La première function (getLocation) invoque l’API asynchrone de géolocalisation (tout est asynchrone ou presque en Javascript…) et appelle notre function callback (showPosition) lorsqu’un résultat est disponible. Dans celle-ci, on affiche simplement les coordonnées obtenues (longitude et latitude dans un DIV. La deuxième fonction (watchLocation) se comporte de la même façon mais cela déclenche un traitement qui retourne une nouvelle position à environ toutes les secondes.  Le callback (showWatchPosition) est donc appelé à chaque fois.

Il est donc très facile avec ces données de tracer un parcours sur une carte en utilisant l’API de Google Maps qui ne nécessite aucune installation, seulement l’ajout d’une référence javascript:

<script 
    type="text/javascript" 
    src="https://maps.googleapis.com/maps/api/js?v=3&&libraries=geometry&sensor=true">
</script>

Une des applications que j’ai développées comportait justement ce besoin de suivre la route de l’utilisateur en temps réel et de la représenter sur une carte. Une première implémentation simple plaçait les points sur la carte et les reliait à l’aide d’une polyline (ligne droite entre deux points) ce qui est facilement supporté par Google Maps.

L’exemple de code suivant tiré de la documentation de Google démontre comment tracer une ligne sur la carte. Dans cet exemple, on construit un plan de vol fictif que l’on affiche sur une carte.

function initialize() {
  var myLatLng = new google.maps.LatLng(0, -180);
  var mapOptions = {
    zoom: 3,
    center: myLatLng,
    mapTypeId: google.maps.MapTypeId.TERRAIN
  };
  var map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
  var flightPlanCoordinates = [
    new google.maps.LatLng(37.772323, -122.214897),
    new google.maps.LatLng(21.291982, -157.821856),
    new google.maps.LatLng(-18.142599, 178.431),
    new google.maps.LatLng(-27.46758, 153.027892)
  ];
  var flightPath = new google.maps.Polyline({
    path: flightPlanCoordinates,
    strokeColor: "#FF0000",
    strokeOpacity: 1.0,
    strokeWeight: 2
  });
  flightPath.setMap(map);
}

On voit que pour tracer le parcours, il faut fournir une série de coordonnées géospatiales et construire une polyline avec ces coordonnées. On indique ensuite sur quelle carte (map) la ligne doit être tracée et cela se fait automatiquement comme la figure ci-dessous le démontre.

Cette implémentation de base comporte plusieurs problèmes. Ils concernent tous la précision de la route obtenue. Un des buts importants de cette fonctionnalité dans mon application est de calculer la distance parcourue. En utilisant des lignes droites entre les points, le nombre de points requis est très grand pour tenir compte des changements de direction. De plus, la précision des points obtenus par le GPS est très variable ce qui donne parfois des distances complètement erronées. J’ai donc dû utiliser des stratégies de filtration des points pour obtenir des données plus précises.

La première modification que j’ai apportée est de rejeter les points GPS qui comportent une précision trop faible (exemple : plus de 30 mètres). Cela a aidé un peu mais une bonne précision ne garantit pas la précision réelle du point parce que la précision obtenue du GPS peut être imprécise elle aussi!!!

La deuxième modification que j’ai apportée est d’utiliser le service de directions de Google (Direction Service). Celui-ci permet de tracer une route entre deux points en utilisant une carte routière et aussi d’obtenir la distance entre ces points. C’est déjà une amélioration considérable puisque les points utilisés par l’API se trouvent nécessairement sur une route. Donc en fournissant mes points GPS, le service de directions essaiera de trouver une route entre ces deux points même si les points ne sont pas exactement sur la route en question. Mon application en étant une de suivi routier, cela convient parfaitement. L’exemple de code suivant tiré de la documentation de Google illustre l’utilisation de cet API :

var directionsDisplay;
var directionsService = new google.maps.DirectionsService();
var map;

function initialize() {
  directionsDisplay = new google.maps.DirectionsRenderer();
  var chicago = new google.maps.LatLng(41.850033, -87.6500523);
  var mapOptions = {
    zoom:7,
    mapTypeId: google.maps.MapTypeId.ROADMAP,
    center: chicago
  }
  map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
  directionsDisplay.setMap(map);
}

function calcRoute() {
  var start = document.getElementById("start").value;
  var end = document.getElementById("end").value;
  var request = {
    origin:start,
    destination:end,
    travelMode: google.maps.TravelMode.DRIVING
  };
  directionsService.route(request, function(result, status) {
    if (status == google.maps.DirectionsStatus.OK) {
      directionsDisplay.setDirections(result);
    }
  });
}

En gros, on invoque cet API en lui spécifiant 2 points et il nous retourne une route qui tient compte des routes terrestres véritables pour aller du départ à la fin. L’objet directionsDisplay permet de tracer automatiquement cette route sur une carte sans avoir à traiter les points intermédiaires. Mais il est aussi possible de tracer nous même les points si on veut appliquer des traitements particuliers.

Mais cela ne s’est pas avéré suffisant pour répondre à mes besoins. Il peut en effet arriver que des points erronés se trouvent sur une route secondaire et le service de directions essaiera de trouver une route qui tient compte de cette route secondaire même si on ne l’a pas visitée réellement. Cela se produit surtout dans les quartiers résidentiels où les routes sont très rapprochées. J’ai donc dû ajouter un troisième correctif important. J’ai créé un algorithme de filtration assez simple : pour chaque point qui est fourni par le GPS, je calcule la distance linéaire et la distance obtenue du service de direction de Google et j’utilise la vitesse moyenne des 2 derniers points ainsi que le temps écoulé entre les deux. Je compare ces valeurs et si la valeur linéaire calculée est beaucoup plus grande que la valeur obtenue en tenant compte de la vitesse moyenne, je rejette simplement ce point. Cette stratégie a complètement éliminé les points qui se situent sur les routes secondaires puisque le temps requis pour parcourir cette distance serait beaucoup trop grand par rapport au temps réel.

Me restait un cas à régler. Si on fait du surplace pendant un certain temps (arrêt à une lumière par exemple), et que pendant ce temps on obtient un point sur une route secondaire, le temps écoulé pourrait permettre d’avoir parcouru cette fausse distance. J’ai donc finalement rejeté tous les points GPS pour lesquels la vitesse est très basse (ex : moins de 0,5 mètres par seconde).

En conservant tous les points retenus dans une base de données (voir le billet précédent sur ce sujet), il est possible de consulter les routes parcourues comme l’illustre la figure suivante :

 Geolocalisation-mobile-exemple

En conclusion, les outils de géo-localisation disponibles sur les plateformes mobiles avec HTML 5 sont très puissants mais il est nécessaire d’appliquer une certaine intelligence au traitement pour obtenir des données précises. Et cette expérimentation m’a amené à supposer que les compagnies telles que TomTom ou Garmin ont accès à des données satellites de grande qualité ou possèdent des algorithmes très élaborés.

blog comments powered by Disqus

0 Comments:

Post a comment

Comments have been closed for this post.