Fond de carte OpenStreetMap
JaVelo – étape 7
1. Introduction
Cette étape a pour but principal d'écrire deux classes : une première permettant de télécharger le fond de carte depuis les serveurs OpenStreetMap ; et une seconde permettant de produire un fichier au format GPX à partir d'un itinéraire.
2. Concepts
2.1. Fond de carte OpenStreetMap
Comme l'illustre la copie d'écran de la figure 1 ci-dessous, l'interface graphique de JaVelo montre une carte sur laquelle il est possible de placer des points de passage. Une fois ceux-ci placés, le meilleur itinéraire les reliant est calculé et affiché sur la carte, en rouge.
![javelo-gui;64.png](i/javelo-gui;64.png)
L'image de la carte est celle d'OpenStreetMap, visible également sur le site Web principal du projet. Afin de l'afficher dans l'interface, JaVelo la télécharge directement depuis les serveurs mis à disposition par le projet OpenStreetMap.
Ce téléchargement est moins simple à effectuer qu'on pourrait le penser, car l'image constituant la carte n'est pas disponible en un seul morceau, mais est découpée en petites images — nommées tuiles — qui doivent être téléchargées individuellement puis assemblées.
2.2. Tuiles OpenStreetMap
Comme nous l'avons vu à l'étape 2, la carte OSM au niveau de zoom \(z\) est une image carrée de \(2^{z + 8}\) pixels de côté représentant la quasi-totalité de la planète — seules les latitudes au-delà de ±85° n'y figurent pas.
Aux niveaux de zoom faibles (0 à 4 environ), cette image est de taille raisonnable. Toutefois, aux niveaux de zoom élevés, elle devient énorme. Par exemple, au niveau 19, le nombre total de pixels dans l'image vaut :
\[ \left(2^{19 + 8}\right)^2 = 2^{54} = 18\,014\,398\,509\,481\,984 \approx 18\cdot 10^{15} \]
soit plus de 18 pétapixels.
Sachant que chacun de ces pixels est représenté par une valeur de 32 bits (4 octets) contenant sa couleur empaquetée, l'image totale a une taille de 72 pétaoctets, ce qui est conséquent. Pour donner un ordre de grandeur, la capacité du disque SSD d'un bon ordinateur portable actuel est d'environ 1 téraoctets, et il en faudrait donc 72 000 pour stocker l'image de la carte OSM au niveau 19.
Il n'est donc clairement pas réaliste de représenter la carte OSM à un niveau de zoom donné au moyen d'une seule image. Au lieu de cela, l'image est découpée en petites images carrées nommées tuiles (tiles), et ces tuiles sont ensuite assemblées pour obtenir l'image correspondant à une zone du monde donnée.
Les tuiles OSM font 256 pixels de côté, ce qui se trouve être la taille de la carte entière au niveau de zoom 0. Cette carte-là est donc constituée d'une seule tuile. Au niveau de zoom 1, la carte est constituée de 4 tuiles ; au niveau de zoom 2, de 16 tuiles ; et ainsi de suite. Les tuiles sont indexées par deux index, (X, Y), la tuile du coin en haut à gauche ayant l'index (0, 0). Ces conventions sont illustrées dans l'image ci-dessous, qui montre les quatre tuiles OSM formant la carte au niveau de zoom 1, avec leurs index.
![osm-tiles-z1;16.png](i/osm-tiles-z1;16.png)
À la §2.3.1 de l'étape 2, nous avons décrit le système de coordonnées utilisé pour désigner la position d'un point sur l'image d'une carte. Pour un niveau de zoom \(z\) donné, il existe bien entendu une correspondance directe entre les coordonnées \((x_z, y_z)\) d'un point dans ce système de coordonnées et les index \((X_z, Y_z)\) de la tuile le contenant, exprimée par les équations suivantes :
\[ X_z = \left\lfloor\frac{x_z}{256}\right\rfloor\hspace{2em} Y_z = \left\lfloor\frac{y_z}{256}\right\rfloor \]
Ainsi, nous avions vu à l'étape 2 que le Chêne de Napoléon a les coordonnées WebMercator (arrondies) suivantes au niveau de zoom 19 :
\[x_{19} = 69\,561\,722\hspace{2em} y_{19} = 47\,468\,099 \]
Il en découle que, au niveau de zoom 19, les index de la tuile le contenant sont :
\begin{align} X_{19} &= \left\lfloor\frac{69\,561\,722}{256}\right\rfloor = 271\,725\\[0.5em] Y_{19} &= \left\lfloor\frac{47\,468\,099}{256}\right\rfloor = 185\,422 \end{align}Cette tuile est visible ci-dessous.
![185422.png](https://tile.openstreetmap.org/19/271725/185422.png)
2.3. Serveur de tuiles
Les tuiles OpenStreetMap sont stockées sur des ordinateurs gérés par le projet, que l'on nomme serveurs de tuiles (tile servers). Ces ordinateurs sont connectés à Internet et offrent la possibilité de télécharger les tuiles au moyen du protocole HTTPS — le protocole du Web.
Le serveur de tuiles OSM principal porte le nom tile.openstreetmap.org
, et c'est lui qui fournit, entre autres, les tuiles visibles sur le site OSM principal. Nous l'utiliserons également pour JaVelo. D'autres serveurs de tuile existent, qui donnent souvent accès à des tuiles dessinées dans un style différent de celui utilisé par le serveur principal. Ils sont répertoriés sur la page Tile servers du Wiki OSM.
Pour obtenir l'image d'une tuile, il suffit de déterminer son URL1 et d'effectuer une requête HTTPS au serveur de tuile pour obtenir l'image correspondante. L'URL d'une tuile est déterminée par son niveau de zoom et ses index, et a la forme suivante :
https://tile.openstreetmap.org/<zoom>/<X>/<Y>.png
où <zoom>
représente le niveau de zoom, <X>
l'index X de la tuile et <Y>
son index Y. Par exemple, l'URL suivante :
https://tile.openstreetmap.org/19/271725/185422.png
permet d'obtenir l'image de la tuile d'index (271725, 185422) au niveau de zoom 19, présentée à l'image 3. Ces images sont fournies au format PNG, un format d'image fréquemment utilisé sur le Web.
2.4. Cache de tuiles
Grâce aux serveurs de tuiles, il est possible de télécharger très facilement n'importe quelle tuile d'une carte OSM. Ce téléchargement a toutefois un coût, puisqu'il implique le transfert, via Internet, de données situées sur un ordinateur distant.
Pour cette raison, un programme comme JaVelo doit impérativement limiter autant que possible le téléchargement direct de tuiles depuis le serveur. Pour ce faire, lors du premier téléchargement d'une tuile, il la stocke localement — en mémoire et/ou sur disque — afin d'éviter de devoir la télécharger à nouveau la prochaine fois qu'elle sera nécessaire.
L'emplacement dans lequel on stocke ainsi des ressources distantes afin de pouvoir y accéder plus rapidement lors de la prochaine utilisation s'appelle généralement un cache (ou mémoire cache, cache memory) en informatique.
Pour JaVelo, nous stockerons les tuiles OSM dans deux caches de tuiles : un cache mémoire de relativement petite taille, et un cache disque de très grande taille.
2.4.1. Cache mémoire
Un cache mémoire stocke, directement dans la mémoire du programme, des valeurs qui sont chères à obtenir. Dans le cas de JaVelo, le cache de tuile stocke, sous la forme d'objets Java représentant des images, un certain nombre de tuiles obtenues à l'origine depuis le serveur OSM.
Ce cache a une taille limitée, car la mémoire à disposition d'un programme l'est également. Sachant qu'une tuile OSM fait 256 pixels de côté, la mémoire nécessaire au stockage de ses pixels, en octets, est de :
\[ 256^{2} \times 4 = 262\,144 \]
donc environ 260 kilooctets. En gardant 100 tuiles en mémoire, on utilise donc environ 26 mégaoctets, ce qui semble être une limite raisonnable.
2.4.2. Cache disque
Un cache mémoire a l'avantage d'être extrêmement rapide, mais l'inconvénient d'être limité en capacité. Il est donc fréquemment judicieux d'utiliser, en plus d'un cache mémoire de faible capacité, un cache disque de plus grande capacité. Comme son nom l'indique, ce cache stocke ses données sur le « disque » – disque dur ou SSD — de l'ordinateur, dans des fichiers.
Le cache disque de JaVelo stocke les images des tuiles sous la forme de fichiers image au format PNG, puisque c'est celui qui est utilisé par les serveurs de tuile. Les tuiles sont stockées dans des répertoires organisés ainsi :
- au niveau supérieur de la hiérarchie se trouve un répertoire par niveau de zoom,
- chacun de ces répertoires contient un sous-répertoire par index X de tuile,
- chacun de ces sous-répertoires contient un fichier PNG par tuile.
Par exemple, sachant que, au niveau de zoom 19, la tuile contenant le Chêne de Napoléon a les index (271725, 185422), le cache disque stocke son image dans un fichier nommé 185422.png
qui se trouve dans un répertoire nommé 271725
situé lui-même dans un répertoire nommé 19
. Cette hiérarchie peut être représentée schématiquement ainsi :
19 └── 271725 └── 185422.png
2.5. Fichiers GPX
À l'étape précédente, nous avons vu comment produire un fichier au format KML contenant un itinéraire calculé par JaVelo. Le format KML n'est toutefois pas le seul format existant pour représenter des données géographiques. En particulier, les récepteurs GPS et de nombreuses applications cartographiques utilisent généralement un autre format, nommé GPX.
Les formats KML et GPX sont tous deux basés sur le format XML (pour extensible markup language), un format textuel extensible permettant de décrire des données organisées en hiérarchie, qu'il convient de décrire brièvement.
2.5.1. Format XML
Un document XML est composé d'éléments (elements), souvent appelés nœuds (nodes), imbriqués les uns dans les autres afin de former une hiérarchie.
Les différents types d'éléments ont un nom qui les identifient. Ils peuvent posséder des attributs (attributes), qui leur sont attachés directement, ainsi que des enfants (children), qui sont d'autres éléments imbriqués dans eux. En plus de ses enfants, un élément peut également contenir du texte brut imbriqué.
Dans un document XML, le début d'un élément est signalé au moyen d'une balise ouvrante (start tag) composée du nom de l'élément entouré de caractères « plus petit » (<
) et « plus grand » (>
). Les éventuels attributs de l'élément sont placés avant le caractère « plus grand ». Chaque attribut est composé d'un nom et d'une valeur, les deux étant séparés par un signe « égal » (=
), et la valeur est placée entre guillemets.
La fin d'un élément est signalé au moyen d'une balise fermante (end tag), qui est presque identique à la balise ouvrante, si ce n'est que le caractère « plus petit » est suivi d'une barre oblique (/
). Les enfants d'un élément, y compris l'éventuel texte brut, sont placés entre les deux balises.
Par exemple, l'extrait de document XML suivant :
<rtept lat="46.51907" lon="6.56158"> <ele>396.88</ele> </rtept>
est constitué d'un élément rtept
doté de deux attributs :
lat
, qui vaut46.51907
,lon
, qui vaut6.56158
,
et d'un enfant. Cet enfant est un élément ele
dont le fils est le texte brut 396.88
.
Le format XML étant extensible, les types d'éléments utilisables dans un document ne sont pas prédéfinis et peuvent être quelconques. Un fichier GPX est donc un cas particulier de fichier XML utilisant un certain nombre d'éléments qui lui sont propres. Ceux qui nous intéressent sont décrits ci-dessous.
2.5.2. Format GPX
Un document GPX peut contenir un assez grand nombre de types d'éléments différents, mais seule une petite partie d'entre eux nous intéresse ici. Il s'agit de :
gpx
- la racine du document, contenant tous les autres éléments,
metadata
- contenant les méta-données du document, comme son nom,
name
- représentant le nom du document,
rte
- représentant un itinéraire,
rtept
- représentant un point d'un itinéraire,
ele
- représentant l'altitude d'un point.
L'élément rte
, qui représente un itinéraire, est constitué d'une séquence de points. Chacun d'entre eux est représenté par un élément rtept
comportant deux attributs, lat
et lon
, donnant la position du points en degrés, dans le système WGS 84. L'élément rtept
peut contenir un élément ele
donnant l'altitude, en mètres, du point.
Schématiquement, la structure d'un document GPX peut donc être représentée ainsi :
gpx ├── metadata │ └── name └── rte ├── rtept │ └── ele ├── rtept │ └── ele …
L'extrait ci-dessous montre la structure d'un fichier GPX décrivant l'itinéraire allant de l'EPFL à Sauvabelin utilisé en exemple à l'étape 6. Seuls les deux premiers points sont inclus. La toute première ligne donne quelques informations au sujet du format du fichier, et la ligne suivante représente l'élément gpx
à la racine du document. Il n'est pas nécessaire de comprendre la signification des attributs qui lui sont attachés — creator
, version
, xmlns:xsi
, etc. Le reste devrait être facilement compréhensible.
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <gpx creator="JaVelo" version="1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation= "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd" xmlns="http://www.topografix.com/GPX/1/1"> <metadata> <name>Route JaVelo</name> </metadata> <rte> <rtept lat="46.51907" lon="6.56158"> <ele>396.88</ele> </rtept> <rtept lat="46.51887" lon="6.56148"> <ele>397.67</ele> </rtept> <!-- … nombreux autres points --> </rte> </gpx>
Les fichiers GPX peuvent être utilisés dans de nombreuses applications cartographiques. Par exemple, la copie d'écran ci-dessous montre ce qu'affiche l'application swisstopo pour iOS lorsqu'on y importe le fichier GPX de l'itinéraire EPFL - Sauvabelin.
![javelo-swisstopo-ios.jpg](i/javelo-swisstopo-ios.jpg)
3. Mise en œuvre Java
Cette étape est la première de la seconde partie du projet, durant laquelle vous serez plus libres et moins guidés que durant la première.
En particulier, vous avez maintenant le droit de modifier ou augmenter l'interface publique des classes et interfaces proposées, pour peu bien entendu que vous ayez une bonne raison de le faire. Pour faciliter la correction, nous vous demandons néanmoins de respecter les noms de paquetages et de classes, interfaces, enregistrements et types énumérés donnés.
D'autre part, nous nous attendons à ce que vous lisiez et compreniez la documentation des parties de la bibliothèque Java que vous devez utiliser.
La plupart des classes de cette étape sont à définir dans un nouveau sous-paquetge nommé gui
et destiné à contenir la totalité du code lié à l'interface graphique de JaVelo — gui étant l'acronyme de graphical user interface.
Une grande partie du code gérant l'interface graphique utilise la bibliothèque JavaFX, qui ne fait pas partie de la bibliothèque standard Java et doit donc être installée séparément. Pour ce faire, suivez les instructions que nous donnons dans notre guide.
3.1. Enregistrement TileManager.TileId
L'enregistrement TileId
, imbriqué dans la classe TileManager
décrite à la section suivante, représente l'identité d'une tuile OSM. Il possède trois attributs, qui sont :
- le niveau de zoom de la tuile,
- l'index
X
de la tuile, - l'index
Y
de la tuile.
TileId
offre une méthode publique et statique, nommée p. ex. isValid
, prenant en argument ces trois attributs (zoom et index X/Y) et retournant vrai si — et seulement si — ils constituent une identité de tuile valide.
3.2. Classe TileManager
La classe TileManager
du sous-paquetage gui
, publique et finale, représente un gestionnaire de tuiles OSM. Son rôle est d'obtenir les tuiles depuis un serveur de tuile et de les stocker dans un cache mémoire et dans un cache disque.
Son constructeur prend en arguments :
- le chemin d'accès au répertoire contenant le cache disque, de type
Path
, - le nom du serveur de tuile (p.ex.
tile.openstreetmap.org
).
La seule méthode publique offerte par TileManager
, nommée p. ex. imageForTileAt
, prend en argument l'identité d'une tuile (de type TileId
) et retourne son image (de type Image
de la bibliothèque JavaFX).
L'image est cherchée tout d'abord dans le cache mémoire, et si elle s'y trouve, est simplement retournée. Sinon, elle est cherchée dans le cache disque, et si elle s'y trouve, elle est chargée, placée dans le cache mémoire et retournée. Sinon, elle est obtenue depuis le serveur de tuiles, placée dans le cache disque, chargée, placée dans le cache mémoire et enfin retournée.
3.2.1. Conseils de programmation
- Limitation de la taille du cache mémoire
Le cache mémoire doit contenir un maximum de 100 images. Lorsqu'il est plein, il faut donc supprimer l'une des images qu'il contient, mais pas n'importe laquelle ! Il semble en effet plus judicieux de choisir celle utilisée le moins récemment (least-recently used ou LRU en anglais), car c'est probablement la moins utile de toutes.
La bibliothèque Java offre la classe
LinkedHashMap
, qui est une table associative similaire àHashMap
mais qui offre un constructeur permettant de demander à ce que les éléments soient parcourus du moins récemment accédé au plus récemment accédé. Utilisez-le pour facilement trouver l'élément du cache à supprimer lorsqu'il est plein. - Téléchargement d'une tuile
Il est très facile d'obtenir un flot d'entrée fournissant les données d'une tuile grâce à la classe
URLConnection
, comme l'illustre l'extrait de programme suivant :URL u = new URL( "https://tile.openstreetmap.org/19/271725/185422.png"); URLConnection c = u.openConnection(); c.setRequestProperty("User-Agent", "JaVelo"); InputStream i = c.getInputStream();
Bien entendu, il est impératif de fermer le flot retourné par
getInputStream
, ce qui n'a pas été fait ci-dessus. Pour cela, utilisez la notation try-with-resource.Pour sauvegarder la tuile dans le cache disque, il suffit d'obtenir un flot de sortie écrivant dans le fichier désiré, puis d'utiliser la méthode
transferTo
pour transférer les données du flot d'entrée vers le flot de sortie.Une fois la tuile placée dans le cache disque, il est facile de la charger et d'obtenir l'image JavaFX correspondante grâce au constructeur de
Image
prenant un flot d'entrée en argument.Notez que certaines méthodes de la classe
Files
pourraient vous être utiles pour gérer le cache disque, en particulierexists
etcreateDirectories
.
3.3. Enregistrement MapViewParameters
L'enregistrement MapViewParameters
du sous-paquetage gui
, public, représente les paramètres du fond de carte présenté dans l'interface graphique. Il possède trois attributs, qui sont :
- le niveau de zoom,
- la coordonnée
x
du coin haut-gauche de la portion de carte affichée, - la coordonnée
y
du coin haut-gauche de la portion de carte affichée.
Les coordonnées x
et y
sont exprimées dans le système de coordonnées Web Mercator de l'image au niveau de zoom donné. Par exemple, pour la carte affichée dans l'interface de la figure 1, ces trois attributs sont :
- niveau de zoom : 10,
- coordonnée
x
du coin haut-gauche : 135735, - coordonnée
y
du coin haut-gauche : 92327.
La classe PointWebMercator
peut être utilisée pour déterminer les coordonnées WGS 84 du coin haut-gauche :
PointWebMercator p = PointWebMercator.of(10, 135735, 92327); double lon = Math.toDegrees(p.lon()); // ~ 6.40366 double lat = Math.toDegrees(p.lat()); // ~46.88366
Ce point est indiqué par le marqueur bleu sur cette carte, et on peut vérifier visuellement qu'il se trouve bien à la position du coin haut-gauche de la portion de carte affichée dans l'interface de la figure 1.
MapViewParameters
offre les méthodes publiques suivantes :
- une méthode, nommée p. ex.
topLeft
, qui retourne les coordonnées du coin haut-gauche sous la forme d'un objet de typePoint2D
— le type utilisé par JavaFX pour représenter les points, - une méthode, nommée p. ex.
withMinXY
, qui retourne une instance deMapViewParameters
identique au récepteur, si ce n'est que les coordonnées du coin haut-gauche sont celles passées en arguments à la méthode, - une méthode, nommée p. ex.
pointAt
, qui prend en arguments les coordonnéesx
ety
d'un point, exprimées par rapport au coin haut-gauche de la portion de carte affichée à l'écran, et retourne ce point sous la forme d'une instance dePointWebMercator
, - deux méthodes, nommées p. ex.
viewX
etviewY
, qui prennent en argument un point Web Mercator et retournent la position x ou y correspondante, exprimée par rapport au coin haut-gauche de la portion de carte affichée à l'écran.
Le but des méthodes pointAt
et viewX
/ viewY
, qui sont inverses l'une de l'autre, est de convertir entre le système de coordonnées de l'image de la carte OpenSteetMap et celui de la portion affichée à l'écran.
Par exemple, avec les paramètres donnés plus haut en exemple, la méthode pointAt
appliquée aux coordonnées (0, 0) retourne simplement le point Web Mercator correspondant au coin haut-gauche de la portion de carte affichée, c.-à-d. le point p
de l'extrait de code. À l'inverse, les méthodes viewX
et viewY
appliquées à ce point p
retournent toutes deux 0.
3.4. Enregistrement Waypoint
L'enregistrement Waypoint
du sous-paquetage gui
, public, représente un point de passage. Il possède deux attributs :
- la position du point de passage dans le système de coordonnées suisse,
- l'identité du nœud JaVelo le plus proche de ce point de passage.
Waypoint
ne possède aucune autre méthode publique que celles définies automatiquement par Java pour les enregistrements.
3.5. Classe GpxGenerator
La classe GpxGenerator
du sous-paquetage routing
, publique et non instanciable, représente un générateur d'itinéraire au format GPX. Elle offre deux méthodes publiques (et statiques) :
- la première, nommée p. ex.
createGpx
, qui prend en arguments un itinéraire et le profil de cet itinéraire et retourne le document GPX (de typeDocument
) correspondant, - la seconde, nommée p. ex.
writeGpx
, qui prend en arguments un nom de fichier, un itinéraire et le profil de cet itinéraire et écrit le document GPX correspondant dans le fichier, ou lèveIOException
en cas d'erreur d'entrée/sortie.
Les document GPX produits par ces deux méthodes doivent avoir les mêmes points que l'itinéraire qui leur est passé, et l'altitude de chacun de ces points doit être obtenue du profil.
3.5.1. Conseils de programmation
Les classes du paquetage javax.xml
permettant de travailler avec les documents XML ne sont malheureusement pas très bien conçues, et il en va de même du format XML lui-même. Pour cette raison, nous vous fournissons ci-dessous des exemples de code dont vous pouvez vous inspirer.
- Méthode
createGpx
L'extrait de code ci-dessous crée, dans la variable
doc
, un embryon de document GPX constitué des élémentsgpx
,metadata
etname
. Il ne vous reste plus qu'à y ajouter l'élémentrte
représentant la route, constitué d'élémentsrtept
possédant un élémentele
donnant l'altitude du point.Document doc = newDocument(); // voir plus bas Element root = doc .createElementNS("http://www.topografix.com/GPX/1/1", "gpx"); doc.appendChild(root); root.setAttributeNS( "http://www.w3.org/2001/XMLSchema-instance", "xsi:schemaLocation", "http://www.topografix.com/GPX/1/1 " + "http://www.topografix.com/GPX/1/1/gpx.xsd"); root.setAttribute("version", "1.1"); root.setAttribute("creator", "JaVelo"); Element metadata = doc.createElement("metadata"); root.appendChild(metadata); Element name = doc.createElement("name"); metadata.appendChild(name); name.setTextContent("Route JaVelo");
La méthode
newDocument
utilisée pour créer un nouveau document peut être définie ainsi :private static Document newDocument() { try { return DocumentBuilderFactory .newDefaultInstance() .newDocumentBuilder() .newDocument(); } catch (ParserConfigurationException e) { throw new Error(e); // Should never happen } }
Notez que cette méthode utilise un bloc
try/catch
afin de rattraper les exceptions de typeParserConfigurationException
et de lever une autre exception de typeError
contenant l'exception originale. Cela a été fait car l'exception en question ne devrait jamais être levée (parnewDocumentBuilder
) étant donné qu'on utilise ici la configuration par défaut, qui doit être valide.Le fait de rattraper ces exceptions qui ne devraient jamais être levées en pratique, mais qui sont de type checked, et de les emballer dans une exception (
Error
) de type unchecked permet d'éviter de devoir annoter inutilement les méthodes utilisant ce code avec desthrows
. Et si l'exception devait néanmoins être levée pour une raison ou pour une autre, elle ferait planter le programme plutôt que d'être ignorée silencieusement. - Méthode
writeGpx
Une fois le document GPX créé au moyen de la méthode
createGpx
, il n'est pas non plus très simple de l'écrire dans un fichier car il faut passer par une instance d'une classeTransformer
. L'exemple ci-dessous, à compléter, illustre cela en écrivant le documentdoc
dans l'écrivainw
.Document doc = …; Writer w = …; Transformer transformer = TransformerFactory .newDefaultInstance() .newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.transform(new DOMSource(doc), new StreamResult(w));
Notez qu'ici aussi, les méthode
newTransformer
ettransform
peuvent lever des exceptions de type checked qui ne devraient jamais être levées en pratique. Utilisez la même technique que ci-dessus pour les « transformer » en exceptions de typeError
.
3.6. Tests
À partir de cette étape, aucun fichier de vérification de signatures ne vous est fourni, étant donné que la signature des différentes méthodes n'est plus spécifiée en détail. Pour la même raison, aucun test unitaire ne sera plus fourni à l'avenir, à vous d'écrire les vôtres. Notez que cela est fortement recommandé en général.
Nous vous donnons néanmoins ci-après quelques conseils pour tester certaines parties de cette étape.
3.6.1. Classe TileManager
Pour tester votre gestionnaire de tuiles, vous pouvez l'utiliser pour obtenir la tuile contenant le Chêne de Napoléon et vérifier qu'elle est bien stockée dans le cache disque.
Pour ce faire, il vous faut écrire une toute petite application JavaFX, et comme nous n'avons pas encore examiné cette bibliothèque en cours, nous vous fournissons l'exemple suivant dont vous pouvez vous inspirer :
public final class TestTileManager extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) throws Exception { TileManager tm = new TileManager( Path.of("."), "tile.openstreetmap.org"); Image tileImage = tm.imageForTileAt( new TileManager.TileId(19, 271725, 185422)); Platform.exit(); } }
Une fois cette application exécutée, vous devriez avoir, dans le répertoire de votre projet, un dossier nommé 19
, contenant un sous-dossier nommé 271725
, contenant un fichier nommé 185422.png
. En ouvrant ce fichier, vous devriez voir l'image de la figure 3.
3.6.2. Classe GpxGenerator
Pour voir si les fichiers GPX que vous générez sont valides, vous pouvez utiliser le site GPX file viewer. Lorsque vous y téléchargez un fichier GPX, il affiche à la fois le profil déterminé au moyen des données de Google Maps et le profil contenu dans le fichier GPX lui-même. Les deux devraient être similaires mais ne sont que rarement identiques en raison des données différentes utilisées par Google Maps.
4. Résumé
Pour cette étape, vous devez :
- écrire les classes
TileManager
,MapViewParameters
,Waypoint
etGpxGenerator
selon les indications données ci-dessus, - tester votre code,
- documenter la totalité des entités publiques que vous avez définies.
Aucun rendu n'est à faire pour cette étape avant le rendu final. N'oubliez pas de faire régulièrement des copies de sauvegarde de votre travail en suivant nos indications à ce sujet.
Notes de bas de page
Une URL, ou adresse Web, est une chaîne de caractères identifiant une ressource (page, image, etc.) sur le Web. Par exemple, l'URL https://www.epfl.ch/ identifie la page principale du site de l'EPFL, https://cs108.epfl.ch/ identifie la page principale de ce cours, etc.