Classes de base

Chaque objet géométrique est considéré comme un ensemble infini de points. En tant qu’ensemble, leurs opérations les plus fondamentales sont de même nature que les opérations standards des collections du Java. On pourrait donc voir une géométrie comme une sorte de java.util.Set dont les éléments seraient des points, à ceci près que le nombre d’éléments contenus dans cet ensemble est infini (à l’exception des géométries représentant un simple point). Pour mieux représenter ce concept, la norme ISO et GeoAPI définissent une interface TransfiniteSet que l’on peut voir comme un Set de taille infini. Bien qu’un lien de parenté existe conceptuellement entre ces interfaces, GeoAPI ne définit pas TransfiniteSet comme une sous-interface de java.util.Set car la définition de certaines méthodes telles que size() et iterator() serait problématique. On y retrouve toutefois des méthodes très similaires telles que contains(…) et intersects(…).

Toutes les géométries sont des spécialisations de TransfiniteSet. La classe parente de toutes ces géométries est appelée GM_Object dans la norme ISO 19107. Les interfaces de GeoAPI utilisent plutôt le nom Geometry, car l’omission du préfixe GM_ (comme le veut la convention dans GeoAPI) aurait laissé un nom trop proche de la classe Object du Java.

Points et positions directes

ISO 19107 définit deux types de structures pour représenter un point: GM_Point et DirectPosition. Le premier type est une véritable géométrie et peut donc être relativement lourd, selon les implémentations. Le second type n’est pas considéré formellement comme une géométrie; il n’étend ni GM_Object ni TransfiniteSet. Il ne définit pratiquement pas d’opérations autres que le stockage d’une séquence de nombres représentant une coordonnée. Il peut donc être un objet plus léger.

Afin de permettre à l’API de travailler indifféremment avec ces deux types de positions, ISO 19107 définit Position comme une union de DirectPosition et GM_Point. Il s’agit d’une union au sens du C/C++. Pour le langage Java, GeoAPI obtient le même effet en définissant Position comme l’interface parente de DirectPosition et Point. Dans la pratique, la grande majorité des API de Apache SIS travaillent sur des DirectPosition, ou occasionnellement des Position quand il semble utile d’autoriser aussi des points géométriques.

Enveloppes

Les enveloppes stockent les valeurs minimales et maximales des coordonnées d’une géométrie. Les enveloppes ne sont pas elles-mêmes des géométries; ce ne sont pas des ensembles infinis de points (TransfiniteSet). Il n’y a aucune garantie que toutes les positions contenues dans les limites d’une enveloppe soient géographiquement valides. Il faut voir les enveloppes comme une information sur les valeurs extrêmes que peuvent prendre les coordonnées d’une géométrie en faisant comme si chaque dimension était indépendante des autres, rien de plus. Nous assimilons néanmoins les enveloppes à des rectangles, cubes ou hyper-cubes (selon le nombre de dimensions) afin de faciliter la discussion, mais en gardant à l’esprit leur nature non-géométrique.

Exemple: Nous pouvons tester si une position est à l’intérieur des limites de l’enveloppe. Un résultat positif ne garantie pas que la position est à l’intérieur de la géométrie délimitée par l’enveloppe, mais un résultat négatif garantie qu’elle est à l’extérieur. De même on peut effectuer des tests d’intersections. En revanche appliquer une rotation n’a pas beaucoup de sens pour une enveloppe, car le résultat peut être très différent de celui que nous aurions obtenu en effectuant une rotation de la géométrie originale, puis en recalculant son enveloppe.

Une enveloppe peut être représentée par deux positions correspondant à deux coins opposés d’un rectangle, cube ou hyper-cube. On prend souvent comme premier coin celui dont toutes les ordonnées ont la valeur minimale (lowerCorner), et comme second coin celui dont toutes les ordonnées ont la valeur maximale (upperCorner). Lors d’un affichage utilisant un système de coordonnées classique (valeurs de l’axe des y augmentant vers le haut), ces deux positions apparaissent respectivement dans le coin inférieur gauche et dans le coin supérieur droit d’un rectangle. Attention toutefois aux différents systèmes de coordonnées, qui peuvent faire varier les positions de ces coins à l’écran. Les expressions lower corner et upper corner doivent être comprises au sens mathématique plutôt que visuel.

Enveloppes traversant l’antiméridien

Les minimums et maximums sont les valeurs les plus souvent assignées aux lowerCorner et upperCorner. Mais les choses se compliquent dans le cas d’une enveloppe traversant l’antiméridien (-180° ou 180° de longitude). Par exemple, une enveloppe de 10° de largeur peut commencer à 175° de longitude et se terminer à -175°. Dans ce cas, la valeur de longitude assignée au lowerCorner est supérieure à celle qui est assignée à l’upperCorner. Apache SIS emploie donc une définition légèrement différente de ces deux coins:

Lorsque l’enveloppe ne traverse par l’antiméridien, ces deux définitions sont équivalentes à la sélection des valeurs minimales et maximales respectivement. C’est le cas du rectangle vert dans la figure ci-dessous. Lorsque l’enveloppe traverse l’antiméridien, les coins lowerCorner et upperCorner apparaissent encore en bas et en haut du rectangle (en supposant un système de coordonnées classique), donc leurs noms restent appropriés d’un point de vue visuel. Mais les positions gauche et droite sont interchangées. Ce cas est représenté par le rectangle rouge dans la figure ci-dessous.

Exemples d’enveloppes avec et sans croisement de l’antiméridien.

Les notions d’inclusion et d’intersection s’interprètent toutefois de manière légèrement différente dans ces deux cas. Dans le cas habituel où l’on ne traverse pas l’antiméridien, le rectangle vert délimite bien une région d’inclusion. Les régions exclues de ce rectangle se propagent à l’infini dans toutes les directions. En d’autres mots, la région d’inclusion n’est pas répétée tous les 360°. Mais dans le cas du rectangle rouge, l’information fournie par l’enveloppe délimite plutôt la région d’exclusion qui se trouve entre les deux bords du rectangle. La région d’inclusion se propage à l’infini des côtés gauche et droit. Nous pourrions stipuler que toute longitude inférieure à -180° ou supérieure à 180° est considérée exclue, mais ça serait une décision arbitraire qui ne serait pas un reflet symétrique du cas habituel (rectangle vert). Un développeur pourrait vouloir utiliser ces valeurs, par exemple dans une mosaïque où la carte du monde est répétée plusieurs fois horizontalement tout en considérant chaque répétition comme distincte des autres. Si un développeur souhaite effectuer des opérations comme si les régions d’inclusions ou d’exclusions étaient répétées tous les 360°, alors il doit lui-même ramener ses valeurs de longitudes entre -180° et 180° au préalable. Toutes les fonctions add(…), contains(…), intersect(…), etc. de toutes les enveloppes définies dans le paquet org.apache.sis.geometry effectuent leurs calculs selon cette convention.

Pour que les fonctions telles que add(…) fonctionnent correctement, tous les objets impliqués doivent utiliser le même système de référence des coordonnées, y compris la même plage de valeurs. Ainsi, une enveloppe exprimant les longitudes dans la plage [-180 … +180]° n’est pas compatible avec une enveloppe exprimant les longitudes dans la plage [0 … 360]°. Les conversions, si nécessaires, sont à la charge de l’utilisateur (la classe Envelopes fournit des méthodes de commodités pour ce faire). En outre, les coordonnées de l’enveloppe doivent être comprises dans les limites du système de coordonnées, sauf si le développeur souhaite volontairement considérer (par exemple) 300° de longitude comme un position distincte de -60°. La classe GeneralEnvelope fournit une méthode normalize() pour ramener les coordonnées dans les limites attendues, au prix parfois de valeurs lower supérieures à la valeur upper.