Archives de Catégorie: Bing Map

[WP7] GPS Helper

Le développement d’une application GPS peut être laborieux. Certains Best Practices sont à respecter :

  • Il faut, par exemple, demander à l’utilisateur s’il souhaite être localisé, lui permettre de modifier ce choix en tout temps.
  • Pendant la recherche d’une localisation nous pouvons être amené à montrer le chargement.
  • En fonction du matériel, du réseau GPS disponible, on peut être amené à afficher des statuts différents.

J’ai donc commencé une petite library pour simplifier tout ça ( http://wp7gpshelper.codeplex.com/ ). Une fois le GPSToolKit instancié :

  • Vous pourrez démarrer le GPS en appelant simplement la méthode Start(). Les vérifications sur les autorisations se font automatiquement. Le GPS ne démarrera pas si l’utilisateur ne le souhaite pas.
  • Vous abonner aux évènements habituels StatusChanged et LocationChanged.
  • Un booléen IsIndeterminate permet de savoir si le GPS est en train de chercher ou non. L’évènement IsIndeterminateChanged a été ajouté.
  • La propriété GPSParam.IsGpsAuthorized est sérialisée dans l’isolated storage et permet donc de savoir si l’utilisateur a autorisé ou non le GPS.

Vous pourrez ajouter par vous-même un bouton bindé sur le GPSParam.IsGpsAuthorized dans les options de votre application. Pensez par contre à préciser les politiques de confidentialités de votre application vis-à-vis des coordonnées GPS.

J’ai aussi inclus une classe pour faciliter l’implémentation du Geocoding.  Il suffit maintenant d’instancier la classe Geocoding en lui passant votre credential Bing Map (vous verrez comment l’avoir dans ce précédent article : https://onefor4.wordpress.com/2011/01/02/geocoding-en-silverlight-avec-bing-map/), de vous abonner à l’évènement souhaité en fonction de ce que vous voulez faire (GeocodeRequestCompleted ou ReverseGeocodeRequestCompleted) et d’appeler votre requête (idem, MakeReverseGeocodeRequest ou MakeGeocodeRequest) avec les paramètres adéquats.

Cette library est toujours en test. J’ai essayé de commenter le plus possible que cela puisse aussi servir d’exemple.
Il y a juste la partie où je récupère et retourne la localisation dont je ne suis pas très fier. Pour être sûr de récupérer les points depuis le GPS et non depuis le cache ou le réseau, j’évince volontairement les 4 premiers points récupérés. S’il y a de meilleures techniques, je suis preneur Sourire.

Par JC VASSELON

[WP7] Trouver son chemin avec Bing Map

Suite à mon article précédent sur le geocoding : https://onefor4.wordpress.com/2011/01/02/geocoding-en-silverlight-avec-bing-map/ nous allons maintenant voir comment relier des points sur la carte et ensuite comment suivre une route.

Mise en place du module

Ouvrons notre projet WP7 et ajoutons notre carte à notre fichier xaml :

<Microsoft_Phone_Controls_Maps:Map CredentialsProvider= »{Binding MyCredential, ElementName=phoneApplicationPage} » x:Name= »MyMap » Mode= »Road » Center= »{Binding CenterCoord, ElementName=phoneApplicationPage} » ZoomLevel= »10″  >
<Microsoft_Phone_Controls_Maps:MapLayer>
<Microsoft_Phone_Controls_Maps:MapPolyline x:Name= »routeLine » Stroke= »Black » StrokeThickness= »6″ Locations= »{Binding Points, ElementName=phoneApplicationPage} » />
</Microsoft_Phone_Controls_Maps:MapLayer>
</Microsoft_Phone_Controls_Maps:Map>

On remarquera quelques bindings :

– MyCredential : Votre “API Key” que vous avez normalement généré dans l’article précédent

– CenterCoord : Objet GeoCoordinate qui représente les coordonnées sur lesquelles vous souhaitez centrer votre carte.

– Points : objet LocationsCollection, comme son nom l’indique c’est une collection d’objets GeoCoordinate ou Location. Ce sont tous les points par lesquels passera notre ligne.

Ensuite on modifie la propriété MapLayer. C’est celle là qui nous permettra de modifier ensuite notre fond de carte. Ici nous ajoutons un objet MapPolyline nous permettant de tracer justement des lignes. Des lignes qui passeront par des points (Captain Obvious spotted !).
On paramètre notre MapPolyline en lui donnant une couleur “Stroke” et une épaisseur “StrokeThickness”.

Notre code-behind ressemblera à ça :

public Credentials MyCredential { get; private set; }
public GeoCoordinate CenterCoord { get; private set; }
public MainPage()
{
MyCredential = new Credentials(){ApplicationId = « VOTRECLEF »};
CenterCoord = new GeoCoordinate(42.00, 1.337);
Points = new LocationCollection();
InitializeComponent();
}

Traçons notre premier trait

MapPolyline trace donc des traits en passant par les points représentés par des coordonnées stockées dans sa collection Locations.
Créons donc une méthode AddLocation().

private void AddLocations()
{
Points.Add(new GeoCoordinate(42.00, 1.337));
Points.Add(new GeoCoordinate(42.600, 1.42));
}

On appelle notre méthode et nous pouvons voir notre premier trait tracé au nord de l’Espagne (oui l’exemple est totalement abstrait).

Maintenant que l’on voit l’idée, il serait intéressant de pouvoir récupérer une liste de points correspondant à un trajet réel entre deux ou plusieurs lieux !

Récupérons les coordonnées de notre route

Ajoutons une référence de service vers :
http://dev.virtualearth.net/webservices/v1/routeservice/routeservice.svc?wsdl
Créons ensuite nos méthodes qui calculeront et afficheront le trajet entre nos points.

private void CalculateRoute(IEnumerable<GeoCoordinate> Lieux)
{
var routeRequest = new RouteRequest();
routeRequest.Credentials = MyCredential;
routeRequest.Waypoints = new ObservableCollection<Waypoint>();
foreach (GeoCoordinate geoCoordinate in Lieux)
routeRequest.Waypoints.Add(new Waypoint(){Location = geoCoordinate});
var routeService = new RouteServiceClient(« BasicHttpBinding_IRouteService »);
routeService.CalculateRouteCompleted += new EventHandler<CalculateRouteCompletedEventArgs>(routeService_CalculateRouteCompleted);
routeRequest.Options = new RouteOptions();
routeRequest.Options.Mode = TravelMode.Driving;
routeRequest.UserProfile = new UserProfile() { DistanceUnit = DistanceUnit.Kilometer };
routeService.CalculateRouteAsync(routeRequest);
}

Lieux est donc une collection de GeoCoordinate, le LocationsCollection vu précédemment est parfaitement le type de valeur attendu. Vous pouvez donc tester avec notre objet Points.
Rien de compliqué dans cette première méthode. On créé notre requête, on y ajoute notre credential et nos Waypoints (littéralement “points de passages” Clignement d'œil).
On s’abonne à l’évènement levé lorsque les données seront récupérés, on verra la méthode plus bas.
routeRequest.Options.Mode nous permet de choisir grâce à l’énumération TravelMode entre un trajet en véhicule ou à pied.
Et avec l’UserProfile on peut choisir les unités de distances. La doc vous en apprendra plus !
Nous avons là la requête basique, voyons maintenant comment traiter ses valeurs de retours.

void routeService_CalculateRouteCompleted(object sender, CalculateRouteCompletedEventArgs e)
{
Points.Clear();
var P_Start = new Pushpin();
var P_End = new Pushpin();

P_Start.Location = e.Result.Result.Legs.First().ActualStart;
P_End.Location = e.Result.Result.Legs.Last().ActualEnd;

foreach (RouteLeg leg in e.Result.Result.Legs)
foreach (ItineraryItem itineraryItem in leg.Itinerary)
Points.Add(itineraryItem.Location);
MyMap.Children.Add(P_Start);
MyMap.Children.Add(P_End);
}

La partie la plus intéressante dans le résultat de notre requête est la collection “Legs”. Elle contient des objets Leg qui sont des portions de routes. En effet, un trajet passe par différents points, donc du coup un trajet est un ensemble de petits segments passant par ces points : les legs.

On fait un Clear() sur notre collection de Points histoire de mettre à jour notre trajet.
Je créé ensuite des Pushpins, ces petites flèches sur la carte qui nous permettront de savoir où démarre et finis le trajet.
Je les positionne en utilisant leur propriété Location et en récupérant le premier point du premier leg de ma collection pour le départ et bien sûr le dernier point du dernier leg pour l’arrivée.
Ensuite je parcours la collection pour ajouter à ma liste de points les coordonnées de chaque segment.

On n’oublie pas d’ajouter les push pins à la carte et voilà vous avez votre trajet !
En couplant ça à la géolocalisation et au geocoding de nombreuses possibilités s’offrent à vous !

Par JC VASSELON

Geocoding en Silverlight avec Bing Map

Le geocoding permet de transformer une adresse en coordonnée (latitude, longitude). Au contraire, le reverse geocoding permet de récupérer une adresse à partir de coordonnées.

Nombreuses sont les ressources autour de ce sujet en utilisant les services Bing Map. Que ce soit par une référence web ou en REST en requêtant depuis notre application.
Mais l’utilisation en silverlight est moins documentée. Le développeur se retrouvant dans l’impossibilité d’ajouter une web reference, avec des noms des classes différents, et une utilisation asynchrone…

Dans cet article nous allons donc présenter les prérequis et dégrossir le fonctionnement du geocoding par le code.

Créer un compte bing map

Première étape, créez votre compte Bing Map sur https://www.bingmapsportal.com/.

Une fois votre compte créez cliquez sur “Create or view keys” :

ScreenBingMapPortal

Dans “Application name” entrez le nom de votre application.
Pour “Application URL” donnez l’adresse de la page de votre application ou une adresse quelconque.
Le champ “Application Type” est important, n’hésitez pas à cliquer sur le bouton “What’s this ?” pour plus d’explications. En effet, cela concerne la licence et l’utilisation du service Bing Map par votre application.
Pour cette démo nous utiliserons le type “Developer”.

Une fois la clef générée, gardez-la sous la main nous allons bientôt l’utiliser.

Au sein du projet Silverlight (ou WP7)

Créez donc votre projet silverlight ou Windows Phone 7.
Ajoutez une référence de service à l’adresse : http://dev.virtualearth.net/webservices/v1/geocodeservice/geocodeservice.svc/mex
Pour cet article nous nommerons la référence “GeocodeService”.

Déclarons un objet de type Credentials qui permettra de nous authentifier au service.
Déclarons aussi un objet de type GeocodeRequest pour formuler notre requête.

private GeocodeRequest GeocodeRequest;
private Credentials myCredentials;

Créons ensuite une méthode InitGeocode() dans laquelle nous préparerons l’authentification au service.

private void InitGeoCodeRequest()
{
myCredentials = new Credentials();
myCredentials.ApplicationId = VOTRE_CLEF_GENEREE_DANS_LA_PARTIE_PRECEDENTE;
GeocodeRequest = new GeocodeRequest();
GeocodeRequest.Credentials = myCredentials;
}

Il ne nous reste plus qu’à faire une méthode qui recevra en paramètre un lieu et qui le geocodera.

private void MakeGeocodeRequest(string query)
{
    try
    {
        GeocodeRequest.Query = query;
        var geocodeService = new GeocodeService.GeocodeServiceClient(« BasicHttpBinding_IGeocodeService »);
geocodeService.GeocodeCompleted += delegate(object sender, GeocodeService.GeocodeCompletedEventArgs e)
{
if (sender != null)
{
//Location est une variable que j’utilise pour stocker le résultat de la méthode. A vous de voir comment vous souhaiter le traiter.
Location = e.Result.Results[0].Locations[0];
}
};
geocodeService.GeocodeAsync(GeocodeRequest);
}
   catch(Exception ex)
{
MessageBox.Show(« An exception occurred: «  + ex.Message);
}
}

De la même manière, pour récupérer une adresse depuis des coordonnées, il vous suffit de passer en paramètre un objet de type GeocodeLocation et d’utiliser l’event handler ReverseGeocodeCompleted à la place de GeocodeCompleted.
Bien évidemment, le delegate prendra un ReverseGeocodeCompletedEventArgs à la place du GeocodeCompletedEventArgs.
Ensuite faites l’appel asynchrone avec la méthode ReverseGeocodeAsync (et non plus GeocodeAsync) sur un objet de type ReverseGeocodeRequest initalisé de la même manière que le GeocodeRequest.
L’objet retourné sera de type Address.

Pour aller plus loin :
http://msdn.microsoft.com/en-us/library/cc966793.aspx
qui vous expliquera ce que retourne le  service : un GeocodeResponse. Il contient un GeocodeResult et la doc est intéressante au niveau de cet élément (plusieurs attributs peuvent vous intéresser comme le type Address introduit plus haut).

Par JC VASSELON