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.
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.
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.
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:
lowerCorner
:
le point de départ lorsque l’on parcourt l’intérieur de l’enveloppe dans la direction des valeurs croissantes.
upperCorner
:
le point d’arrivé lorsque l’on a parcouru l’intérieur de l’enveloppe dans la direction des valeurs croissantes.
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.
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.