content/fr/developer-guide/annexes/design/AffineTransform.html (151 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" xmlns:xi="http://www.w3.org/2001/XInclude" xml:lang="fr">
<head>
<title>DesignNotes</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" file
by the 'org.apache.sis.internal.book.Assembler' class in 'sis-build-helper' module.
-->
<section>
<header>
<h2 id="AffineTransform">Utilisation des transformations affines</h2>
</header>
<p>
Parmi les sortes d’opérations qu’un <abbr>SIG</abbr> doit effectuer sur les coordonnées spatiales,
les <cite>transformations affines</cite> sont à la fois relativement simples et très fréquentes.
Les transformations affines peuvent représenter n’importe quelle combinaison d’échelles, de cisaillements,
de retournements, de rotations ou de translations, qui sont toutes des <cite>opérations linéaires</cite>.
Les transformations affines ne peuvent pas effectuer des opérations <cite>non-linéaires</cite>
telles que les projections cartographiques, mais couvrent néanmoins de nombreux autres cas:
</p>
<ul>
<li>Changer l’ordre des axes, par exemple de (<var>latitude</var>, <var>longitude</var>) vers (<var>longitude</var>, <var>latitude</var>).</li>
<li>Changer la direction des axes, par exemple l’axe des <var>y</var> qui pointe habituellement vers le bas dans les images.</li>
<li>Changer le méridien d’origine, par exemple du méridien de <cite>Paris</cite> vers celui de <cite>Greenwich</cite>.</li>
<li>Changer le nombre de dimensions, par exemple passer des coordonnées 3D vers 2D en supprimant la hauteur.</li>
<li>Convertir des unités de mesures, par exemple convertir des pieds en mètres.</li>
<li>Convertir des coordonnées pixels en coordonnées géographiques,
par exemple la conversion exprimée dans les fichiers <code>.tfw</code> qui accompagnent certaines images <abbr>TIFF</abbr>.</li>
<li>Prendre en charge une petite partie des projections cartographiques,
par exemple les paramètres <cite>False Easting</cite>, <cite>False Northing</cite> et <cite>Scale factor</cite>.</li>
</ul>
<p>
Les transformations affines peuvent se combiner efficacement.
Peu importe le nombre de transformations affines que l’on enchaîne, le résultat sera exprimable par une seule transformation affine.
Cette propriété est plus facilement visible lorsque les transformations affines sont exprimées sous forme de matrices:
pour combiner les opérations, il suffit de multiplier les matrices.
Le cas des conversions des coordonnées pixels en coordonnées géographiques ci-dessous donne un exemple.
</p>
<div class="example">
<p><b>Exemple:</b>
supposons que nous disposons d’une image dont les coordonnées des pixels sont représentées par (<var>x</var>,<var>y</var>).
Supposons aussi que les contraintes suivantes sont respectées:
</p>
<ul>
<li>Il n’y a ni cisaillement, ni rotation, ni retournement de l’image.</li>
<li>Tous les pixels ont la même largeur en degrés de longitude.</li>
<li>Tous les pixels ont la même hauteur en degrés de latitude.</li>
<li>Les coordonnées des pixels commencent à (0,0) inclusivement.</li>
</ul>
<p>Alors la conversion des coordonnées pixels (<var>x</var>,<var>y</var>)
vers les coordonnées géographiques (<var>λ</var>,<var>φ</var>)
peut être représentée par les équations suivantes,
où <var>N</var><sub><var>x</var></sub> est la largeur
et <var>N</var><sub><var>y</var></sub> la hauteur de l’image en nombre de pixels.
</p><p>
<xi:include href="../../../../../layouts/partials/math/PixelToGeographicTerms.html"/>
</p><p>
Les équations ci-dessus peuvent être représentées sous forme de matrices comme ci-dessous:
</p><p>
<xi:include href="../../../../../layouts/partials/math/PixelToGeographic.html"/>
</p><p>
Dans ce cas particulier, les facteurs d’échelles <var>S</var> correspondent à la taille des pixels en degrés
et les termes de translations <var>T</var> correspondent aux coordonnées géographiques d’un coin de l’image
(pas nécessairement le coin inférieur gauche si certains axes ont été retournés).
Cette interprétation directe n’est possible que lorsque les contraintes énumérées plus haut sont respectées.
Les coefficients des matrices deviennent plus complexes si l’image a un cisaillement ou une rotation,
ou si les coordonnées des pixels ne commencent pas à (0,0).
Toutefois il n’est pas nécessaire d’utiliser des équations plus complexes pour gérer des cas plus génériques.
L’exemple ci-dessous prend comme point de départ la matrice d’une « conversion initiale »
dans laquelle les coefficients <var>S</var> et <var>T</var> sont les valeurs relativement simples données ci-dessus.
Ensuite la direction de l’axe des <var>y</var> est inversée de manière à correspondre
à la convention habituelle des systèmes de coordonnées des images (changement 1),
et les axes sont intervertis de manière à avoir la latitude avant la longitude (changement 2).
Notez que les concaténations de transformations affines écrites sous forme de multiplications matricielles
se lisent de droite à gauche:
<var>A</var>×<var>B</var>×<var>C</var> est équivalent à d’abord appliquer l’opération <var>C</var>,
suivit de l’opération <var>B</var> et finalement l’opération <var>A</var>.
</p>
<div style="display:table; margin:auto">
<div style="display:table-row">
<div style="display:table-cell" class="caption">Changement 2</div>
<div style="display:table-cell" class="caption"> </div>
<div style="display:table-cell" class="caption">Changement 1</div>
<div style="display:table-cell" class="caption"> </div>
<div style="display:table-cell" class="caption">Conversion initiale</div>
<div style="display:table-cell" class="caption"> </div>
<div style="display:table-cell" class="caption">Opérations combinées</div>
</div>
<div style="display:table-row">
<div style="display:table-cell; vertical-align:middle"><xi:include href="../../../../../layouts/partials/math/AxisSwapping2D.html"/></div>
<div style="display:table-cell; vertical-align:middle; padding-left: 15px; padding-right: 15px">×</div>
<div style="display:table-cell; vertical-align:middle"><xi:include href="../../../../../layouts/partials/math/InverseAxisY.html"/></div>
<div style="display:table-cell; vertical-align:middle; padding-left: 15px; padding-right: 15px">×</div>
<div style="display:table-cell; vertical-align:middle"><xi:include href="../../../../../layouts/partials/math/PixelToGeographicSameAxisDirections.html"/></div>
<div style="display:table-cell; vertical-align:middle; padding-left: 15px; padding-right: 15px">=</div>
<div style="display:table-cell; vertical-align:middle"><xi:include href="../../../../../layouts/partials/math/PixelToGeographicReverseOrderAndY.html"/></div>
</div>
</div>
<p>
Un principe clé est qu’il n’y a pas besoin d’écrire un code dédié à ce type d’opérations sur les axes.
Ces opérations, et bien d’autres, sont prises en compte naturellement par l’algèbre matricielle.
On y gagne en généricité du code et en performance.
Apache <abbr>SIS</abbr> suit ce principe en utilisant les tranformations affine pour toutes les opérations
où elles peuvent s’appliquer.
Il n’y a par exemple aucun code dédié au changement de l’ordre des ordonnées dans une coordonnée.
</p>
</div>
<h3 id="AffineTransformAPI">Intégration avec les bibliothèques graphiques</h3>
<p>
A peu près toutes les bibliothèques graphiques supportent une forme de transformation de coordonnées,
souvent les <cite>transformations affines</cite> ou une légère généralisation.
Chaque bibliothèque défini son propre <abbr>API</abbr>.
Quelques exemples sont:
</p>
<table>
<caption>Implémentations des transformations affines dans des bibliothèques graphiques</caption>
<tr><th>Bibliothèque</th> <th>Implementation de la transformation</th> <th>Dimensions</th></tr>
<tr><td>Java2D</td> <td><code>java.awt.geom.AffineTransform</code></td> <td>2</td></tr>
<tr><td>Java3D</td> <td><code>javax.media.j3d.Transform3D</code></td> <td>3</td></tr>
<tr><td>JavaFX</td> <td><code>javafx.scene.transform.Affine</code></td> <td>2 ou 3</td></tr>
<tr><td>Java Advanced Imaging (<abbr>JAI</abbr>)</td> <td><code>javax.media.jai.PerspectiveTransform</code></td> <td>2</td></tr>
<tr><td>Android</td> <td><code>android.graphics.Matrix</code></td> <td>2</td></tr>
</table>
<p>
Toutefois dans plusieurs cas, les transformations affines sont les seuls types d’opérations supportées par la bibliothèque graphique.
Apache <abbr>SIS</abbr> a besoin de gérer un plus grand nombre de type d’opérations,
parmi lesquelles les transformations affines ne sont que des cas particuliers.
Les projections cartographiques et les changements de référentiels notamment,
ne peuvent pas être représentés par des transformations affines.
<abbr>SIS</abbr> a aussi besoin de transformer des points ayant un nombre arbitraire de dimensions,
alors que les <abbr>API</abbr> cités ci-haut restreignent leur usage à un nombre fixe de dimensions.
Pour ces raisons, <abbr>SIS</abbr> ne peut pas utiliser directement ces <abbr>API</abbr>.
<abbr>SIS</abbr> utilise plutôt une interface plus abstraite, <code>org.opengis.referencing.transform.MathTransform</code>.
Mais dans le cas particulier où la transformation est réellement affine, <abbr>SIS</abbr> peut essayer d’utiliser
une implémentation existante, surtout Java2D.
Par exemple le code suivant peut être utilisé dans les situations où un objet Java2D est désiré:
</p>
<pre><code>MathTransform mt = ...; // N’importe quelle instance créée par Apache SIS.
if (mt instanceof AffineTransform) {
AffineTransform at = (AffineTransform) mt;
// Utiliser l’API de Java2D API à partir d’ici.
}</code></pre>
<p>
Toutefois <abbr>SIS</abbr> n’utilisera Java2D que sur une base opportuniste.
Le forçage de type ci-haut n’est pas garantit de réussir, même si l’instance de
<code>MathTransform</code> répond aux conditions qui devrait permettre un usage de Java2D.
</p>
</section>
</body>
</html>