Archives de Tag: C#

Introduction aux shapefile

Une utilisation cartographique

En voulant m’intéresser à titre personnel aux données cartographiques, j’ai téléchargé sur le site de l’IGN la base de données Route 500, disponible sous licence ouverte. Cette base de données contient les données de 500 000 km de routes en France métropolitaine.

L’archive (161 Mo compressés, 857 décompressés) contient plusieurs descriptifs et des métadonnées, je ne les ai pas consultés entièrement mais je salue l’initiative de joindre des descriptifs. Qui n’a jamais téléchargé  une archive au nom obscur  et oublié distraitement son utilité plusieurs mois plus tard ? Clignement d'œil

Je ne savais pas du tout à quoi m’attendre comme format de fichier en téléchargeant cette base, uniquement l’indication “format Shapefile”.  En fouillant différents dossiers, dont je présumais que l’arborescence n’avais pas beaucoup d’importance, j’ai repéré non pas différents fichiers mais plusieurs ensembles de fichiers. En effet, chaque “fichier” semblait en fait constitué de plusieurs fichiers aux noms identiques mais  aux extensions différentes (cpg, dbf, prj, shp et shx). Aucune de ces extensions ne m’était connue, et en tant que curieux bien trop hâtif, je me suis bien entendu précipité pour essayer de lire ces fichiers au plus vite avec un éditeur de texte, bien entendu sans avoir lu la moindre documentation au préalable. Seulement, avec un éditeur de texte, seuls les fichiers prj et cpg étaient lisibles, les différents cpg contenant toujours “1252” et les différents prj contenant à chaque fois un ensemble de constantes semblables à des sortes de référentiels géographiques. Quant aux autres fichiers, les plus volumineux, ils étaient illisibles (partiellement pour les dbf et totalement pour les shx et shp). Je n’ai donc pas pu éviter de lire dans un premier temps un bref descriptif encyclopédique puis une documentation complète.

Le format

Contenu général

Habitué à parser du json, du xml, des csv ou d’autres formats simples, le format shapefile m’a beaucoup surpris au départ ! Tout d’abord, comme énoncé plus haut, il n’est non pas composé d’un fichier, ni de deux, mais de trois fichiers (minimum)! Ensuite, il est quasiment impossible (mis à part pour le fichier dbf où on devine des chaines de caractères) de lire les fichiers principaux avec un éditeur de texte. En effet, le format datant des années 90, plusieurs centaines de mégaoctets de données représentaient une empreinte de stockage important, il était alors surement impensable de stocker des données sous forme de texte brut. En prenant simplement l’exemple d’un nombre entier, celui-ci sera stocké dans exactement 4 octets en format binaire au lieu de jusqu’à 10 octets en encodage de texte brut. Ainsi, il est totalement impossible de parser le fichier sans documentation. Néanmoins celle ci n’est pas très compliquée à comprendre.

Le fichier le plus important, celui contenant les formes en elles-mêmes, le shp, est constitué de deux parties. La première partie est un en-tête de taille fixe contenant différentes métadonnées comme un type de géométrie, un nombre d’objet présent et une taille par objet. Il suffit donc ensuite de lire le fichier par blocs de taille indiquée, pour trouver le nombre préconisé d’objet au format opportun.

L’endianisme

Le premier point du format qui m’a beaucoup surpris (et mit un petit moment en difficulté) est l’endianisme. Pour ceux qui ne connaissent pas ce terme ni sa traduction anglaise (endianess), cela correspond au sens de lecture de nombres quand ceux-ci ont sur plusieurs octets. Vu qu’un exemple vaut mille discours, imaginez un nombre entier codé sur 4 octets : 0x1A2B3C4D, qui, si on le découpe en octets, se présentera pour un développeur ainsi :

Poids de l’octet 3 2 1 0
Octet 1A 2B 3C 4D

Le premier octet ainsi rencontré est l’octet de poids-fort, ce sens est appelé “Big-endian”. Celui ci à l’avantage de se lire “naturellement” pour un humain mais a l’inconvénient de devoir être lu en commençant par la fin pour une machine. Pour palier à ce problème à l’ère des premiers processeurs, certains systèmes d’exploitation ont alors implémenté le “Little-endian”, c’est à dire la lecture des octets en commençant par celui de poids faible et terminant par ceux de poids forts. Le même nombre en little-endian sera noté ainsi : 4D3C2B1A.

Poids de l’octet 0 1 2 3
Octet 4D 3C 2B 1A

Le problème qu’a le format shapefile avec l’endianisme n’est pas qu’il en utilise un différent de celui de ma machine (Windows sur x86 étant en little-endian), mais qu’il utilise les deux ! En effet, les octets de 0 à 27 du début du fichier sont composés de 7 entiers notés en big-endian puis sont suivis de deux entiers et 8 décimaux notés en…little endian ! De même pour chaque enregistrement du fichier, l’en-tête sera en big-endian alors que les enregistrements eux-mêmes sont composés d’entiers ou de décimaux en little-endian ! Il m’a donc fallu adapter les méthodes de lectures de nombres pour spécifier l’endianisme….

La projection

Il m’est venu ensuite un problème de projection vis à vis des coordonnées. Ce problème n’est pas directement lié au format shape, mais plutôt son utilisation par l’IGN et l’administration française. En effet, nous avons l’habitude d’utiliser des coordonnées dans le système WGS83 (pour World Geodetic System 1983) sous forme de degrés géographiques, ou plus communément appelées “coordonnées GPS”. Ici, les fichiers fournis présentent des données dans la projection cartographiques Lambert 93. Pour faire simple et rapide : je n’ai tout simplement pas réussi à faire la conversion, malgré de la documentation, pourtant en français, je n’arrive pas à implémenter le calcul…

Mis à part cela, une fois les en-têtes de fichiers et d’enregistrement décodés, il suffit d’implémenter la lecture des différents types de données présents, une dizaine en tout mais toujours un seul type dans un même fichier. Ce format n’est ni nouveau, ni complexe et son utilisation est répandue, maitriser son utilisation ne présente pas un gros avantage technologique. Néanmoins, implémenter tous le format peut être assez long pour une seule personne donc autant partager ce code. J’en ai donc profité pour créer un repository (en C#) sur GitHub ! N’hésitez pas à aller  voir mon code, me faire des retours, voire participer (surtout si vous-mêmes ou une de vos connaissance sait convertir des coordonnées Lambert 93 en WGS83…).

Pour la documentation des fichiers shape : ici (et un complément ici pour les fichiers dBASE). Et, encore une fois, si par chance l’un de vous saurait m’aider à implémenter ce calcul,qu’il se fasse connaitre Clignement d'œil

Par Mathieu Hollebecq

Enregistrer

Publicités

L’API Streaming de Twitter avec le HttpClient .net

La recherche et le streaming

Un des fonctionnalités intéressantes de l’API Twitter est l’utilisation du Streaming. Tout comme la recherche, cette API nous permet de spécifier un mot clé et de récupérer les tweets liés à ce mot clé. Cet article a pour but de vous montrer la différence entre la recherche et le streaming sur l’API Twitter ainsi que l’implémentation de ce streaming en C#.

La différence entre l’API de recherche et l’API de streaming réside en la manière de récupérer les tweets. Avec la première, vous envoyez une requête au serveur Twitter qui vous retourne alors page par page les tweets correspondant à la recherche dans une seule et même réponse. Le fonctionnement est celui d’un échange client-serveur classique :


(crédits image : https://dev.twitter.com )

Principe du streaming

Concernant le streaming, les tweets retournés ne vont pas l’être dans une seule et même réponse. En effet le serveur maintiendra la connexion indéfiniment et dès qu’un nouveau tweet concerné par la recherche faite va être soumis à Twitter, celui ci va nous être retourné dans la foulée. Ce cas d’utilisation est notamment intéressant dans des applications de type “live tweet” :

(crédits image : https://dev.twitter.com )

Implémentation en C#

L’url de requête sera https://stream.twitter.com/1.1/statuses/filter.json en POST. A cela s’ajoute un ou plusieurs paramètres. Pour une utilisation de base, nous ajouterons le paramètre “track” qui aura comme valeur votre recherche (un hashtag ou tout simplement un mot ).

Cette requête ne semble pas compliquée, mais l’extrait de code suivant, qui fonctionne dans le cas d’une simple recherche, va ici échouer. Le souci ne vient pas directement de ce code mais de la librairie OAuth que j’avais réalisée suite à un de mes précédents articles (code source disponible en une seule classe ici : https://skydrive.live.com/?cid=230FED47B214039C&id=230FED47B214039C%212851 )

static async void ComputeStreaming(string search)
{
    OAuthRequester.ComputeHmacSha1 = ComputeHMACSHA1Hash;
    string consumerKey = "yourConsumerKey";
    string consumerSecret = "yourConsumerSecret";
    string oauthToken = "yourOAuthToken";
    string oAuthTokenSecret = "yourTokenSecret";
    string searchUrl = 
"https://stream.twitter.com/1.1/statuses/filter.json"; Dictionary<string, string> contentParams = new Dictionary<string, string>(); contentParams.Add("track", search); var searchRequest = OAuthRequester.SignRequest(HttpMethod.Post,
searchUrl, consumerKey, consumerSecret, contentParams,
oauthToken, oAuthTokenSecret);
using (StreamReader reader = new StreamReader(
await (await searchRequest).Content.ReadAsStreamAsync())) { while (!reader.EndOfStream) { string result = reader.ReadLine(); JObject root = JObject.Parse(result); Console.WriteLine(root["text"].ToString()); } } }

Il n’y pas forcément d’erreur de conception dans ma librairie, l’erreur serait similaire avec l’utilisation de “WebClient” ou “WebHttpRequest”. De la même manière, la requête sera lancée, mais rien ne sera renvoyé et au bout d’une minute, vous recevrez un timeout. Le souci provient de la manière dont HttpClient traite la réponse par défaut, le client a bien commencé à recevoir la réponse, mais il attend d’avoir reçu tous le contenu avant de renvoyer votre objet “HttpResponseMessage”. Or, le principe du streaming est de laisser la connexion ouverte et de recevoir le contenu au fur et à mesure, donc HttpClient ne peut pas gérer le cas de figure de cette manière. Mais, heureusement, il suffit d’une petite modification pour gérer le cas particulier des réponses sous forme de flux et non de sous forme de contenu entier. Il suffit de modifier l’appel de la méthode “client.SendAsync(…)”, dans notre cas, nous utiliserons la surcharge suivante:

HttpResponseMessage response = await client.SendAsync(request,
HttpCompletionOption.ResponseHeadersRead);

La différence réside en l’ajout du paramètre de type “HttpCompletionOption” qui, s’il est omis, prend par défaut la valeur “ResponseContentRead” qui signifie que HttpClient attend de recevoir tout le contenu de la réponse avant de la traiter. La valeur qui nous intéresse ici est “ResponseHeaderRead” qui signifie que la réponse sera traitée dès que les header seront reçus. Le contenu en lui même sera reçu plus tard, lors de l’appel de “ReadAsStreamAsync()”. Avec la modification de la requête, vous pouvez à présent tester le code un peu plus haut qui fonctionnera cette fois-ci (testez avec un sujet populaire du moment pour voir le streaming agir ).

Conclusion

Parfois complexe à utiliser dans certains SDK, l’API streaming de Twitter consiste en une simple requête en POST. La seule petite difficulté est de ne pas attendre de recevoir tous le contenu pour traiter la requête comme le font par défaut les clients HTTP en .net mais de la traiter dès réception des headers. HttpClient permet ce traitement particulier avec la modification du paramètre HttpCompletionOption.
La mise à jour de la classe helper OAuth 1.0 est disponible ici.

Par Mathieu Hollebecq