content/fr/developer-guide/geometry/GeometryBase.html (173 lines of code) (raw):

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE html> <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr"> <head> <title>GeometryBase</title> <meta charset="UTF-8"/> <link rel="stylesheet" type="text/css" href="../book.css"/> </head> <body> <!-- Content below this point is copied in "/static/book/fr/developer-guide.html" by the 'org.apache.sis.internal.book.Assembler' class in 'sis-build-helper' module. --> <section> <header> <h2 id="GeometryBase">Classes de base</h2> </header> <p> 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 <code>java.util.Set</code> 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 <abbr>ISO</abbr> et GeoAPI définissent une interface <code class="OGC">TransfiniteSet</code> que l’on peut voir comme un <code>Set</code> de taille infini. Bien qu’un lien de parenté existe conceptuellement entre ces interfaces, GeoAPI ne définit pas <code>TransfiniteSet</code> comme une sous-interface de <code>java.util.Set</code> car la définition de certaines méthodes telles que <code>size()</code> et <code>iterator()</code> serait problématique. On y retrouve toutefois des méthodes très similaires telles que <code class="GeoAPI">contains(…)</code> et <code class="GeoAPI">intersects(…)</code>. </p> <p> Toutes les géométries sont des spécialisations de <code>TransfiniteSet</code>. La classe parente de toutes ces géométries est appelée <code>GM_Object</code> dans la norme <abbr>ISO</abbr> 19107. Les interfaces de GeoAPI utilisent plutôt le nom <code>Geometry</code>, car l’omission du préfixe <code class="OGC">GM_</code> (comme le veut la convention dans GeoAPI) aurait laissé un nom trop proche de la classe <code>Object</code> du Java. </p> <h3 id="DirectPosition">Points et positions directes</h3> <p> <abbr>ISO</abbr> 19107 définit deux types de structures pour représenter un point: <code>GM_Point</code> et <code class="OGC">DirectPosition</code>. 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 <code>GM_Object</code> ni <code class="OGC">TransfiniteSet</code>. 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. </p> <p> Afin de permettre à l’<abbr>API</abbr> de travailler indifféremment avec ces deux types de positions, <abbr>ISO</abbr> 19107 définit <code class="OGC">Position</code> comme une <cite>union</cite> de <code class="OGC">DirectPosition</code> et <code>GM_Point</code>. Il s’agit d’une union au sens du C/C++. Pour le langage Java, GeoAPI obtient le même effet en définissant <code>Position</code> comme l’interface parente de <code>DirectPosition</code> et <code>Point</code>. Dans la pratique, la grande majorité des <abbr>API</abbr> de Apache <abbr>SIS</abbr> travaillent sur des <code>DirectPosition</code>, ou occasionnellement des <code>Position</code> quand il semble utile d’autoriser aussi des points géométriques. </p> <h3 id="Envelope">Enveloppes</h3> <p> Les enveloppes stockent les valeurs minimales et maximales des coordonnées d’une géométrie. Les enveloppes <em>ne sont pas</em> elles-mêmes des géométries; ce ne sont pas des ensembles infinis de points (<code class="OGC">TransfiniteSet</code>). 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. </p> <div class="example"><p><b>Exemple:</b> 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. </p></div> <p> 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 (<code class="OGC">lowerCorner</code>), et comme second coin celui dont toutes les ordonnées ont la valeur maximale (<code class="OGC">upperCorner</code>). Lors d’un affichage utilisant un système de coordonnées classique (valeurs de l’axe des <var>y</var> 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 <i>lower corner</i> et <i>upper corner</i> doivent être comprises au sens mathématique plutôt que visuel. </p> <h4 id="AntiMeridian">Enveloppes traversant l’antiméridien</h4> <p> Les minimums et maximums sont les valeurs les plus souvent assignées aux <code class="OGC">lowerCorner</code> et <code class="OGC">upperCorner</code>. 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 <code class="OGC">lowerCorner</code> est supérieure à celle qui est assignée à l’<code class="OGC">upperCorner</code>. Apache <abbr>SIS</abbr> emploie donc une définition légèrement différente de ces deux coins: </p> <ul> <li><b><code class="SIS">lowerCorner</code>:</b> le point de départ lorsque l’on parcourt l’intérieur de l’enveloppe dans la direction des valeurs croissantes. </li> <li><b><code class="SIS">upperCorner</code>:</b> le point d’arrivé lorsque l’on a parcouru l’intérieur de l’enveloppe dans la direction des valeurs croissantes. </li> </ul> <p> 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 <code class="SIS">lowerCorner</code> et <code class="SIS">upperCorner</code> 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. </p> <p style="text-align:center"> <img src="../../apidocs/org/apache/sis/geometry/doc-files/AntiMeridian.png" alt="Exemples d’enveloppes avec et sans croisement de l’antiméridien."/> </p> <p> 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 <code class="SIS">add(…)</code>, <code class="SIS">contains(…)</code>, <code class="SIS">intersect(…)</code>, <i>etc.</i> de toutes les enveloppes définies dans le paquet <code>org.apache.sis.geometry</code> effectuent leurs calculs selon cette convention. </p> <aside> <h5>Généralisation à d’autres types d’axes</h5> <p> Cette section nomme spécifiquement la longitude car il constitue le cas le plus courant d’axe cyclique. Mais dans les enveloppes de Apache <abbr>SIS</abbr>, il n’est fait nul part mention explicite du cas de la longitude, ni de son cycle de 360°. Les caractéristiques de la plage de valeurs de chaque axe (ses extremums, unités, type de cycle, <i>etc.</i>) sont des attributs des objets <code>CoordinateSystemAxis</code>, indirectement associés aux enveloppes via le système de référence des coordonnées. Apache <abbr>SIS</abbr> inspecte ces attributs pour déterminer de quelle façon il doit effectuer ses opérations. Ainsi, tout axe associé au code <code>RangeMeaning.WRAPAROUND</code> bénéficiera du même traitement que la longitude. Cela pourrait être par exemple un axe du temps dans des données climatologiques (une “année” représentant la température moyenne de tous les mois de janvier, suivit de la moyenne de tous les mois de février, <i>etc.</i>). Cette généralisation s’applique aussi aux axes de longitudes définis par une plage de 0° à 360° plutôt que de -180° à 180°. </p> </aside> <p> Pour que les fonctions telles que <code class="SIS">add(…)</code> 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 <code>Envelopes</code> 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 <code>GeneralEnvelope</code> fournit une méthode <code class="SIS">normalize()</code> pour ramener les coordonnées dans les limites attendues, au prix parfois de valeurs <cite><i>lower</i></cite> supérieures à la valeur <cite><i>upper</i></cite>. </p> <aside> <h5>Le cas particulier de la plage [+0 … -0]</h5> <p> le Java (ou de manière plus générale, la norme IEEE 754) définit deux valeurs distinctes de zéro: un zéro positif et un zéro négatif. Ces deux valeurs sont considérées égales lorsqu’on les compares avec l’opérateur <code>==</code> du Java. Mais dans les enveloppes de <abbr>SIS</abbr>, ils peuvent mener à des résultats opposés pour les axes ayant <code>RangeMeaning.WRAPAROUND</code>. Une enveloppe dont la plage est [0 … 0], [-0 … -0] ou [-0 … +0] sera bien considérée comme une enveloppe vide, mais la page [+0 … -0] sera au contraire considérée comme incluant la totalité des valeurs, jusqu’à l’infini. Ce comportement est conforme à la définition de <code class="SIS">lowerCorner</code> et <code class="SIS">upperCorner</code> qui considère +0 comme le point de départ, et -0 comme le point d’arrivé après avoir fait le tour des valeurs possibles. Un tel comportement ne se produit que pour la paire de valeurs +0 et -0, et seulement dans cet ordre. Pour toutes les autres valeurs réelles, si la condition <code>lower</code> <code>==</code> <code>upper</code> est vrai, alors il est garanti que l’enveloppe est vide. </p> </aside> </section> </body> </html>