Astuces DotNet (Sébastien Courtois)

01/02/2010

[Bing Maps] Développement Microsoft Bing Maps Web Services – Part 5 : Search Service

Filed under: .NET, Bing Maps, Débutant, Intermediaire, Virtual Earth — Étiquettes : , , , — sebastiencourtois @ 21:22

Cet article est une suite de l’article se trouvant ici. Il était question de créer un compte Bing Maps et se connecter en C# aux différents services Web de Virtual Earth.

Liens des posts sur le sujet sur ce blog :

  1. Introduction à Microsoft Virtual Earth (Part 1)
  2. Géocoding / Géocoding Inverse (Part 2)
  3. Récupération des images satellites (Part 3)
  4. Calcul d’itinéraires (Part 4)
  5. Search Service (Part 5)

Bing Maps intègre un système de recherche permettant de trouver des entités géographiques afin de les afficher sur une carte.).

  • Configuration préliminaire

Afin de pouvoir utiliser le service de recherche, il est nécessaire d’avoir rajouté les références aux services Common et Search (http://staging.dev.virtualearth.net/webservices/v1/searchservice/searchservice.svc) et d’avoir récupérer un ticket de session valide.

L’accès au service se fera par l’intermédiaire de la classe proxy généré lors de l’ajout du Service Reference.

SearchServiceClient svc = new SearchServiceClient();

  • Requêtage du service de recherche

La définition de la requête à effectuer se réalise grâce à l’objet SearchRequest. Celui-ci contient une propriété StructuredQuery de type StructuredSearchQuery. Cette propriété contient deux champs textes :

    • Keywords : Liste des mots clés liés à la recherche
    • Location : Lieu autour duquel on veut trouver les entités

Ainsi la requête suivante ramène l’ensemble des pizzerias près des locaux de Microsoft.

SearchServiceClient svc = new SearchServiceClient();

SearchRequest sq = new SearchRequest();

sq.Culture = "fr-fr";

sq.Credentials = new Credentials();

sq.Credentials.Token = token;

sq.StructuredQuery = new StructuredSearchQuery()

{

Keyword = "Pizzeria",

Location = "Issy Les Moulineaux",

};

SearchResponse response = svc.Search(sq);

Une autre façon de réaliser cette requête est d’utiliser la propriété Query de la classe SearchRequest à la place de StructuredQuery. Vous pouvez ajouter des délimiteurs tels que le ‘;’ pour indiquer les différents paramètres.

SearchServiceClient svc = new SearchServiceClient();

SearchRequest sq = new SearchRequest();

sq.Credentials = new Credentials();

sq.Credentials.Token = token;

sq.Query = "Resturant; Issy-Les-Moulineaux";

  • Configuration supplémentaires

Il est possible de paramétrer cette requête afin que les résultats soient en correspondance avec ce que l’on souhaite afficher. Pour cela, on utilise la propriété SearchOptions de la classe SearchRequest.

Cette classe contient une propriété Count permettant de demander la récupération d’un nombre défini de résultat (par défaut 10) et une propriété StartingIndex (par défaut 0). Ces deux propriétés permettent la réalisation de grille avec gestion de pages lorsque le nombre de résultat est trop grand.

La propriété SortOrder permet de définir dans quel ordre doivent être envoyé. Cette propriété est une énumération de type SortOrder comprenant les quatres valeurs suivants :

    • Distance : Du plus proche au plus loin
    • Popularity : Du plus populaire au moins populaire
    • Rating : du mieux noté au moins bien noté
    • Relevance : du plus correspondant aux critères de recherche au moins correspondant.

La propriété ListingType permet de définir la base de données depuis laquelle va être effectué la recherche. Cette propriété est une énumération de type ListingType ayant les choix suivants :

    • Business : Entreprises,Commerces (valeur par défaut)
    • CommunityContent : Contenu fourni par la communauté (non disponible pour la France)
    • Person : Personne (non disponible pour la France)
    • Unknown : Entité dont le type est inconnu

Afin de filtrer encore plus spécifiquement les données, la propriété Filters permet de réaliser des recherches spécifiques à un domaine d’activité. Les filtres disponibles et les valeurs possibles sont disponibles sur le site MSDN (http://msdn.microsoft.com/en-us/library/cc966911.aspx).

La propriété AutocorrectQuery permet de demander à Bing Maps de corriger les mots mal orthographiés dans la requête avant de l’exécuter. Cette correction est effectuée en fonction d’un dictionnaire dont la langue dépend de la propriété Culture de la requête. Cette propriété est à true par défaut. En cas de correction sur la requête, les corrections apportées seront indiqué dans la propriété QuerySuggestion de la réponse.

La propriété ParseOnly permet d’indiquer si l’on souhaite que la requête soit uniquement analysé sans renvoyé les résultats de la recherche en elle-même. Cela permet notamment de vérifier les suggestions ou les corrections faites par Bing Maps sur la requête sans récupérer une série de résultats qui pourrait être lourde en termes de bande passante.

SearchServiceClient svc = new SearchServiceClient();
SearchRequest sq = new SearchRequest();
sq.Credentials = new Credentials();
sq.Credentials.Token = token;
sq.Query = "Resturant Issy-Les-Moulineaux";
sq.SearchOptions = new SearchOptions()
{
    StartingIndex = 0,
    Count = 20,
    SortOrder = SortOrder.Rating,
    ListingType = ListingType.Business,
    AutocorrectQuery = true
};
SearchResponse response = svc.Search(sq);

  • Analyse des résultats

La classe résultat récupéré suite à l’appel à la méthode Search est de type SearchResponse. Cette classe contient de nombreux champs que nous avons déjà vu précédement comme ExtensionData et ResponseSummary.

L’une des propriétés spécifiques est QuerySuggestion. Cette propriété n’est remplie que si la propriété AutoCorrectQuery de la requête est à true. Au sein de QuerySuggestion, on trouve la propriété Query qui contient la requête corrigé sous forme d’une chaine de caractères. La propriété StructuredQuery contient la requête corrigé sous forme plus structure : Le lieu recherché (dans la propriété Location) et l’objet de la recherche (la propriété Keyword). Dans notre exemple (‘Restaurant Issy-Les-Moulineaux’), on aura pour ‘Restaurant’ dans la propriété Keyword et ‘Issy-Les-Moulineaux’ dans la propriété Location.

SearchResponse response = svc.Search(sq);
Console.WriteLine("Nombre de résultats :" + response.ResultSets[0].EstimatedMatches);
foreach(SearchResultBase srs in response.ResultSets[0].Results)
{
   Console.WriteLine("----------------------------------");
   Console.WriteLine("Id : "+ srs.Id);
   Console.WriteLine("Nom : "+ srs.Name);
   Console.WriteLine("Distance : "+ srs.Distance);
   Console.WriteLine("Position : (" + srs.LocationData.Locations[0].Longitude + ";" + srs.LocationData.Locations[0].Latitude+")");
   Console.WriteLine("----------------------------------");
}
Console.ReadLine();

  • Affichage des résultats suite à la requête

L’autre propriété spécifique est ResultSet qui est le tableau des résultats des requêtes (type ResultSet[]). Chaque ResultSet contient une tableau de SearchResultBase[] contenu dans la propriété Result.

Le type SearchResultBase contient les propriétés suivantes :

    • Id : Identifiant Bing Maps de l’entité
    • Name : Nom de l’entité
    • Distance : Distance entre le lieu cible et ce que l’on recherche (dans notre exemple, distance entre le centre d’Issy Les Moulineaux et le restaurant).
    • LocationData : Informations plus précise sur le lieu de l’entité (Position géographique, Niveau de confiance …)

Voici l’article qui termine ma série sur le WebService Bing Maps. Vous retrouverez l’ensemble des liens vers ces articles au début de ce post.

24/04/2009

[Virtual Earth] Développement Microsoft Virtual Earth Web Services – Part 4 : Route Service

Filed under: .NET, Débutant, Virtual Earth — Étiquettes : , , , , , — sebastiencourtois @ 15:01

Liens des posts précédents :

  1. Introduction à Microsoft Virtual Earth (Part 1)
  2. Géocoding / Géocoding Inverse (Part 2)
  3. Récupération des images satellites (Part 3)
  4. Calcul d’itinéraires (Part 4)

Suite de notre grande exploration du Web Service Virtual Earth. Aujourd’hui, nous allons nous intéresser au calcul d’itinéraire. Cette fonctionnalité de Virtual Earth permet de calculer le trajet entre une série de point de contrôles (Waypoints). Il est possible de régler les options du calcul d’itinéraire (type de déplacement, trajet le plus rapide, le plus court …).

Comme d’habitude, il faut ajouter faire “Add Service Reference” avec l’adresse : http://staging.dev.virtualearth.net/webservices/v1/routeservice/routeservice.svc 

Remarque : Afin de fonctionner, il est nécessaire régler certains paramètres WCF de ce service. Dans le fichier app.config (ou web.config ou encore ServiceReference.clientconfig selon le type de projet) de l’application, dans la partie contenant les Binding WCF, il faut trouver le binding lié à RouteService (en général : <binding name="BasicHttpBinding_IRouteService") puis modifier l’attribut maxReceivedMessageSize (mettre la valeur 9000000 à la place de celle par défaut) et l’attribut maxBufferSize (mettre la valeur 9000000 à la place de celle par défaut). Cela est du au fait que RouteService renvoie un nombre d’informations supérieur à ce dont WCF est habitué à manipuler.

Ce service contient une classe principale RouteServiceClient  qui contient deux méthodes :

      • CalculateRoute(RouteRequest request) : Calcul d’un itinéraire entre plusieurs points
      • CalculateRoutesFromMajorRoads(MajorRoutesRequest request) : Calcul d’itinéraires partant des routes principales vers un point d’arrivée spécifié (carte d’accès).

 


  • Calcul d’un itinéraire entre plusieurs points

Le calcul d’itinéraire entre plusieurs points à besoin de deux informations : Les points de passages et là façons de calculer le trajet. Ces deux informations sont contenues dans la classe RouteRequest qui sera passer en paramètre de la méthode CalculateRoute de RouteServiceClient.

Les points de passages doivent être fournis dans la propriété WayPoints de  RouteRequest. Cette propriété prend un tableau de WayPoint, un WayPoint n’étant composé que d’une localisation GPS (latitude/longitude/altitude) et d’une propriété Description pour donner un titre au point de passage.

Les options de calcul d’itinéraire se trouvent dans la propriété Options. Cette propriété est de type RouteOptions et contient les champs suivantes :

Nom de la propriété Description
Mode Type de déplacement.
Enumération TravelMode :
Driving : Voiture (par défaut)
Walking : A pied (ne marche pas pour tous les pays)
Optimization Méthode de calcul du trajet. Marche en combinaison avec TrafficUsage
Enumération RouteOptimization :

MinimizeDistance : Distance minimale
MinimizeTime : Temps minimal

RoutePathType Type de données brutes renvoyées (en plus des données d’itinéraires)
Enumération RoutePathType :
None : Aucune donnée (par défaut)
Points : Un ensemble de points décrivant le chemin de la route.
TrafficUsage Type d’adaptation du trajet en fonction du trafic
Enumération TrafficUsage :

None : On ne tient pas compte du trafic (par défaut)

TrafficBasedRouteAndTime : On change le trajet pour minimiser le temps si nécessaire

TrafficBasedTime : On ne change pas la route mais on tient compte du trafic lors du calcul du trajet.

Combinaisons de Optimization et TrafficUsage :

Optimization TrafficUsage Description

MinimizeDistance

None

Trajet le plus direct (en distance) sans prendre en compte le trafic.

MinimizeDistance

TrafficBasedRouteAndTime

Une Exception lancée. Je pense que c’est du au fait que changer la route d’un trajet le plus direct en fonction du trafic => trajet plus long => incohérence.

MinimizeDistance

TrafficBasedTime

Trajet le plus direct (en distance) en tenant compte du trafic dans les calculs de durée (le trajet n’est pas changé… on passera dans les bouchons quand même :)).

MinimizeTime

None

Trajet le plus rapide (en temps) sans prendre en compte le trafic.

MinimizeTime

TrafficBasedRouteAndTime

Trajet le plus rapide (en temps) en tenant compte du trafic et en le modifiant le cas échéant.

MinimizeTime

TrafficBasedTime

Trajet le plus rapide (en temps) en tenant compte du trafic dans les calculs de temps de trajet (la route n’est pas modifié en fonction du trafic).

Un petit code vaut mieux qu’un long discours : (les variables positionWinwise, positionMSFUniv, positionMSF sont des coordonnées géographiques calculées avant ce code)

RouteServiceClient rsc = new RouteServiceClient();
RouteRequest rq = new RouteRequest();
rq.Credentials = new VETutorial.RouteService.Credentials();
rq.Credentials.Token = token;
rq.Culture = "fr-FR";
rq.Waypoints = new Waypoint[]
{
	new Waypoint() 
	{ 					
		Description = "Winwise (Départ)", 
		Location = new VETutorial.RouteService.Location() 
		{
			Longitude = positionWinwise.Longitude,
			Latitude = positionWinwise.Latitude,
		}
	}, 
	new Waypoint() 
	{ 
		Description = "Microsoft France (Rue de l'université)", 
		Location =  new VETutorial.RouteService.Location() 
		{
			Longitude = positionMSFUniv.Longitude,
			Latitude = positionMSFUniv.Latitude,
		}
	}, 
	new Waypoint() 
	{ 
		Description = "Microsoft France (Rue du québec)", 
		Location =  new VETutorial.RouteService.Location() 
		{
			Longitude = positionMSF.Longitude,
			Latitude = positionMSF.Latitude,
		}
	},
};
rq.Options = new RouteOptions()
{
	Mode = TravelMode.Driving,
	Optimization = RouteOptimization.MinimizeTime,
	RoutePathType = RoutePathType.Points,
	TrafficUsage = TrafficUsage.TrafficBasedRouteAndTime,
};
RouteResponse routeResult = rsc.CalculateRoute(rq);

Comme vous pouvez voir dans ce code, on peut définir des informations supplémentaires comme les données d’authentifications ou encore la culture (langue) du résultat.

En réponse à l’appel de la méthode CalculateRoute, on obtient une classe de réponse de type RouteResponse contenant un champ ResponseSummary (déjà décrit dans les posts précédents) et un champ Result de type RouteResult contenant les informations sur le trajet.

La classe RouteResult fonctionne en arborescence :

Un RouteResult contient des Legs: Un Leg  est un trajet entre deux points de passages. Si plusieurs points de passages alors plusieurs Legs dans le RouteResult

Un Leg contient un tableau d’ItineraryItem (dans la propriété Itinerary) : Un ItineraryItem contient les informations entre deux changements de directions.

Chaque RouteResult, Leg et ItineraryItem contient une propriété Summary contenant le rectangle de leur localisation (propriété BoundingRectangle) ainsi que le temps de parcours en secondes (propriété TimeInSeconds) et la longueur de ce parcours dans la propriété Distance (par défaut en KM mais réglable dans la propriété UserProfile de la requête).

En dehors de ces données, la classe RouteResult contient aussi les données brutes du chemin dans la propriété RoutePath. Il contient un tableau de points géographiques représentant le trajet à faire. Cette propriété est la raison pour laquelle les données renvoyés par le service sont énormes. N’activer cette propriété que si nécessaire (désactivé par défaut : propriété RoutePathType de la requête).

La classe Leg a aussi deux propriétés spécifiques : ActualStart, ActualEnd. Ces propriétés indiquent les positions géographiques de départ et d’arrivés du Leg.

La classe ItineraryItem contient les propriétés suivantes :

Nom de la propriété Description
CompassDirection Orientation du déplacement (chaines de caractères “Nord” …)
Hints Indication permettant de mieux repérer le changement de direction (exemple : “la rue précédente est …”)
Location Position du changement de direction
ManeuverType Type de changement (tourner à gauche, droite, demi tour …)
Text Texte en format XML indiquant le changement à faire (Exemple : “<VirtualEarth:Action>Quitter</VirtualEarth:Action> <VirtualEarth:RoadName>Rue Gaillon</VirtualEarth:RoadName>”)
Warnings Danger sur la route. Lié aux infos traffic, cette propriété indique s’il y a un évènement sur votre trajet (accident, travaux …)

Voici le code d’affichage d’un trajet :

Console.WriteLine("--- Itinéraire  ---");
Console.WriteLine("Temps de calcul : "+ sw.Elapsed);
int i = 1;				
foreach (var leg in routeResult.Result.Legs)
{							
	var duree = new TimeSpan(0,0,(int)leg.Summary.TimeInSeconds);
	Console.WriteLine("-----    Partie " + i + " ------");
	Console.WriteLine("De (" + leg.ActualStart.Latitude +","+leg.ActualStart.Longitude+") à (" + leg.ActualEnd.Latitude +","+leg.ActualEnd.Longitude+")");
	Console.WriteLine("Distance " + leg.Summary.Distance + " km");
	Console.WriteLine("Temps estimé : " + duree.Hours + " h " + duree.Minutes + " min " + duree.Seconds+ " sec");
	Console.WriteLine("************ TRAJET ************");
	int j = 1;
	double distanceDone = 0;
	foreach (var turn in leg.Itinerary)
	{			
		var duree2 = new TimeSpan(0, 0, (int)turn.Summary.TimeInSeconds);
		string HumanInfos = StripXMLFromText(turn.Text);
		Console.WriteLine("Indication " + j + " " + (distanceDone) + " km ["+duree2.Hours+":" + duree2.Minutes + ":" + duree2.Seconds+ "] : " + HumanInfos);
		distanceDone += turn.Summary.Distance;
		j++;
	}
	Console.WriteLine("----- Fin Partie " + i + " -----");
	i++;
}

Le résultat obtenu est le suivant :

— Itinéraire  —

Temps de calcul : 00:00:04.3373465

—–    Partie 1 ——

De (48,868681,2,334231) à (48,861122,2,309237)

Distance 2,788 km

Temps estimé : 0 h 7 min 46 sec

************ TRAJET ************

Indication 1 0 km [0:0:11] : Quitter Rue Gaillon

Indication 2 0,13 km [0:0:49] : Prendre à gauche Avenue de l’Opéra

Indication 3 0,156 km [0:0:53] : Tourner à droite Rue Saint-Roch

Indication 4 0,569 km [0:1:17] : Tourner à droite Rue de Rivoli

Indication 5 1,215 km [0:0:5] : Continuer tout droit Place de la Concorde

Indication 6 1,257 km [0:0:9] : Continuer à gauche Place de la Concorde

Indication 7 1,338 km [0:0:58] : Au rond-point prendre 4

Indication 8 1,61 km [0:0:57] : Prendre à droite Pont de la Concorde

Indication 9 1,835 km [0:1:17] : Tourner à droite Quai d’Orsay

Indication 10 2,531 km [0:0:6] : Continuer à droite Quai d’Orsay

Indication 11 2,584 km [0:0:2] : Tourner à gauche Quai d’Orsay

Indication 12 2,61 km [0:0:56] : Continuer tout droit Rue Surcouf

Indication 13 2,777 km [0:0:6] : Tourner à droite Rue de l’Université

Indication 14 2,788 km [0:0:0] : Arrivée Microsoft France (Rue de l’université)

—– Fin Partie 1 —–

—–    Partie 2 ——

De (48,861122,2,309237) à (48,6900826,2,2157051)

Distance 33,094 km

Temps estimé : 0 h 33 min 46 sec

************ TRAJET ************

Indication 1 0 km [0:0:36] : Quitter Rue de l’Université

Indication 2 0,28 km [0:0:28] : Tourner à droite Rue Malar

Indication 3 0,439 km [0:1:9] : Tourner à gauche Quai d’Orsay

Indication 4 0,685 km [0:2:26] : Continuer tout droit Quai Branly

Indication 5 2,079 km [0:1:27] : Le nom de la voie change Quai de Grenelle

Indication 6 2,877 km [0:2:34] : Le nom de la voie change Quai André Citroën

Indication 7 4,109 km [0:0:33] : Au rond-point prendre 1

Indication 8 4,378 km [0:0:55] : Le nom de la voie change Quai d’Issy-les-Moulin

eaux

Indication 9 4,925 km [0:5:21] : Voie Ad/15 prendre à gauche Boulevard Périphéri

que Lyon

Indication 10 10,008 km [0:2:57] : Prendre à droite E15 Nantes-Bordeaux/Aéroport

Orly-Rungis/Évry-Lyon

Indication 11 12,67 km [0:2:14] : Prendre à droite E15 Véhicules Lents-Toutes Di

rections

Indication 12 15,678 km [0:2:11] : Continuer à gauche E15

Indication 13 19,625 km [0:7:10] : Prendre à droite E5/E50

Indication 14 30,882 km [0:0:54] : 9 prendre à droite Chartres Par RN/Les Ulis/Z

.A. de Courtaboeuf/Villejust

Indication 15 31,465 km [0:0:31] : Prendre à droite D118

Indication 16 31,913 km [0:0:15] : Prendre à droite

Indication 17 32,063 km [0:0:36] : Tourner à droite Avenue de la Baltique

Indication 18 32,32 km [0:1:29] : Tourner à droite Avenue du Québec

Indication 19 33,094 km [0:0:0] : Arrivée Microsoft France (Rue du québec)

—– Fin Partie 2 —–

J’avoue que c’est moins sexy qu’une belle carte en 3D avec le chemin en surbrillance mais c’est mieux que rien. Je vais essayer de voir comment afficher ce trajet sur une carte (avec le RoutePath de RouteResult je pense). Sujet d’un prochain post.


  • Calcul d’itinéraires depuis des routes principales

Le principe de la méthode CalculateRoutesFromMajorRoads est de fournir les trajet allant (ou revenant) d’un point nommé Destination vers les grands axes routiers. Au niveau de la requête, la plupart des propriétés décrites ci dessus fonctionnent avec la classe MajorRoutesRequest. Deux différences toutefois :

La propriété Waypoints disparait au profit d’une propriété Destination ne permettant de définir qu’un WayPoint.

La propriété Options devient du type MajorRoutesOptions et cela ajoute un nouveau paramètre d’options : la propriété booléenne ReturnRoutes indique si on souhaite calculer les routes entre la destination et les routes majeurs (true) où si l’on souhaite uniquement les points d’entrées sur les routes majeures les plus proches (false. valeur par défaut).

MajorRoutesRequest mrr = new MajorRoutesRequest();
mrr.Credentials = new VETutorial.RouteService.Credentials();
mrr.Credentials.Token = token;
mrr.Destination = new Waypoint()
{
	Description = "Winwise (Départ)",
	Location = new VETutorial.RouteService.Location()
	{
		Longitude = positionWinwise.Longitude,
		Latitude = positionWinwise.Latitude,
	}
};
mrr.Culture = "fr-FR";
mrr.Options = new MajorRoutesOptions()
{			  
	Mode = TravelMode.Driving,
	Optimization = RouteOptimization.MinimizeTime,
	RoutePathType = RoutePathType.Points,
	TrafficUsage = TrafficUsage.TrafficBasedRouteAndTime,
	ReturnRoutes = true
};
MajorRoutesResponse MRresult = rsc.CalculateRoutesFromMajorRoads(mrr);

Au niveau de la réponse, on reste sur les mêmes types de données. On a ainsi la propriété Routes contenant des RouteResult (décrit plus haut) donnant les itinéraires entre le point destination et une route majeure. La propriété StartingPoints est un tableau de positions géographiques indiquant les entrées sur les routes majeures environnantes.

Ici se conclut ce post sur les calculs d’itinéraire sous Virtual Earth. Il ne reste plus qu’un service à découvrir : Le SearchService puis nous terminerons par une belle application WPF reprenant tout ce que l’on a appris aux cours de ces 5 posts.

N’hésitez pas à mettre des commentaires pour enrichir ces tutoriaux.

Propulsé par WordPress.com.

%d blogueurs aiment cette page :