posté le 23/03/2008 à 16h02
En travaillant sur l'application PSP-Maps, j'ai eu l'occasion de (re)découvrir l'envers du décor des services de cartographie en ligne.
Pour des raisons techniques, je ne peux pas passer par l'API classique prévue par exemple par Google.
En effet, il s'agit d'une API javascript, et le navigateur intégrée à la PSP est très limité.

L'intérêt est donc d'étudier comment Google Maps, Virtual Earth et Yahoo! Maps stockent leurs images pour les récupérer directement à la source.
Ainsi, il devient possible de les intégrer à des applications de plus bas niveau.
On trouve déjà pas mal de documentation sur internet, mais je n'ai pas trouvé de billet résumant tout sur la même page, et encore moins en français, ce que je vais essayer de faire ici.

La meilleure façon d'obtenir les informations est d'utiliser un sniffer réseau, afin de récupérer les requêtes effectuées pendant qu'on utilise le service de cartographie dans son navigateur.
Personnellement, j'ai utilisé Wireshark (l'ancien Ethereal), qui reconnait le protocole HTTP et le présente de façon simplifié.

Les 3 principaux services de cartographies se ressemblent énormément au niveau de la projection et du découpage de la carte.
La carte est découpée en carrés de 256 x 256 pixels, et chaque fois qu'on zoome on redivise le carré en 4 nouvelles images.
Je trouve assez amusant de voir que les 3 acteurs ont choisi exactement les mêmes chiffres. Pourquoi 256 pixels et pas 512 ou 1024 ? Pourquoi découper exactement de la même façon la carte ?
En tout cas c'est très sympa pour le programmeur car ça rend plus facile l'écriture d'un programme compatible avec les 3 services de cartographie.
On arrive ainsi à passer d'une carte à une autre en étant aligné au pixel près !

Dans la suite du billet, "z" désigne le niveau de zoom, et "x" et "y" les coordonnées.
Pour nommer une image de la carte à un niveau de zoom donné, on va distinguer 2 méthodes de désignation : la méthode "récursive" et la méthode "linéaire".
Par exemple pour désigner la zone rouge suivante (z=3) :


La première façon de désigner les images est tout simplement de numéroter les lignes et les colonnes de 0 à 2^z-1.
Par exemple, x=5 et y=3 pour la zone rouge.

(0,0) (1,0) (2,0) (3,0) (4,0) (5,0) (6,0) (7,0)
(0,1) (1,1) (2,1) (3,1) (4,1) (5,1) (6,1) (7,1)
(0,2) (1,2) (2,2) (3,2) (4,2) (5,2) (6,2) (7,2)
(0,3) (1,3) (2,3) (3,3) (4,3) (5,3) (6,3) (7,3)
(0,4) (1,4) (2,4) (3,4) (4,4) (5,4) (6,4) (7,4)
(0,5) (1,5) (2,5) (3,5) (4,5) (5,5) (6,5) (7,5)
(0,6) (1,6) (2,6) (3,6) (4,6) (5,6) (6,6) (7,6)
(0,7) (1,7) (2,7) (3,7) (4,7) (5,7) (6,7) (7,7)

L'autre technique de désignation est la suivante : on divise la carte en 4, le quart nord-ouest s'appele "A", le quart nord-est "B", le quart sud-ouest "C" et le quart sud-est "D".
On redivise récursivement le bon carré de la même façon.
En concaténant les lettres obtenu on obtient la référence de l'image, en "z" lettres pour un zoom de niveau "z".
Par exemple "BCD" pour notre zone rouge.
Les coordonnées "x" et "y" n'apparaissent donc pas directement, mais on passe facilement d'un système à l'autre avec une fonction récursive.

A
BA BB
BCA BCB
BCC BCD
BD
C D

Et voilà, ces deux techniques sont les seules utilisées par nos services de cartographies, aux lettres utilisées près, et aux décalages près...

Voici le détail :
  • Google Maps

    Chez Google, le zoom est numéroté de 17 à -4 (on peut peut-être aller encore plus bas sur certaines zones).
    17 correspond au niveau de zoom le plus lointain, où on voit toute la terre dans un carré de 256x256 pixels.
    • Vue "Map"

      C'est la vue par défaut, les images sont au format PNG.
      Les coordonnées "x" et "y" sont linéaires, et vont de 0 à 2^(17-z)-1.
      L'adresse est de la forme suivante : http://mt0.google.com/mt?n=404&v=w2.69&x=5&y=3&zoom=14



      mt0 est un des serveurs d'images, il y en a d'autres (mt1, mt2 et mt3 en ce moment).
      Le paramètre v=2.69 doit être mis à jour pour se conformer à la dernière version du protocole.
      Comme vous pouvez le voir, il n'y a pas de clef en paramètre (pas d'API key). On peut donc obtenir les images de façon "publique".
    • Vue "Terrain"

      Images au format JPEG, même système de coordonées, avec une adresse légèrement différente : http://mt0.google.com/mt?n=404&v=w2p.64&x=5&y=3&zoom=14



      Le paramètre v=2p.64 doit être mis à jour pour se conformer à la dernière version du protocole.
    • Vue "Satellite"

      Les images sont au format JPEG.
      La technique pour désigner les images est l'approche récursive, avec les lettres "q" (pour le NW), "r" (pour le NE), "s" (pour le SE), "t" (pour le SW).
      La racine est désignée par "t" : http://kh0.google.com/kh?n=404&v=25&t=trts



      Là aussi il y a d'autres serveurs possibles (kh1, kh2 et kh3 en ce moment).
      Attention, j'ai remarqué que Google Maps peut blacklister temporairement votre addresse IP si vous faites trop de requêtes sur ces serveurs...

  • Virtual Earth

    Chez Virtual Earth, c'est encore plus simple, seule la technique "récursive" est utilisée, avec les chiffres "0" (pour le NW), "1" (pour le NE), "2" (pour le SW) et "3" (pour le SE).
    Bizarrement, c'est le protocole pour lequel j'ai trouvé le plus de documentation "officielle" : Contrairement à Google Maps, il n'y a pas de "racine", on démarre tout de suite avec 4 images au plus haut niveau.
    • Vue "Road"

      Les images sont au format PNG : http://tiles.virtualearth.net/tiles/r123?g=117



      Le paramètre g=117 est à mettre à jour en fonction du numéro actuel de version.
      Là aussi il y a plusieurs serveurs, mais j'ai choisi le nom de domaine de plus haut niveau, qui assure lui-même la répartition (round robin DNS).
    • Vue "Aerial"

      Les images sont au format JPEG : http://tiles.virtualearth.net/tiles/a123?g=117


    • Vue "Hybrid"

      Les images sont au format JPEG : http://tiles.virtualearth.net/tiles/h123?g=117


  • Yahoo! Maps

    Le découpage utilisé est "linéaire", avec un zoom "z" démarrant à 18 (histoire de ne pas faire 17 comme Google wink), "x" variant entre 0 et 2^(18-z)-1, et "y" variant entre -2^(17-z) et 2^(17-z)-1.
    Attention l'axe "y" est inversé par rapport aux autres protocoles (les grandes valeurs sont au nord).
    • Vue "Map"

      Les images sont au format JPEG : http://us.maps1.yimg.com/us.tile.yimg.com/tl?v=4.1&x=5&y=0&z=15


    • Vue "Satellite"

      Les images sont au format JPEG : http://us.maps3.yimg.com/aerial.maps.yimg.com/ximg?v=1.7&t=a&x=5&y=0&z=15


Comme vous pouvez le voir, les différentes vues proposées se complètent bien, et surtout sont parfaitement alignées.
Sur PSP-Maps, j'ai rajouté un petit effet de "fading" lorsqu'on passe d'une vue à l'autre, et c'est du plus bel effet wink

Dans votre programme, il faut choisir votre système de coordonnées "principal".
Dans PSP-Maps, j'ai commencé par le support de Google Maps, donc j'ai gardé ce système de coordonnées linéaires.
On a donc "z" qui varie entre 17 et -4, "x" et "y" qui varient entre 0 et 2^(17-z)-1.
Lorsqu'on zoome, il suffit de décrémenter "z", et de multiplier "x" et "y" par 2.
Lorsqu'on dézoome, il suffit d'incrémenter "z", et de diviser "x" et "y" par 2.
Pour passer aux coordonnées linéaires utilisées par Yahoo! Maps, on peut réutiliser "x" directement, "z+1" comme niveau de zoom, et il faut décaler "y" : "2^(16-z)-y-1".
Pour passer aux coordonnées récursives utilisées par Google Maps, j'utilise la fonction suivante :
/* returns in buffer "b" the name of the Google Maps tile for location (x,y,z) */
void GGtile(int x, int y, int z, char *b)
{
	int c = 18 - z;
	b[c] = '\0';
	while (z++ < 17)
	{
		c--;
		if (x % 2)
		{
			if (y % 2)
				b[c] = 's';
			else
				b[c] = 'r';
		}
		else
		{
			if (y % 2)
				b[c] = 't';
			else
				b[c] = 'q';
		}
		x/=2;
		y/=2;
	}
	b[0] = 't';
}
Pour passer aux coordonnées récursives utilisées par Virtual Earth, j'utilise la fonction suivante :
/* returns in buffer "b" the name of the Virtual Earth tile for location (x,y,z) */
void VEtile(int x, int y, int z, char *b)
{
	int c = 17 - z;
	b[c] = '\0';
	while (z++ < 17)
	{
		c--;
		if (x % 2)
		{
			if (y % 2)
				b[c] = '3';
			else
				b[c] = '1';
		}
		else
		{
			if (y % 2)
				b[c] = '2';
			else
				b[c] = '0';
		}
		x/=2;
		y/=2;
	}
}
Avec des commentaires et un contrôle sur les paramètres ça serait mieux wink

Comme il ne s'agit que de requêtes HTTP, je pense qu'il n'y a pas de "risques" à utiliser ces informations, même si chaque service peut choisir de vous bannir.
C'est le cas de Google Maps si vous faites trop de requêtes (heureusement c'est un blacklistage temporaire).

Je vous invite fortement à mettre en place un cache local, afin de ne pas surcharger les serveurs de requêtes, et d'améliorer la fluidité de votre application.
Attention à la taille de celui-ci, ça grossi vite. Pour FreeMaps que je n'ai jamais "nettoyé", j'en suis à :
royale@fanta:~$ ls freemaps-cache/ | wc -l
439017
royale@fanta:~$ du -hs freemaps-cache/
5,7G    freemaps-cache/
Certaines images ne sont pas disponibles à tous les niveaux de zoom, il faut donc gérer la réponse du serveur.
Sur PSP-Maps j'envoie directement le buffer de réponse à la fonction IMG_Load_RW de SDL_Image.
Si l'image est valide (PNG ou JPEG), un pointeur vers l'image décodée est retourné.
Si l'image est invalide (erreur HTML par exemple), NULL est retourné.

Commentaires

Pseudo :
Message :
(pas de HTML)

msettache [ 05/02 - 19:02 ] : je pense que ça sera plus interessant de pouvoir récupérer les images google earth.
pour information, google grave le nom "google" sur les images disponibles dans ggogle maps contrairement à google earth ou l'image est totalement nette !


krahn [ 31/03 - 11:52 ] : Moi on me demande de faire ca dans mon stage (recup image google...) et j'ai chopé le wire shark....
Mais je comprend rien de ce qu'il faut faire avec :/

Brosto [ 08/10 - 21:30 ] : Salut,
t'as une idée du facteur de conversion entre les coordonnées GPS et les valeur XY ? ce serait pratique, tu récupère les coordonnées via l'API avec l'adresse de ce que tu veux et hop, tu affiche l'image.

je sais que x=126 / y=127 correspond à 0.433956,0.653687 par exemple.

MS [ 11/09 - 06:12 ] : Merci beaucoup pour ces infos sur l'acces aux serveurs d'image. Je n'arrive pas a connaitre la version actuelle de Google (parametre v). Pourrais-tu me renseigner

Royale [ 01/04 - 16:17 ] : Christophe : Désolé je n'ai jamais étudié le fonctionnement de Géoportail.

Christophe [ 01/04 - 08:32 ] : Super les infos. Juste une question Géoportailo semble utiliser le meme genre de nomenclature, mais je ne m'y retriouve pas. As tu des infos?

Royale [ 24/02 - 09:46 ] : JuliusCesarus : Dans mon projet PSP-Maps, vous trouverez une fonction latlon2xy qui pour une latitude, une longitude et un niveau de zoom donné renvoie les coordonnées (x,y) nécessaires afin de récupérer l'image.

JuliusCesarus [ 24/02 - 03:22 ] : Bonsoir,
Je sais que le post est vieux mais j aimerais savoir s il etait possible de recuperer la carte voulue selon une latitude et une longitude donnee.

Merci d avance.

lolo888 [ 24/02 - 03:04 ] : Et avec les carte geoportail de l'IGN en OpenLayer ça serait faisable ???

Fabien [ 22/10 - 16:02 ] : question subsidiaire : les différents paramètres de de l'URL, je présume qu'ils sont documentés nulle part... Sinon, tu aurais pas un moyen rapide pour récupérer les coordonnées géographiques des points sup gauche et inf droit des cartes ?? Hein ??? Ah... tant pis...

Fabien [ 22/10 - 16:00 ] : Ok. J'ai fait comme toi, un petit coup de wireshark et en effet, c'est le v= qui me mettait dedans. Maintenant ça marche. Trop bien :-]

Royale [ 19/10 - 23:29 ] : Pour Google Maps, il faut mettre à jour le paramètre v=... , ils le changent régulièrement :)

Fabien [ 19/10 - 15:51 ] : Salut !! Ca fait un moment que je cherche à récuperer des fonds de cartes. MERCI !! Pour googlemaps, t'es sûre que ça marche encore ? Je n'y arrive pas !

Pierrot [ 16/04 - 11:19 ] : Super article bien utile.

Royale [ 28/03 - 19:23 ] : Merci Nicolas pour cette information complémentaire :)

Nicolas [ 28/03 - 00:25 ] : Sur virtual Earth, tu peux même récupérer la version avec relief en indiquant le paramètre supplémentaire dans l'URL : shading=hill
Exemple : http://tiles.virtualearth.net/tiles/r123?g=117&shading=hill

Ils sont accessibles depuis différentes url afin de répartir la charge... t1 à t4.virtualearth.net....
Google lui c'est encore différent, c'est clusterisé également en fonction des styles de vue (map, aerial..)...

Tu as bien fais de préciser le blacklistage possible (et surtout très probable). Il en va de même pour la propriété des images.

Le système utilisé est celui des Quadtree et comme le précise NoMan, c'est un classique.

Nono [ 26/03 - 08:54 ] : Intéressant, je récupèrerai bien toute la haute-garonne pour faire de la géolocalisation hors ligne de mes photos :)

Royale [ 25/03 - 00:56 ] : Merci NoMan, maintenant que tu le dis ça me rappelle quelque chose. C'était pas en Prolog même ? Ceci dit je n'avais pas fait le lien...

NoMan [ 24/03 - 23:16 ] : "Récursif"... c'est des qtrees ou quad trees, on avait vu ça en scheme ou caml à la fac (un classique en fait) ;-)

Jo [ 24/03 - 11:01 ] : Super article Royale !

Mais arrête de bosser là-dessus, tu vas te faire embaucher cher http://www.makina-corpus.com/ ;)

Infos TiBlog

Pseudo : Royale
Titre : Le blog de Royale
Description : Le blog de l'administrateur de TiBlog.fr où vous trouverez quelques détails techniques sur le fonctionnement de ce site.

Créer un blog !

blog gratuit

Recherche

Photo