Etape 1 – Points et projections

1 Introduction

Le but de cette première étape est d'écrire les classes permettant de représenter les entités suivantes :

  1. un point à la surface de la Terre, spécifié dans un système de coordonnées sphérique,
  2. un point sur une carte, spécifié dans un système de coordonnées cartésien bidimensionnel,
  3. une projection cartographique permettant de passer d'un système à l'autre.

1.1 Coordonnées géographiques

La Terre a une forme irrégulière mais assez bien approximée par une sphère légèrement applatie aux pôles — c-à-d un ellipsoïde de révolution. Il est donc naturel de spécifier la position de points dans son voisinage en utilisant un système de coordonnées sphérique. Un tel système de coordonnées est une généralisation à trois dimensions d'un système de coordonnées polaire dans lequel la position d'un point est donné par trois coordonnées :

  1. sa longitude \(\lambda\), qui est la distance angulaire du point à un méridien de référence — un méridien étant un cercle passant par les deux pôles,
  2. sa latitude \(\phi\), qui est la distance angulaire du point à l'équateur,
  3. son rayon \(\rho\), qui est la distance du point à l'origine.

En cartographie, on ignore généralement la troisième coordonnée, les points étant simplement supposés être à la surface de l'ellipsoïde terrestre. C'est ce que nous ferons dans ce qui suit, en représentant les points par leur longitude et leur latitude uniquement.

Par convention, la longitude d'un point à la surface de la Terre est comprise entre -180° et +180° (inclus, les longitudes -180° et +180° étant égales), la longitude 0 étant celle du méridien de référence choisi ; la latitude d'un point est quant à elle comprise entre -90° et +90° (inclus), la latitude 0 étant celle de l'équateur. La figure ci-dessous illustre ces conventions.

Sorry, your browser does not support SVG.

Figure 1 : Latitude et longitude (image de Wikimedia Commons)

Décider d'utiliser un système de coordonnées sphérique pour spécifier la position des points à la surface de la Terre ne suffit pas, il faut de plus définir un repère, c-à-d l'origine de l'ellipsoïde dans l'espace et ses dimensions. Un tel repère se nomme système géodésique, et le plus populaire de nos jours est le système WGS 84, utilisé entre autres par les récepteurs GPS. En plus des caractéristiques de l'ellipsoïde, WGS 84 spécifie également le méridien de référence, qui passe près de l'observatoire de Greenwich en Angleterre.

Tous les points en coordonnées sphériques utilisés dans ce projet sont implicitement exprimés dans le système WGS 84.

1.2 Coordonnées projetées

Contrairement à la Terre, une carte n'est pas sphérique mais plane. Il est donc naturel de spécifier la position des objets qu'elle représente en utilisant un système de coordonnées cartésien à deux dimensions.

Tout comme pour les coordonnées sphériques, décider d'utiliser un système de coordonnées cartésien pour les cartes ne suffit pas, encore faut-il choisir un repère, c-à-d une origine et des axes.

Les cartes topographiques suisses, qui nous intéressent ici, utilisent un repère nommé CH1903. Dans ce repère, tout point du territoire suisse est désigné par une paire de coordonnées à 6 chiffres, et l'origine a été choisie afin que l'ancien observatoire de Berne ait les coordonnées (600'000, 200'000), comme illustré sur la carte ci-dessous.

Sorry, your browser does not support SVG.

Figure 2 : Le système CH1903 (geodata © swisstopo)

Le système CH1903 a quelques caractéristiques intéressantes.

Premièrement, les coordonnées sont exprimées (approximativement) en mètres, ce qui permet de facilement connaître la distance entre deux points. Par exemple, la distance entre le coin sud-ouest du Learning Center (533'133, 152'199) et le coin sud-ouest de la cathédrale de Lausanne (538'321, 152'670) peut ainsi être estimé à :

\[\sqrt{(538321 - 533133)^2 + (152670 - 152199)^2} = 5209\]

Cette valeur est très proche des 5'206 m mesurés sur Google Earth, qui prend en compte les différences d'altitude et la courbure de la Terre.

D'autre part, la totalité du territoire de la Confédération se trouve dans le premier quadrant du plan, et sous l'axe \(y=x\). Il en découle que tout point situé en Suisse a des coordonnées CH1903 positives et que sa coordonnée \(y\) est inférieure à sa coordonnée \(x\). Il est donc impossible de confondre ces dernières.

1.3 Projection

Pour passer du système de coordonnées sphérique de la Terre au système de coordonnées cartésien de la carte il convient d'effectuer une projection dont le but est, en quelque sorte, d'applanir l'ellipsoïde terrestre. Etant donné que toute projection d'une sphère (ou d'un ellipsoïde) sur le plan implique une déformation, de très nombreuses projections cartographiques sont utilisées pour différentes applications, chacune faisant des compromis différents.

Projection équirectangulaire

La projection la plus simple qui soit consiste simplement à utiliser la longitude et la latitude des points comme coordonnées cartésiennes :

\begin{array}{rcl} x & = & \lambda\\ y & = & \phi \end{array}

Cette projection est appelée équirectangulaire. Son principal avantage est d'être extrêmement simple, mais étant donné les distortions qu'elle produit, elle n'est pas fréquemment utilisée en pratique. Il est néanmoins intéressant de savoir qu'elle a été utilisée dans les premières versions de Google Maps, mais depuis ce service est passé à une projection de Mercator.

Projection de Mercator

La projection de Mercator est probablement la plus connue d'entre toutes. Les formules de projection ne sont pas données ici car elles ne sont pas directement utiles au projet, pour les raisons expliquées ci-dessous.

Projection Suisse

La projection utilisée pour les cartes topographiques suisses est une projection de Mercator — à axe oblique, pour être précis, mais nous ignorerons ce détail. On pourrait dès lors s'attendre à pouvoir transformer un point WGS 84 en un point CH1903 en utilisant les formules correspondant à cette projection.

Malheureusement les choses ne sont pas aussi simples, car le système CH1903 n'est pas basé sur le système géodésique WGS 84 mais sur un autre système plus ancien. Dès lors, pour passer d'un point spécifié en WGS 84 à un point en CH1903, il faut commencer par effectuer le changement de système géodésique avant de faire la projection de Mercator elle-même.

Pour simplifier les choses, nous utiliserons des formules qui combinent ces deux opérations. Nous les regrouperons dans ce que nous nommerons par abus de langage la « projection CH1903 ».

Les formules en question, données ci-dessous, ont été adaptées de celles figurant dans le document Transformation CH1903 <=> WGS 84 publié par swisstopo. Ces formules sont approximatives, mais leur précision de l'ordre du mètre suffit largement pour l'utilisation que nous en ferons.

Notez toutefois que le système CH1903 fait le choix surprenant de nommer X la coordonnée Nord/Sud (donc verticale sur une carte) et Y la coordonnée Est/Ouest (donc horizontale sur une carte). Les formules ci-dessous ont été adaptées pour utiliser x pour la coordonnée horizontale et y pour la verticale, conformément aux conventions mathématiques.

Attention : dans ces formules, la longitude \(\lambda\) et la latitude \(\phi\) sont exprimées en degrés.

\begin{array}{rcrl} \lambda_1 & = && \frac{1}{10\,000}\left(\lambda\times 3\,600 - 26\,782.5\right)\\[0.5em] \phi_1 & = && \frac{1}{10\,000}\left(\phi\times 3\,600 - 169\,028.66\right)\\[0.5em] x & = & & 600\,072.37\\ & & + & 211\,455.93 \times\lambda_1\\ & & - & 10\,938.51 \times\lambda_1\times\phi_1\\ & & - & 0.36\times\lambda_1\times\phi_1^2\\ & & - & 44.54\times\lambda_1^3\\[0.5em] y & = & & 200\,147.07\\ & & + & 308\,807.95\times\phi_1\\ & & + & 3\,745.25\times\lambda_1^2\\ & & + & 76.63\times\phi_1^2\\ & & - & 194.56\times\lambda_1^2\times\phi_1\\ & & + & 119.79\times\phi_1^3 \end{array}

L'inverse de cette « projection » est donnée par les formules suivantes :

\begin{array}{rcrl} x_1 & = & & \frac{x - 600\,000}{1\,000\,000}\\[0.5em] y_1 & = & & \frac{y - 200\,000}{1\,000\,000}\\[0.5em] \lambda_0 & = & & 2.6779094\\ & & + & 4.728982\times x_1\\ & & + & 0.791484\times x_1\times y_1\\ & & + & 0.1306\times x_1\times y_1^2\\ & & - & 0.0436\times x_1^3\\[0.5em] \phi_0 & = & & 16.9023892\\ & & + & 3.238272\times y_1\\ & & - & 0.270978\times x_1^2\\ & & - & 0.002528\times y_1^2\\ & & - & 0.0447\times x_1^2\times y_1\\ & & - & 0.0140\times y_1^3\\ \lambda & = & & \lambda_0\times\frac{100}{36}\\ \phi & = & & \phi_0\times\frac{100}{36} \end{array}

2 Mise en œuvre Java

Les différents concepts utiles à la réalisation de cette étape ayant été décrits, il reste à voir comment les mettre en œuvre en Java. Les sections ci-dessous énumèrent les différentes classes et interface à écrire dans ce but.

Prenez bien garde à écrire exactement les classes et interfaces qui vous sont demandées, jusque dans les moindres détails. Par exemple, si une classe est décrite comme étant « finale », la vôtre doit l'être également. Et si une méthode est décrite comme levant une exception donnée dans une certaine situation, votre méthode doit faire de même.

Toutes les classes et interfaces de ce projet appartiendront au paquetage ch.epfl.imhof ou à l'un de ses sous-paquetages.

Attention : avant de créer votre projet, il vous faut absolument configurer Eclipse en fonction des instructions données dans ce document. N'oubliez surtout pas de le faire, faute de quoi votre projet sera refusé par notre système de rendu et vous n'obtiendrez aucun point !

2.1 Points

Les deux types de points décrits ci-dessus, à savoir les points en coordonnées cartésiennes et ceux en coordonnées sphériques, sont représentés respectivement par les classes Point et PointGeo, décrites ci-dessous.

Point

La classe Point du paquetage ch.epfl.imhof.geometry, publique, finale et immuable, représente un point dans le plan, en coordonnées cartésiennes. Cette classe n'est dotée que d'un seul constructeur public :

  • Point(double x, double y), qui construit un point avec les coordonnées données.

Elle possède de plus les deux méthodes publiques suivantes :

  • double x(), qui retourne la coordonnée x du point.
  • double y(), qui retourne la coordonnée y du point.

PointGeo

La classe PointGeo du paquetage ch.epfl.imhof, publique, finale et immuable, représente un point à la surface de la Terre, dont la position est exprimée en coordonnées sphériques dans le système WGS 84. Cette classe est dotée d'un unique constructeur public :

  • PointGeo(double longitude, double latitude), qui construit un point avec la longitude et la latitude données (en radians). Lève l'exception IllegalArgumentException si la longitude est hors de l'intervalle \([-\pi; \pi]\) ou si la latitude est hors de l'intervalle \([-\tfrac{\pi}{2}; \tfrac{\pi}{2}]\).

Elle possède de plus les deux méthodes publiques suivantes, qui permettent d'obtenir les coordonnées du point :

  • double longitude(), qui retourne la longitude du point, en radians.
  • double latitude(), qui retourne la latitude du point, en radians.

Note : la constante PI de la classe java.lang.Math, qui contient la meilleure approximation possible de \(\pi\) par une valeur de type double, peut être utile à la programmation de cette classe.

2.2 Projection

La notion de projection est décrite en Java par l'interface Projection du paquetage ch.epfl.imhof.projection. Pour ce projet, deux classes implémentant cette interface sont de plus définies :

  • la classe EquirectangularProjection, qui représente la projection équirectangulaire,
  • la classe CH1903Projection, qui représente la « projection » CH1903 — même si, comme cela a été expliqué précédemment, il ne s'agit pas rigoureusement d'une simple projection.

Projection

L'interface Projection du paquetage ch.epfl.imhof.projection représente une projection. Cette interface est dotée des deux méthodes suivantes, qui sont inverses l'une de l'autre :

  • Point project(PointGeo point), qui projette sur le plan le point reçu en argument.
  • PointGeo inverse(Point point), qui « dé-projette » le point du plan reçu en argument.

EquirectangularProjection

La classe EquirectangularProjection du paquetage ch.epfl.imhof.projection, publique, finale et immuable, représente la projection équirectangulaire.

CH1903Projection

La classe CH1903Projection du paquetage ch.epfl.imhof.projection, publique, finale et immuable, représente la projection CH1903.

Note : étant donné que les formules données pour la projection CH1903 font l'hypothèse que les longitudes et latitudes sont exprimées en degrés, des conversions sont nécessaires. Pour les effectuer, vous pouvez utiliser les méthodes toDegrees et toRadians de la classe Math. La méthode pow de cette classe, qui permet d'élever un nombre à une puissance donnée, peut également vous être utile.

2.3 Tests

Pour vous aider à démarrer ce projet, nous vous fournissons exceptionnellement une archive Zip contenant des tests unitaires JUnit pour cette étape.

Pour pouvoir utiliser ces tests, il vous faut tout d'abord les importer dans votre projet en suivant les indications d'importation d'archive Zip dans Eclipse, puis ajouter la bibliothèque JUnit à votre projet, en suivant les explications à ce sujet.

Attention : nous ne garantissons pas l'exhaustivité de ces tests et nous nous réservons le droit d'utiliser des tests plus complets que ceux-ci pour noter votre projet.

2.4 Documentation

Une fois les tests exécutés avec succès, il reste à documenter la totalité des entités publiques (classes, champs et méthodes) définies dans cette étape, au moyen de commentaires Javadoc. Vous pouvez écrire ces commentaires en français ou en anglais, en fonction de votre préférence, mais vous ne devez utiliser qu'une seule langue pour tout le projet.

Les commentaires Javadoc sont des commentaires structurés que l'on peut attacher aux différentes entités d'un programme (classes, interfaces, champs et méthodes). On les reconnaît au fait qu'ils commencent par une barre oblique suivie de deux astérisques (/**).

Les commentaires Javadoc peuvent inclure des étiquettes (tag), qui commencent par un arobas (@). Même s'il existe de nombreuses étiquettes, les quatre les plus importantes sont :

  1. L'étiquette @author, qui est suivie du nom d'un des auteurs de la classe ou interface à laquelle elle est attachée. Peut apparaître plusieurs fois s'il y a plus d'un auteur.
  2. L'étiquette @param, qui est suivie du nom d'un paramètre de l'entité à laquelle on l'attache (méthode ou constructeur) et d'une description de la signification de ce paramètre.
  3. L'étiquette @throws, qui est suivie du nom d'une exception qui peut être levée par la méthode à laquelle on l'attache et d'une description des cas dans lesquels elle est levée.
  4. L'étiquette @return, qui est suivie d'une description de la valeur retournée par la méthode à laquelle on l'attache.

Pour ce projet, vous avez l'obligation de lister la totalité des auteurs de chaque interface ou classe publique que vous rendez. Le prénom et le nom de chaque auteur doit être suivi de son numéro SCIPER entre parenthèses.

Pour illustrer l'utilisation des différentes étiquettes mentionnées plus haut, voici ce à quoi la documentation de la classe PointGeo et de son constructeur pourrait ressembler :

/**
 * Un point à la surface de la Terre, en coordonnées
 * sphériques.
 *
 * @author Marie Durand (654321)
 * @author Jean Dupond (123456)
 */
public final class PointGeo {
    // 

    /**
     * Construit un point avec la latitude et la longitude
     * données.
     *
     * @param longitude
     *            la longitude du point, en radians
     * @param latitude
     *            la latitude du point, en radians
     * @throws IllegalArgumentException
     *             si la longitude est invalide, c-à-d hors
     *             de l'intervalle [-π; π]
     * @throws IllegalArgumentException
     *             si la latitude est invalide, c-à-d hors
     *             de l'intervalle [-π/2; π/2]
     */
    public PointGeo(double longitude, double latitude) {
        // 
    }

    // 
}

Deux commandes Eclipse sont d'une grande aide lorsqu'on rédige des commentaires Javadoc :

  1. Dans le menu Source, l'entrée Generate Element Comment permet de générer un squelette de commentaire Javadoc pour l'élément sous le curseur.
  2. Dans le menu Source, l'entrée Format Element permet de reformatter l'élément sous le curseur. Lorsqu'on l'utilise dans un commentaire Javadoc, celui est reformatté de manière plaisante.

3 Résumé

Pour cette étape, vous devez :

  • configurer Eclipse selon les indications données dans le document consacré à ce sujet,
  • écrire les classes PointGeo, Point, EquirectangularProjection et CH1903Projection ainsi que l'interface Projection en fonction des spécifications données plus haut,
  • vérifier que les tests que nous vous fournissons s'exécutent sans erreur, et dans le cas contraire, corriger votre code,
  • documenter la totalité des entités publiques que vous avez définies,
  • (optionnel mais vivement recommandé) rendre votre code au plus tard le 20 février 2015 à 16h00, via le système de rendu.

Ce premier rendu n'est pas noté, mais celui de la prochaine étape le sera. Dès lors, il vous est fortement conseillé de faire un rendu de test cette semaine afin de vous familiariser avec la procédure à suivre.