AngleFormat changes for revisions 10795:10796

Changes in this commit seem to be the result of some "auto reformat" tool execution. The Java - GeoAPI - GeoTools import ordering is altered, imports used only in Javadoc are lost and the encoding of non-ASCII characters is broken. This commit has been reverted, except for the removal of really unused imports which are kept removed.

Command line:

svn diff --extensions "--unified --ignore-space-change --ignore-all-space --ignore-eol-style" -r10795:10796 https://svn.osgeo.org/geotools/trunk/modules/library/referencing/src/main/java/org/geotools/measure/AngleFormat.java
Revision 10795Revision 10796
/*
 * Geotools 2 - OpenSource mapping toolkit
 * (C) 2003, Geotools Project Managment Committee (PMC)
 * (C) 2001, Institut de Recherche pour le Développement
 * (C) 1999, Fisheries and Oceans Canada
 *
 *    This library is free software; you can redistribute it and/or
/*
 * Geotools 2 - OpenSource mapping toolkit
 * (C) 2003, Geotools Project Managment Committee (PMC)
 * (C) 2001, Institut de Recherche pour le D�veloppement
 * (C) 1999, Fisheries and Oceans Canada
 *
 *    This library is free software; you can redistribute it and/or
package org.geotools.measure;

// Text format
import java.util.Locale;
import java.text.Format;
import java.text.DecimalFormat;
import java.text.FieldPosition;
import java.text.ParsePosition;
import java.text.ParseException;
import java.text.DecimalFormatSymbols;

// Input/output
import java.io.IOException;
import java.io.ObjectInputStream;

// Resources
import org.geotools.resources.XMath;
import org.geotools.resources.Utilities;
import org.geotools.resources.cts.Resources;
import org.geotools.resources.cts.ResourceKeys;


/**
package org.geotools.measure;

// Text format
import java.io.IOException;
import java.io.ObjectInputStream;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.FieldPosition;
import java.text.Format;
import java.text.ParseException;
import java.text.ParsePosition;
import java.util.Locale;

import org.geotools.resources.Utilities;
import org.geotools.resources.XMath;
import org.geotools.resources.cts.ResourceKeys;
import org.geotools.resources.cts.Resources;


/**
* <br>
* Upper-case letters <code>D</code>, <code>M</code> and <code>S</code> are for the integer
* parts of degrees, minutes and seconds respectively. They must appear in this order (e.g.
* "<code>M'D</code>" is illegal because "M" and "S" are inverted; "<code>D°S</code>" is
* illegal too because there is no "M" between "D" and "S"). Lower-case letters <code>d</code>,
* <code>m</code> and <code>s</code> are for fractional parts of degrees, minutes and seconds
* respectively. Only one of those may appears in a pattern, and it must be the last special
* symbol (e.g. "<code>D.dd°MM'</code>" is illegal because "d" is followed by "M";
* "<code>D.mm</code>" is illegal because "m" is not the fractional part of "D").
* <br><br>
* The number of occurrence of <code>D</code>, <code>M</code>, <code>S</code> and their
* lower-case counterpart is the number of digits to format. For example, "DD.ddd" will
* format angle with two digits for the integer part and three digits for the fractional
* part (e.g. 4.4578 will be formatted as "04.458"). Separator characters like <code>°</code>,
* <code>'</code> and <code>"</code> and inserted "as-is" in the formatted string (except the
* decimal separator dot ("<code>.</code>"), which is replaced by the local-dependent decimal
* separator). Separator characters may be completely omitted; <code>AngleFormat</code> will
* still differentiate degrees, minutes and seconds fields according the pattern. For example,
* "<code>0480439</code>" with the pattern "<code>DDDMMmm</code>" will be parsed as 48°04.39'.
* <br><br>
* The following table gives some examples of legal patterns.
*
* <blockquote><table cellpadding="3">
* <tr><th>Pattern                </th>  <th>Example   </th></tr>
* <tr><td><code>DD°MM'SS" </code></td>  <td>48°30'00" </td></tr>
* <tr><td><code>DD°MM'    </code></td>  <td>48°30'    </td></tr>
* <tr><td><code>DD.ddd    </code></td>  <td>48.500    </td></tr>
* <tr><td><code>DDMM      </code></td>  <td>4830      </td></tr>
* <tr><td><code>DDMMSS    </code></td>  <td>483000    </td></tr>
* <br>
* Upper-case letters <code>D</code>, <code>M</code> and <code>S</code> are for the integer
* parts of degrees, minutes and seconds respectively. They must appear in this order (e.g.
* "<code>M'D</code>" is illegal because "M" and "S" are inverted; "<code>D�S</code>" is
* illegal too because there is no "M" between "D" and "S"). Lower-case letters <code>d</code>,
* <code>m</code> and <code>s</code> are for fractional parts of degrees, minutes and seconds
* respectively. Only one of those may appears in a pattern, and it must be the last special
* symbol (e.g. "<code>D.dd�MM'</code>" is illegal because "d" is followed by "M";
* "<code>D.mm</code>" is illegal because "m" is not the fractional part of "D").
* <br><br>
* The number of occurrence of <code>D</code>, <code>M</code>, <code>S</code> and their
* lower-case counterpart is the number of digits to format. For example, "DD.ddd" will
* format angle with two digits for the integer part and three digits for the fractional
* part (e.g. 4.4578 will be formatted as "04.458"). Separator characters like <code>�</code>,
* <code>'</code> and <code>"</code> and inserted "as-is" in the formatted string (except the
* decimal separator dot ("<code>.</code>"), which is replaced by the local-dependent decimal
* separator). Separator characters may be completely omitted; <code>AngleFormat</code> will
* still differentiate degrees, minutes and seconds fields according the pattern. For example,
* "<code>0480439</code>" with the pattern "<code>DDDMMmm</code>" will be parsed as 48�04.39'.
* <br><br>
* The following table gives some examples of legal patterns.
*
* <blockquote><table cellpadding="3">
* <tr><th>Pattern                </th>  <th>Example   </th></tr>
* <tr><td><code>DD�MM'SS" </code></td>  <td>48�30'00" </td></tr>
* <tr><td><code>DD�MM'    </code></td>  <td>48�30'    </td></tr>
* <tr><td><code>DD.ddd    </code></td>  <td>48.500    </td></tr>
* <tr><td><code>DDMM      </code></td>  <td>4830      </td></tr>
* <tr><td><code>DDMMSS    </code></td>  <td>483000    </td></tr>
 */
public class AngleFormat extends Format {
    /**
     * Caractère représentant l'hémisphère nord.
     * Il doit obligatoirement être en majuscule.
     */
    private static final char NORTH='N';

    /**
     * Caractère représentant l'hémisphère sud.
     * Il doit obligatoirement être en majuscule.
     */
    private static final char SOUTH='S';

    /**
     * Caractère représentant l'hémisphère est.
     * Il doit obligatoirement être en majuscule.
     */
    private static final char EAST='E';

    /**
     * Caractère représentant l'hémisphère ouest.
     * Il doit obligatoirement être en majuscule.
     */
    private static final char WEST='W';

    /**
     * Constante indique que l'angle
     * à formater est une longitude.
     */
    static final int LONGITUDE=0;

    /**
     * Constante indique que l'angle
     * à formater est une latitude.
     */
    static final int LATITUDE=1;

    /**
     * Constante indique que le nombre
     * à formater est une altitude.
     */
    static final int ALTITUDE=2;
 */
public class AngleFormat extends Format {
    /**
     * Caract�re repr�sentant l'h�misph�re nord.
     * Il doit obligatoirement �tre en majuscule.
     */
    private static final char NORTH='N';

    /**
     * Caract�re repr�sentant l'h�misph�re sud.
     * Il doit obligatoirement �tre en majuscule.
     */
    private static final char SOUTH='S';

    /**
     * Caract�re repr�sentant l'h�misph�re est.
     * Il doit obligatoirement �tre en majuscule.
     */
    private static final char EAST='E';

    /**
     * Caract�re repr�sentant l'h�misph�re ouest.
     * Il doit obligatoirement �tre en majuscule.
     */
    private static final char WEST='W';

    /**
     * Constante indique que l'angle
     * � formater est une longitude.
     */
    static final int LONGITUDE=0;

    /**
     * Constante indique que l'angle
     * � formater est une latitude.
     */
    static final int LATITUDE=1;

    /**
     * Constante indique que le nombre
     * � formater est une altitude.
     */
    static final int ALTITUDE=2;
public static final int HEMISPHERE_FIELD = 3;

/**
 * Symboles représentant les degrés (0),
 * minutes (1) et les secondes (2).
 */
private static final char[] SYMBOLS = {'D', 'M', 'S'};

/**
 * Nombre minimal d'espaces que doivent occuper les parties
 * entières des degrés (0), minutes (1) et secondes (2). Le
 * champs <code>widthDecimal</code> indique la largeur fixe
 * que doit avoir la partie décimale. Il s'appliquera au
 * dernier champs non-zero dans <code>width0..2</code>.
 */
private int width0=1, width1=2, width2=0, widthDecimal=0;

/**
 * Caractères à insérer au début (<code>prefix</code>) et à la
 * suite des degrés, minutes et secondes (<code>suffix0..2</code>).
 * Ces champs doivent être <code>null</code> s'il n'y a rien à insérer.
 */
private String prefix=null, suffix0="\u00B0", suffix1="'", suffix2="\"";

/**
 * Indique s'il faut utiliser le séparateur décimal pour séparer la partie
 * entière de la partie fractionnaire. La valeur <code>false</code> indique
 * que les parties entières et fractionnaires doivent être écrites ensembles
 * (par exemple 34867 pour 34.867). La valeur par défaut est <code>true</code>.
 */
private boolean decimalSeparator=true;

/**
 * Format à utiliser pour écrire les nombres
 * (degrés, minutes ou secondes) à l'intérieur
 * de l'écriture d'un angle.
 */
private final DecimalFormat numberFormat;

/**
 * Objet à transmetre aux méthodes <code>DecimalFormat.format</code>.
 * Ce paramètre existe simplement pour éviter de créer cet objet trop
 * souvent, alors qu'on ne s'y intéresse pas.
 */
private transient FieldPosition dummy = new FieldPosition(0);
public static final int HEMISPHERE_FIELD = 3;

/**
 * Symboles repr�sentant les degr�s (0),
 * minutes (1) et les secondes (2).
 */
private static final char[] SYMBOLS = {'D', 'M', 'S'};

/**
 * Nombre minimal d'espaces que doivent occuper les parties
 * enti�res des degr�s (0), minutes (1) et secondes (2). Le
 * champs <code>widthDecimal</code> indique la largeur fixe
 * que doit avoir la partie d�cimale. Il s'appliquera au
 * dernier champs non-zero dans <code>width0..2</code>.
 */
private int width0=1, width1=2, width2=0, widthDecimal=0;

/**
 * Caract�res � ins�rer au d�but (<code>prefix</code>) et � la
 * suite des degr�s, minutes et secondes (<code>suffix0..2</code>).
 * Ces champs doivent �tre <code>null</code> s'il n'y a rien � ins�rer.
 */
private String prefix=null, suffix0="\u00B0", suffix1="'", suffix2="\"";

/**
 * Indique s'il faut utiliser le s�parateur d�cimal pour s�parer la partie
 * enti�re de la partie fractionnaire. La valeur <code>false</code> indique
 * que les parties enti�res et fractionnaires doivent �tre �crites ensembles
 * (par exemple 34867 pour 34.867). La valeur par d�faut est <code>true</code>.
 */
private boolean decimalSeparator=true;

/**
 * Format � utiliser pour �crire les nombres
 * (degr�s, minutes ou secondes) � l'int�rieur
 * de l'�criture d'un angle.
 */
private final DecimalFormat numberFormat;

/**
 * Objet � transmetre aux m�thodes <code>DecimalFormat.format</code>.
 * Ce param�tre existe simplement pour �viter de cr�er cet objet trop
 * souvent, alors qu'on ne s'y int�resse pas.
 */
private transient FieldPosition dummy = new FieldPosition(0);
 */
public AngleFormat(final String pattern, final DecimalFormatSymbols symbols) {
    // NOTE: pour cette routine, il ne faut PAS que DecimalFormat
    //       reconnaisse la notation exponentielle, parce que ça
    //       risquerait d'être confondu avec le "E" de "Est".
    numberFormat=new DecimalFormat("#0", symbols);
    applyPattern(pattern);
}
 */
public AngleFormat(final String pattern, final DecimalFormatSymbols symbols) {
    // NOTE: pour cette routine, il ne faut PAS que DecimalFormat
    //       reconnaisse la notation exponentielle, parce que �a
    //       risquerait d'�tre confondu avec le "E" de "Est".
    numberFormat=new DecimalFormat("#0", symbols);
    applyPattern(pattern);
}
final int length = pattern.length();
for (int i=0; i<length; i++) {
    /*
     * On examine un à un tous les caractères du patron en
     * sautant ceux qui ne sont pas réservés ("D", "M", "S"
     * et leur équivalents en minuscules). Les caractères
     * non-reservés seront mémorisés comme suffix plus tard.
     */
    final char c = pattern.charAt(i);
    final char upperCaseC = Character.toUpperCase(c);
    for (int field=DEGREES_FIELD; field<SYMBOLS.length; field++) {
        if (upperCaseC == SYMBOLS[field]) {
            /*
             * Un caractère réservé a été trouvé. Vérifie maintenant
             * s'il est valide. Par exemple il serait illegal d'avoir
             * comme patron "MM.mm" sans qu'il soit précédé des degrés.
             * On attend les lettres "D", "M" et "S" dans l'ordre. Si
             * le caractère est en lettres minuscules, il doit être le
             * même que le dernier code (par exemple "DD.mm" est illegal).
             */
            if (c==upperCaseC) {
                symbolIndex++;
final int length = pattern.length();
for (int i=0; i<length; i++) {
    /*
     * On examine un � un tous les caract�res du patron en
     * sautant ceux qui ne sont pas r�serv�s ("D", "M", "S"
     * et leur �quivalents en minuscules). Les caract�res
     * non-reserv�s seront m�moris�s comme suffix plus tard.
     */
    final char c = pattern.charAt(i);
    final char upperCaseC = Character.toUpperCase(c);
    for (int field=DEGREES_FIELD; field<SYMBOLS.length; field++) {
        if (upperCaseC == SYMBOLS[field]) {
            /*
             * Un caract�re r�serv� a �t� trouv�. V�rifie maintenant
             * s'il est valide. Par exemple il serait illegal d'avoir
             * comme patron "MM.mm" sans qu'il soit pr�c�d� des degr�s.
             * On attend les lettres "D", "M" et "S" dans l'ordre. Si
             * le caract�re est en lettres minuscules, il doit �tre le
             * m�me que le dernier code (par exemple "DD.mm" est illegal).
             */
            if (c==upperCaseC) {
                symbolIndex++;
}
if (c==upperCaseC) {
    /*
     * Mémorise les caractères qui précédaient ce code comme suffix
     * du champs précédent. Puis on comptera le nombre de fois que le
     * code se répète, en mémorisant cette information comme largeur
     * de ce champ.
     */
    setSuffix(field-1, (i>startPrefix) ? pattern.substring(startPrefix, i) : null);
}
if (c==upperCaseC) {
    /*
     * M�morise les caract�res qui pr�c�daient ce code comme suffix
     * du champs pr�c�dent. Puis on comptera le nombre de fois que le
     * code se r�p�te, en m�morisant cette information comme largeur
     * de ce champ.
     */
    setSuffix(field-1, (i>startPrefix) ? pattern.substring(startPrefix, i) : null);
    setWidth(field, w);
} else {
    /*
     * Si le caractère est une minuscule, ce qui le précédait sera le
     * séparateur décimal plutôt qu'un suffix. On comptera le nombre
     * d'occurences du caractères pour obtenir la précision.
     */
    switch (i-startPrefix) {
        case 0: decimalSeparator=false; break;
    setWidth(field, w);
} else {
    /*
     * Si le caract�re est une minuscule, ce qui le pr�c�dait sera le
     * s�parateur d�cimal plut�t qu'un suffix. On comptera le nombre
     * d'occurences du caract�res pour obtenir la pr�cision.
     */
    switch (i-startPrefix) {
        case 0: decimalSeparator=false; break;
int w=getWidth(field);
if (w>0) {
    /*
     * Procède à l'écriture de la partie entière des degrés,
     * minutes ou secondes. Le suffix du champs précédent
     * sera écrit avant les degrés, minutes ou secondes.
     */
    if (previousSuffix!=null) {
        buffer.append(previousSuffix);
int w=getWidth(field);
if (w>0) {
    /*
     * Proc�de � l'�criture de la partie enti�re des degr�s,
     * minutes ou secondes. Le suffix du champs pr�c�dent
     * sera �crit avant les degr�s, minutes ou secondes.
     */
    if (previousSuffix!=null) {
        buffer.append(previousSuffix);
    while (--w>0);
} else {
    /*
     * Procède à l'écriture de la partie décimale des
     * degrés, minutes ou secondes. Le suffix du ce
     * champs sera écrit après cette partie fractionnaire.
     */
    w=widthDecimal;
    if (w>0) {
    while (--w>0);
} else {
    /*
     * Proc�de � l'�criture de la partie d�cimale des
     * degr�s, minutes ou secondes. Le suffix du ce
     * champs sera �crit apr�s cette partie fractionnaire.
     */
    w=widthDecimal;
    if (w>0) {
{
    double degrees = angle;
    /*
     * Calcule à l'avance les minutes et les secondes. Si les minutes et secondes
     * ne doivent pas être écrits, on mémorisera NaN. Notez que pour extraire les
     * parties entières, on utilise (int) au lieu de 'Math.floor' car (int) arrondie
     * vers 0 (ce qui est le comportement souhaité) alors que 'floor' arrondie vers
     * l'entier inférieur.
     */
    double minutes  = Double.NaN;
    double secondes = Double.NaN;
    if (width1!=0 && !Double.isNaN(angle)) {
        int tmp = (int) degrees; // Arrondie vers 0 même si négatif.
        minutes = Math.abs(degrees-tmp)*60;
        degrees = tmp;
        if (minutes<0 || minutes>60) {
            // Erreur d'arrondissement (parce que l'angle est trop élevé)
            throw new IllegalArgumentException(Resources.format(ResourceKeys.ERROR_ANGLE_OVERFLOW_$1, new Double(angle)));
        }
        if (width2 != 0) {
            tmp      = (int) minutes; // Arrondie vers 0 même si négatif.
            secondes = (minutes-tmp)*60;
            minutes  = tmp;
            if (secondes<0 || secondes>60) {
                // Erreur d'arrondissement (parce que l'angle est trop élevé)
                throw new IllegalArgumentException(Resources.format(ResourceKeys.ERROR_ANGLE_OVERFLOW_$1, new Double(angle)));
            }
            /*
             * On applique maintenant une correction qui tiendra
             * compte des problèmes d'arrondissements.
             */
            final double puissance=XMath.pow10(widthDecimal);
            secondes=Math.rint(secondes*puissance)/puissance;
{
    double degrees = angle;
    /*
     * Calcule � l'avance les minutes et les secondes. Si les minutes et secondes
     * ne doivent pas �tre �crits, on m�morisera NaN. Notez que pour extraire les
     * parties enti�res, on utilise (int) au lieu de 'Math.floor' car (int) arrondie
     * vers 0 (ce qui est le comportement souhait�) alors que 'floor' arrondie vers
     * l'entier inf�rieur.
     */
    double minutes  = Double.NaN;
    double secondes = Double.NaN;
    if (width1!=0 && !Double.isNaN(angle)) {
        int tmp = (int) degrees; // Arrondie vers 0 m�me si n�gatif.
        minutes = Math.abs(degrees-tmp)*60;
        degrees = tmp;
        if (minutes<0 || minutes>60) {
            // Erreur d'arrondissement (parce que l'angle est trop �lev�)
            throw new IllegalArgumentException(Resources.format(ResourceKeys.ERROR_ANGLE_OVERFLOW_$1, new Double(angle)));
        }
        if (width2 != 0) {
            tmp      = (int) minutes; // Arrondie vers 0 m�me si n�gatif.
            secondes = (minutes-tmp)*60;
            minutes  = tmp;
            if (secondes<0 || secondes>60) {
                // Erreur d'arrondissement (parce que l'angle est trop �lev�)
                throw new IllegalArgumentException(Resources.format(ResourceKeys.ERROR_ANGLE_OVERFLOW_$1, new Double(angle)));
            }
            /*
             * On applique maintenant une correction qui tiendra
             * compte des probl�mes d'arrondissements.
             */
            final double puissance=XMath.pow10(widthDecimal);
            secondes=Math.rint(secondes*puissance)/puissance;
        final double puissance=XMath.pow10(widthDecimal);
        minutes = Math.rint(minutes*puissance)/puissance;
    }
    tmp = (int) (minutes/60); // Arrondie vers 0 même si négatif.
    minutes -= 60*tmp;
    degrees += tmp;
}
/*
 * Les variables 'degrés', 'minutes' et 'secondes' contiennent
 * maintenant les valeurs des champs à écrire, en principe épurés
 * des problèmes d'arrondissements. Procède maintenant à l'écriture
 * de l'angle.
 */
if (prefix != null) {
        final double puissance=XMath.pow10(widthDecimal);
        minutes = Math.rint(minutes*puissance)/puissance;
    }
    tmp = (int) (minutes/60); // Arrondie vers 0 m�me si n�gatif.
    minutes -= 60*tmp;
    degrees += tmp;
}
/*
 * Les variables 'degr�s', 'minutes' et 'secondes' contiennent
 * maintenant les valeurs des champs � �crire, en principe �pur�s
 * des probl�mes d'arrondissements. Proc�de maintenant � l'�criture
 * de l'angle.
 */
if (prefix != null) {
}

/**
 * Procède à l'écriture d'un champ de l'angle.
 *
 * @param value Valeur à écrire.
 * @param toAppendTo Buffer dans lequel écrire le champs.
 * @param pos Objet dans lequel mémoriser les index des premiers
 *        et derniers caractères écrits, ou <code>null</code>
 *        pour ne pas mémoriser ces index.
 * @param w Nombre de minimal caractères de la partie entière.
 * @param last <code>true</code> si ce champs est le dernier,
 *        et qu'il faut donc écrire la partie décimale.
 * @param s Suffix à écrire après le nombre (peut être nul).
 */
private StringBuffer formatField(double value,
                                 StringBuffer toAppendTo, final FieldPosition pos,
}

/**
 * Proc�de � l'�criture d'un champ de l'angle.
 *
 * @param value Valeur � �crire.
 * @param toAppendTo Buffer dans lequel �crire le champs.
 * @param pos Objet dans lequel m�moriser les index des premiers
 *        et derniers caract�res �crits, ou <code>null</code>
 *        pour ne pas m�moriser ces index.
 * @param w Nombre de minimal caract�res de la partie enti�re.
 * @param last <code>true</code> si ce champs est le dernier,
 *        et qu'il faut donc �crire la partie d�cimale.
 * @param s Suffix � �crire apr�s le nombre (peut �tre nul).
 */
private StringBuffer formatField(double value,
                                 StringBuffer toAppendTo, final FieldPosition pos,
}

/**
 * Procède à l'écriture d'un angle, d'une latitude ou d'une longitude.
 *
 * @param  angle      Angle ou nombre à écrire.
 * @param  type       Type de l'angle ou du nombre:
 *                    {@link #LONGITUDE},
 *                    {@link #LATITUDE} ou
 *                    {@link #ALTITUDE}.
 * @param  toAppendTo Buffer dans lequel écrire l'angle.
 * @param  pos        En entré, le code du champs dont on désire les index
 *                    ({@link #DEGREES_FIELD},
 *                     {@link #MINUTES_FIELD},
 *                     {@link #SECONDS_FIELD} ou
 *                     {@link #HEMISPHERE_FIELD}).
 *                    En sortie, les index du champs demandé. Ce paramètre
 *                    peut être nul si cette information n'est pas désirée.
 *
 * @return Le buffer <code>toAppendTo</code> par commodité.
 */
synchronized StringBuffer format(final double number, final int type,
                                 StringBuffer toAppendTo,
}

/**
 * Proc�de � l'�criture d'un angle, d'une latitude ou d'une longitude.
 *
 * @param  angle      Angle ou nombre � �crire.
 * @param  type       Type de l'angle ou du nombre:
 *                    {@link #LONGITUDE},
 *                    {@link #LATITUDE} ou
 *                    {@link #ALTITUDE}.
 * @param  toAppendTo Buffer dans lequel �crire l'angle.
 * @param  pos        En entr�, le code du champs dont on d�sire les index
 *                    ({@link #DEGREES_FIELD},
 *                     {@link #MINUTES_FIELD},
 *                     {@link #SECONDS_FIELD} ou
 *                     {@link #HEMISPHERE_FIELD}).
 *                    En sortie, les index du champs demand�. Ce param�tre
 *                    peut �tre nul si cette information n'est pas d�sir�e.
 *
 * @return Le buffer <code>toAppendTo</code> par commodit�.
 */
synchronized StringBuffer format(final double number, final int type,
                                 StringBuffer toAppendTo,
}

/**
 * Procède à l'écriture d'un angle suivit d'un suffix 'N','S','E' ou 'W'.
 * L'angle sera formaté en utilisant comme modèle le patron spécifié lors
 * du dernier appel de la méthode {@link #applyPattern}.
 *
 * @param  angle      Angle à écrire, en degrés.
 * @param  toAppendTo Buffer dans lequel écrire l'angle.
 * @param  pos        En entré, le code du champs dont on désire les index
 *                    ({@link #DEGREES_FIELD},
 *                     {@link #MINUTES_FIELD},
 *                     {@link #SECONDS_FIELD} ou
 *                     {@link #HEMISPHERE_FIELD}).
 *                    En sortie, les index du champs demandé. Ce paramètre
 *                    peut être nul si cette information n'est pas désirée.
 * @param north       Caractères à écrire si l'angle est positif ou nul.
 * @param south       Caractères à écrire si l'angle est négatif.
 *
 * @return Le buffer <code>toAppendTo</code> par commodité.
 */
private StringBuffer format(final double angle,
                            StringBuffer toAppendTo,
}

/**
 * Proc�de � l'�criture d'un angle suivit d'un suffix 'N','S','E' ou 'W'.
 * L'angle sera format� en utilisant comme mod�le le patron sp�cifi� lors
 * du dernier appel de la m�thode {@link #applyPattern}.
 *
 * @param  angle      Angle � �crire, en degr�s.
 * @param  toAppendTo Buffer dans lequel �crire l'angle.
 * @param  pos        En entr�, le code du champs dont on d�sire les index
 *                    ({@link #DEGREES_FIELD},
 *                     {@link #MINUTES_FIELD},
 *                     {@link #SECONDS_FIELD} ou
 *                     {@link #HEMISPHERE_FIELD}).
 *                    En sortie, les index du champs demand�. Ce param�tre
 *                    peut �tre nul si cette information n'est pas d�sir�e.
 * @param north       Caract�res � �crire si l'angle est positif ou nul.
 * @param south       Caract�res � �crire si l'angle est n�gatif.
 *
 * @return Le buffer <code>toAppendTo</code> par commodit�.
 */
private StringBuffer format(final double angle,
                            StringBuffer toAppendTo,
}

/**
 * Ignore le suffix d'un nombre. Cette méthode est appellée par la méthode
 * {@link #parse} pour savoir quel champs il vient de lire. Par exemple si
 * l'on vient de lire les degrés dans "48°12'", alors cette méthode extraira
 * le "°" et retournera 0 pour indiquer que l'on vient de lire des degrés.
 *
 * Cette méthode se chargera d'ignorer les espaces qui précèdent le suffix.
 * Elle tentera ensuite de d'abord interpréter le suffix selon les symboles
 * du patron (spécifié avec {@link #applyPattern}. Si le suffix n'a pas été
 * reconnus, elle tentera ensuite de le comparer aux symboles standards
 * (° ' ").
 *
 * @param  source Chaîne dans laquelle on doit sauter le suffix.
 * @param  pos En entré, l'index du premier caractère à considérer dans la
 *         chaîne <code>pos</code>. En sortie, l'index du premier caractère
 *         suivant le suffix (c'est-à-dire index à partir d'où continuer la
 *         lecture après l'appel de cette méthode). Si le suffix n'a pas été
 *         reconnu, alors cette méthode retourne par convention <code>SYMBOLS.length</code>.
 * @param  field Champs à vérifier de préférences. Par exemple la valeur 1 signifie que les
 *         suffix des minutes et des secondes devront être vérifiés avant celui des degrés.
 * @return Le numéro du champs correspondant au suffix qui vient d'être extrait:
 *         -1 pour le préfix de l'angle, 0 pour le suffix des degrés, 1 pour le
 *         suffix des minutes et 2 pour le suffix des secondes. Si le texte n'a
 *         pas été reconnu, retourne <code>SYMBOLS.length</code>.
 */
private int skipSuffix(final String source, final ParsePosition pos, int field) {
    /*
     * Essaie d'abord de sauter les suffix qui
     * avaient été spécifiés dans le patron.
     */
    final int length=source.length();
    int start=pos.getIndex();
}

/**
 * Ignore le suffix d'un nombre. Cette m�thode est appell�e par la m�thode
 * {@link #parse} pour savoir quel champs il vient de lire. Par exemple si
 * l'on vient de lire les degr�s dans "48�12'", alors cette m�thode extraira
 * le "�" et retournera 0 pour indiquer que l'on vient de lire des degr�s.
 *
 * Cette m�thode se chargera d'ignorer les espaces qui pr�c�dent le suffix.
 * Elle tentera ensuite de d'abord interpr�ter le suffix selon les symboles
 * du patron (sp�cifi� avec {@link #applyPattern}. Si le suffix n'a pas �t�
 * reconnus, elle tentera ensuite de le comparer aux symboles standards
 * (� ' ").
 *
 * @param  source Cha�ne dans laquelle on doit sauter le suffix.
 * @param  pos En entr�, l'index du premier caract�re � consid�rer dans la
 *         cha�ne <code>pos</code>. En sortie, l'index du premier caract�re
 *         suivant le suffix (c'est-�-dire index � partir d'o� continuer la
 *         lecture apr�s l'appel de cette m�thode). Si le suffix n'a pas �t�
 *         reconnu, alors cette m�thode retourne par convention <code>SYMBOLS.length</code>.
 * @param  field Champs � v�rifier de pr�f�rences. Par exemple la valeur 1 signifie que les
 *         suffix des minutes et des secondes devront �tre v�rifi�s avant celui des degr�s.
 * @return Le num�ro du champs correspondant au suffix qui vient d'�tre extrait:
 *         -1 pour le pr�fix de l'angle, 0 pour le suffix des degr�s, 1 pour le
 *         suffix des minutes et 2 pour le suffix des secondes. Si le texte n'a
 *         pas �t� reconnu, retourne <code>SYMBOLS.length</code>.
 */
private int skipSuffix(final String source, final ParsePosition pos, int field) {
    /*
     * Essaie d'abord de sauter les suffix qui
     * avaient �t� sp�cifi�s dans le patron.
     */
    final int length=source.length();
    int start=pos.getIndex();
    if (++field >= SYMBOLS.length) field=-1;
}
/*
 * Le texte trouvé ne correspondant à aucun suffix du patron,
 * essaie maintenant de sauter un des suffix standards (après
 * avoir ignoré les espaces qui le précédaient).
 */
char c;
do {
    if (++field >= SYMBOLS.length) field=-1;
}
/*
 * Le texte trouv� ne correspondant � aucun suffix du patron,
 * essaie maintenant de sauter un des suffix standards (apr�s
 * avoir ignor� les espaces qui le pr�c�daient).
 */
char c;
do {
/**
 * Parse a string as an angle. This method can parse an angle even if it
 * doesn't comply exactly to the expected pattern. For example, this method
 * will parse correctly string "<code>48°12.34'</code>" even if the expected
 * pattern was "<code>DDMM.mm</code>" (i.e. the string should have been
 * "<code>4812.34</code>"). Spaces between degrees, minutes and secondes
 * are ignored. If the string ends with an hemisphere symbol "N" or "S",
/**
 * Parse a string as an angle. This method can parse an angle even if it
 * doesn't comply exactly to the expected pattern. For example, this method
 * will parse correctly string "<code>48�12.34'</code>" even if the expected
 * pattern was "<code>DDMM.mm</code>" (i.e. the string should have been
 * "<code>4812.34</code>"). Spaces between degrees, minutes and secondes
 * are ignored. If the string ends with an hemisphere symbol "N" or "S",
}

/**
 * Interprète une chaîne de caractères représentant un angle. Les règles
 * d'interprétation de cette méthode sont assez souples. Par exemple cettte
 * méthode interprétera correctement la chaîne "48°12.34'" même si le patron
 * attendu était "DDMM.mm" (c'est-à-dire que la chaîne aurait du être "4812.34").
 * Les espaces entre les degrés, minutes et secondes sont acceptés. Si l'angle
 * est suivit d'un symbole "N" ou "S", alors l'objet retourné sera de la classe
 * {@link Latitude}. S'il est plutot suivit d'un symbole "E" ou "W", alors l'objet
 * retourné sera de la classe {@link Longitude}. Sinon, il sera de la classe
 * {@link Angle}.
 *
 * @param source           Chaîne de caractères à lire.
 * @param pos              Position à partir d'où interpréter la chaîne.
 * @param spaceAsSeparator Indique si l'espace est accepté comme séparateur
 *                         à l'intérieur d'un angle. La valeur <code>true</code>
 *                         fait que l'angle "45 30" sera interprété comme "45°30".
 * @return L'angle lu.
 */
private synchronized Angle parse(final String source,
}

/**
 * Interpr�te une cha�ne de caract�res repr�sentant un angle. Les r�gles
 * d'interpr�tation de cette m�thode sont assez souples. Par exemple cettte
 * m�thode interpr�tera correctement la cha�ne "48�12.34'" m�me si le patron
 * attendu �tait "DDMM.mm" (c'est-�-dire que la cha�ne aurait du �tre "4812.34").
 * Les espaces entre les degr�s, minutes et secondes sont accept�s. Si l'angle
 * est suivit d'un symbole "N" ou "S", alors l'objet retourn� sera de la classe
 * {@link Latitude}. S'il est plutot suivit d'un symbole "E" ou "W", alors l'objet
 * retourn� sera de la classe {@link Longitude}. Sinon, il sera de la classe
 * {@link Angle}.
 *
 * @param source           Cha�ne de caract�res � lire.
 * @param pos              Position � partir d'o� interpr�ter la cha�ne.
 * @param spaceAsSeparator Indique si l'espace est accept� comme s�parateur
 *                         � l'int�rieur d'un angle. La valeur <code>true</code>
 *                         fait que l'angle "45 30" sera interpr�t� comme "45�30".
 * @return L'angle lu.
 */
private synchronized Angle parse(final String source,
double secondes = Double.NaN;
final int length=source.length();
///////////////////////////////////////////////////////////////////////////////
// BLOC A: Analyse la chaîne de caractères 'source' et affecte aux variables //
//         'degrés', 'minutes' et 'secondes' les valeurs appropriées.        //
//         Les premières accolades ne servent qu'à garder locales            //
//         les variables sans intérêt une fois la lecture terminée.          //
///////////////////////////////////////////////////////////////////////////////
{
    /*
     * Extrait le préfix, s'il y en avait un. Si on tombe sur un symbole des
     * degrés, minutes ou secondes alors qu'on n'a pas encore lu de nombre,
     * on considèrera que la lecture a échouée.
     */
    final int indexStart=pos.getIndex();
    int index=skipSuffix(source, pos, PREFIX_FIELD);
double secondes = Double.NaN;
final int length=source.length();
///////////////////////////////////////////////////////////////////////////////
// BLOC A: Analyse la cha�ne de caract�res 'source' et affecte aux variables //
//         'degr�s', 'minutes' et 'secondes' les valeurs appropri�es.        //
//         Les premi�res accolades ne servent qu'� garder locales            //
//         les variables sans int�r�t une fois la lecture termin�e.          //
///////////////////////////////////////////////////////////////////////////////
{
    /*
     * Extrait le pr�fix, s'il y en avait un. Si on tombe sur un symbole des
     * degr�s, minutes ou secondes alors qu'on n'a pas encore lu de nombre,
     * on consid�rera que la lecture a �chou�e.
     */
    final int indexStart=pos.getIndex();
    int index=skipSuffix(source, pos, PREFIX_FIELD);
}
/*
 * Saute les espaces blancs qui
 * précèdent le champs des degrés.
 */
index=pos.getIndex();
while (index<length && Character.isSpaceChar(source.charAt(index))) index++;
pos.setIndex(index);
/*
 * Lit les degrés. Notez que si aucun séparateur ne séparait les degrés
 * des minutes des secondes, alors cette lecture pourra inclure plusieurs
 * champs (exemple: "DDDMMmmm"). La séparation sera faite plus tard.
 */
Number fieldObject=numberFormat.parse(source, pos);
if (fieldObject==null) {
}
/*
 * Saute les espaces blancs qui
 * pr�c�dent le champs des degr�s.
 */
index=pos.getIndex();
while (index<length && Character.isSpaceChar(source.charAt(index))) index++;
pos.setIndex(index);
/*
 * Lit les degr�s. Notez que si aucun s�parateur ne s�parait les degr�s
 * des minutes des secondes, alors cette lecture pourra inclure plusieurs
 * champs (exemple: "DDDMMmmm"). La s�paration sera faite plus tard.
 */
Number fieldObject=numberFormat.parse(source, pos);
if (fieldObject==null) {
            boolean swapDM=true;
BigBoss:    switch (skipSuffix(source, pos, DEGREES_FIELD)) {
                /* ----------------------------------------------
                 * ANALYSE DU SYMBOLE SUIVANT LES PRÉSUMÉS DEGRÉS
                 * ----------------------------------------------
                 * Les degrés étaient suivit du préfix d'un autre angle. Le préfix sera donc
                 * retourné dans le buffer pour un éventuel traitement par le prochain appel
                 * à la méthode 'parse' et on n'ira pas plus loin dans l'analyse de la chaîne.
                 */
                case PREFIX_FIELD: {
                    pos.setIndex(indexEndField);
                    break BigBoss;
                }
                /* ----------------------------------------------
                 * ANALYSE DU SYMBOLE SUIVANT LES PRÉSUMÉS DEGRÉS
                 * ----------------------------------------------
                 * On a trouvé le symbole des secondes au lieu de celui des degrés. On fait
                 * la correction dans les variables 'degrés' et 'secondes' et on considère
                 * que la lecture est terminée.
                 */
                case SECONDS_FIELD: {
                    secondes = degrees;
            boolean swapDM=true;
BigBoss:    switch (skipSuffix(source, pos, DEGREES_FIELD)) {
                /* ----------------------------------------------
                 * ANALYSE DU SYMBOLE SUIVANT LES PR�SUM�S DEGR�S
                 * ----------------------------------------------
                 * Les degr�s �taient suivit du pr�fix d'un autre angle. Le pr�fix sera donc
                 * retourn� dans le buffer pour un �ventuel traitement par le prochain appel
                 * � la m�thode 'parse' et on n'ira pas plus loin dans l'analyse de la cha�ne.
                 */
                case PREFIX_FIELD: {
                    pos.setIndex(indexEndField);
                    break BigBoss;
                }
                /* ----------------------------------------------
                 * ANALYSE DU SYMBOLE SUIVANT LES PR�SUM�S DEGR�S
                 * ----------------------------------------------
                 * On a trouv� le symbole des secondes au lieu de celui des degr�s. On fait
                 * la correction dans les variables 'degr�s' et 'secondes' et on consid�re
                 * que la lecture est termin�e.
                 */
                case SECONDS_FIELD: {
                    secondes = degrees;
    break BigBoss;
}
/* ----------------------------------------------
 * ANALYSE DU SYMBOLE SUIVANT LES PRÉSUMÉS DEGRÉS
 * ----------------------------------------------
 * Aucun symbole ne suit les degrés. Des minutes sont-elles attendues?
 * Si oui, on fera comme si le symbole des degrés avait été là. Sinon,
 * on considèrera que la lecture est terminée.
 */
default: {
    if (width1==0)         break BigBoss;
    break BigBoss;
}
/* ----------------------------------------------
 * ANALYSE DU SYMBOLE SUIVANT LES PR�SUM�S DEGR�S
 * ----------------------------------------------
 * Aucun symbole ne suit les degr�s. Des minutes sont-elles attendues?
 * Si oui, on fera comme si le symbole des degr�s avait �t� l�. Sinon,
 * on consid�rera que la lecture est termin�e.
 */
default: {
    if (width1==0)         break BigBoss;
    // fall through
}
/* ----------------------------------------------
 * ANALYSE DU SYMBOLE SUIVANT LES PRÉSUMÉS DEGRÉS
 * ----------------------------------------------
 * Un symbole des degrés a été explicitement trouvé. Les degrés sont peut-être
 * suivit des minutes. On procèdera donc à la lecture du prochain nombre, puis
 * à l'analyse du symbole qui le suit.
 */
case DEGREES_FIELD: {
    final int indexStartField = index = pos.getIndex();
    // fall through
}
/* ----------------------------------------------
 * ANALYSE DU SYMBOLE SUIVANT LES PR�SUM�S DEGR�S
 * ----------------------------------------------
 * Un symbole des degr�s a �t� explicitement trouv�. Les degr�s sont peut-�tre
 * suivit des minutes. On proc�dera donc � la lecture du prochain nombre, puis
 * � l'analyse du symbole qui le suit.
 */
case DEGREES_FIELD: {
    final int indexStartField = index = pos.getIndex();
minutes = fieldObject.doubleValue();
switch (skipSuffix(source, pos, (width1!=0) ? MINUTES_FIELD : PREFIX_FIELD)) {
    /* ------------------------------------------------
     * ANALYSE DU SYMBOLE SUIVANT LES PRÉSUMÉES MINUTES
     * ------------------------------------------------
     * Le symbole trouvé est bel et bien celui des minutes.
     * On continuera le bloc pour tenter de lire les secondes.
     */
    case MINUTES_FIELD: {
        break; // continue outer switch
    }
    /* ------------------------------------------------
     * ANALYSE DU SYMBOLE SUIVANT LES PRÉSUMÉES MINUTES
     * ------------------------------------------------
     * Un symbole des secondes a été trouvé au lieu du symbole des minutes
     * attendu. On fera la modification dans les variables 'secondes' et
     * 'minutes' et on considèrera la lecture terminée.
     */
    case SECONDS_FIELD: {
        secondes = minutes;
minutes = fieldObject.doubleValue();
switch (skipSuffix(source, pos, (width1!=0) ? MINUTES_FIELD : PREFIX_FIELD)) {
    /* ------------------------------------------------
     * ANALYSE DU SYMBOLE SUIVANT LES PR�SUM�ES MINUTES
     * ------------------------------------------------
     * Le symbole trouv� est bel et bien celui des minutes.
     * On continuera le bloc pour tenter de lire les secondes.
     */
    case MINUTES_FIELD: {
        break; // continue outer switch
    }
    /* ------------------------------------------------
     * ANALYSE DU SYMBOLE SUIVANT LES PR�SUM�ES MINUTES
     * ------------------------------------------------
     * Un symbole des secondes a �t� trouv� au lieu du symbole des minutes
     * attendu. On fera la modification dans les variables 'secondes' et
     * 'minutes' et on consid�rera la lecture termin�e.
     */
    case SECONDS_FIELD: {
        secondes = minutes;
    break BigBoss;
}
/* ------------------------------------------------
 * ANALYSE DU SYMBOLE SUIVANT LES PRÉSUMÉES MINUTES
 * ------------------------------------------------
 * Aucun symbole n'a été trouvé. Les minutes étaient-elles attendues?
 * Si oui, on les acceptera et on tentera de lire les secondes. Si non,
 * on retourne le texte lu dans le buffer et on termine la lecture.
 */
    break BigBoss;
}
/* ------------------------------------------------
 * ANALYSE DU SYMBOLE SUIVANT LES PR�SUM�ES MINUTES
 * ------------------------------------------------
 * Aucun symbole n'a �t� trouv�. Les minutes �taient-elles attendues?
 * Si oui, on les acceptera et on tentera de lire les secondes. Si non,
 * on retourne le texte lu dans le buffer et on termine la lecture.
 */
    // fall through
}
/* ------------------------------------------------
 * ANALYSE DU SYMBOLE SUIVANT LES PRÉSUMÉES MINUTES
 * ------------------------------------------------
 * Au lieu des minutes, le symbole lu est celui des degrés. On considère
 * qu'il appartient au prochain angle. On retournera donc le texte lu dans
 * le buffer et on terminera la lecture.
 */
    // fall through
}
/* ------------------------------------------------
 * ANALYSE DU SYMBOLE SUIVANT LES PR�SUM�ES MINUTES
 * ------------------------------------------------
 * Au lieu des minutes, le symbole lu est celui des degr�s. On consid�re
 * qu'il appartient au prochain angle. On retournera donc le texte lu dans
 * le buffer et on terminera la lecture.
 */
    break BigBoss;
}
/* ------------------------------------------------
 * ANALYSE DU SYMBOLE SUIVANT LES PRÉSUMÉES MINUTES
 * ------------------------------------------------
 * Après les minutes (qu'on accepte), on a trouvé le préfix du prochain
 * angle à lire. On retourne ce préfix dans le buffer et on considère la
 * lecture terminée.
 */
case PREFIX_FIELD: {
    pos.setIndex(indexEndField);
    break BigBoss;
}
/* ------------------------------------------------
 * ANALYSE DU SYMBOLE SUIVANT LES PR�SUM�ES MINUTES
 * ------------------------------------------------
 * Apr�s les minutes (qu'on accepte), on a trouv� le pr�fix du prochain
 * angle � lire. On retourne ce pr�fix dans le buffer et on consid�re la
 * lecture termin�e.
 */
case PREFIX_FIELD: {
    pos.setIndex(indexEndField);
    // fall through
}
/* ----------------------------------------------
 * ANALYSE DU SYMBOLE SUIVANT LES PRÉSUMÉS DEGRÉS
 * ----------------------------------------------
 * Un symbole des minutes a été trouvé au lieu du symbole des degrés attendu.
 * On fera donc la modification dans les variables 'degrés' et 'minutes'. Ces
 * minutes sont peut-être suivies des secondes. On tentera donc de lire le
 * prochain nombre.
 */
case MINUTES_FIELD: {
    // fall through
}
/* ----------------------------------------------
 * ANALYSE DU SYMBOLE SUIVANT LES PR�SUM�S DEGR�S
 * ----------------------------------------------
 * Un symbole des minutes a �t� trouv� au lieu du symbole des degr�s attendu.
 * On fera donc la modification dans les variables 'degr�s' et 'minutes'. Ces
 * minutes sont peut-�tre suivies des secondes. On tentera donc de lire le
 * prochain nombre.
 */
case MINUTES_FIELD: {
secondes = fieldObject.doubleValue();
switch (skipSuffix(source, pos, (width2!=0) ? MINUTES_FIELD : PREFIX_FIELD)) {
    /* -------------------------------------------------
     * ANALYSE DU SYMBOLE SUIVANT LES PRÉSUMÉES SECONDES
     * -------------------------------------------------
     * Un symbole des secondes explicite a été trouvée.
     * La lecture est donc terminée.
     */
    case SECONDS_FIELD: {
        break;
    }
    /* -------------------------------------------------
     * ANALYSE DU SYMBOLE SUIVANT LES PRÉSUMÉES SECONDES
     * -------------------------------------------------
     * Aucun symbole n'a été trouvée. Attendait-on des secondes? Si oui, les
     * secondes seront acceptées. Sinon, elles seront retournées au buffer.
     */
    default: {
        if (width2!=0) break;
        // fall through
    }
    /* -------------------------------------------------
     * ANALYSE DU SYMBOLE SUIVANT LES PRÉSUMÉES SECONDES
     * -------------------------------------------------
     * Au lieu des degrés, on a trouvé un symbole des minutes ou des
     * secondes. On renvoie donc le nombre et son symbole dans le buffer.
     */
    case MINUTES_FIELD:
secondes = fieldObject.doubleValue();
switch (skipSuffix(source, pos, (width2!=0) ? MINUTES_FIELD : PREFIX_FIELD)) {
    /* -------------------------------------------------
     * ANALYSE DU SYMBOLE SUIVANT LES PR�SUM�ES SECONDES
     * -------------------------------------------------
     * Un symbole des secondes explicite a �t� trouv�e.
     * La lecture est donc termin�e.
     */
    case SECONDS_FIELD: {
        break;
    }
    /* -------------------------------------------------
     * ANALYSE DU SYMBOLE SUIVANT LES PR�SUM�ES SECONDES
     * -------------------------------------------------
     * Aucun symbole n'a �t� trouv�e. Attendait-on des secondes? Si oui, les
     * secondes seront accept�es. Sinon, elles seront retourn�es au buffer.
     */
    default: {
        if (width2!=0) break;
        // fall through
    }
    /* -------------------------------------------------
     * ANALYSE DU SYMBOLE SUIVANT LES PR�SUM�ES SECONDES
     * -------------------------------------------------
     * Au lieu des degr�s, on a trouv� un symbole des minutes ou des
     * secondes. On renvoie donc le nombre et son symbole dans le buffer.
     */
    case MINUTES_FIELD:
    break;
}
/* -------------------------------------------------
 * ANALYSE DU SYMBOLE SUIVANT LES PRÉSUMÉES SECONDES
 * -------------------------------------------------
 * Après les secondes (qu'on accepte), on a trouvé le préfix du prochain
 * angle à lire. On retourne ce préfix dans le buffer et on considère la
 * lecture terminée.
 */
case PREFIX_FIELD: {
    pos.setIndex(indexEndField);
    break;
}
/* -------------------------------------------------
 * ANALYSE DU SYMBOLE SUIVANT LES PR�SUM�ES SECONDES
 * -------------------------------------------------
 * Apr�s les secondes (qu'on accepte), on a trouv� le pr�fix du prochain
 * angle � lire. On retourne ce pr�fix dans le buffer et on consid�re la
 * lecture termin�e.
 */
case PREFIX_FIELD: {
    pos.setIndex(indexEndField);
    }
}
////////////////////////////////////////////////////////////////////
// BLOC B: Prend en compte l'éventualité ou le séparateur décimal //
//         aurrait été absent, puis calcule l'angle en degrés.    //
////////////////////////////////////////////////////////////////////
if (minutes<0) {
    secondes = -secondes;
    }
}
////////////////////////////////////////////////////////////////////
// BLOC B: Prend en compte l'�ventualit� ou le s�parateur d�cimal //
//         aurrait �t� absent, puis calcule l'angle en degr�s.    //
////////////////////////////////////////////////////////////////////
if (minutes<0) {
    secondes = -secondes;
    }
}
/*
 * S'il n'y a rien qui permet de séparer les degrés des minutes (par exemple si
 * le patron est "DDDMMmmm"), alors la variable 'degrés' englobe à la fois les
 * degrés, les minutes et d'éventuelles secondes. On applique une correction ici.
 */
if (suffix1==null && width2!=0 && Double.isNaN(secondes)) {
    double facteur = XMath.pow10(width2);
    }
}
/*
 * S'il n'y a rien qui permet de s�parer les degr�s des minutes (par exemple si
 * le patron est "DDDMMmmm"), alors la variable 'degr�s' englobe � la fois les
 * degr�s, les minutes et d'�ventuelles secondes. On applique une correction ici.
 */
if (suffix1==null && width2!=0 && Double.isNaN(secondes)) {
    double facteur = XMath.pow10(width2);
    minutes -= degrees*facteur;
} else {
    ////////////////////
    //// DDD°MMSS.s ////
    ////////////////////
    secondes = minutes;
    minutes = (int) (minutes/facteur); // Arrondie vers 0
    minutes -= degrees*facteur;
} else {
    ////////////////////
    //// DDD�MMSS.s ////
    ////////////////////
    secondes = minutes;
    minutes = (int) (minutes/facteur); // Arrondie vers 0
if (!Double.isNaN(minutes))  degrees += minutes/60;
if (!Double.isNaN(secondes)) degrees += secondes/3600;
/////////////////////////////////////////////////////
// BLOC C: Vérifie maintenant si l'angle ne serait //
//         pas suivit d'un symbole N, S, E ou W.   //
/////////////////////////////////////////////////////
for (int index=pos.getIndex(); index<length; index++) {
if (!Double.isNaN(minutes))  degrees += minutes/60;
if (!Double.isNaN(secondes)) degrees += secondes/3600;
/////////////////////////////////////////////////////
// BLOC C: V�rifie maintenant si l'angle ne serait //
//         pas suivit d'un symbole N, S, E ou W.   //
/////////////////////////////////////////////////////
for (int index=pos.getIndex(); index<length; index++) {
}

/**
 * Interprète une chaîne de caractères qui devrait représenter un nombre.
 * Cette méthode est utile pour lire une altitude après les angles.
 *
 * @param  source Chaîne de caractères à interpréter.
 * @param  pos    Position à partir d'où commencer l'interprétation
 *                de la chaîne <code>source</code>.
 * @return Le nombre lu comme objet {@link Number}.
 */
final Number parseNumber(final String source, final ParsePosition pos) {
}

/**
 * Interpr�te une cha�ne de caract�res qui devrait repr�senter un nombre.
 * Cette m�thode est utile pour lire une altitude apr�s les angles.
 *
 * @param  source Cha�ne de caract�res � interpr�ter.
 * @param  pos    Position � partir d'o� commencer l'interpr�tation
 *                de la cha�ne <code>source</code>.
 * @return Le nombre lu comme objet {@link Number}.
 */
final Number parseNumber(final String source, final ParsePosition pos) {
}

/**
 * Vérifie si l'interprétation d'une chaîne de caractères a été complète.
 * Si ce n'était pas le cas, lance une exception avec un message d'erreur
 * soulignant les caractères problématiques.
 *
 * @param  source Chaîne de caractères qui était à interpréter.
 * @param  pos Position à laquelle s'est terminée l'interprétation de la
 *         chaîne <code>source</code>.
 * @param  isCoordinate <code>false</code> si on interprétait un angle,
 *         ou <code>true</code> si on interprétait une coordonnée.
 * @throws ParseException Si la chaîne <code>source</code> n'a pas été
 *         interprétée dans sa totalité.
 */
static void checkComplete(final String source,
                          final ParsePosition pos,
}

/**
 * V�rifie si l'interpr�tation d'une cha�ne de caract�res a �t� compl�te.
 * Si ce n'�tait pas le cas, lance une exception avec un message d'erreur
 * soulignant les caract�res probl�matiques.
 *
 * @param  source Cha�ne de caract�res qui �tait � interpr�ter.
 * @param  pos Position � laquelle s'est termin�e l'interpr�tation de la
 *         cha�ne <code>source</code>.
 * @param  isCoordinate <code>false</code> si on interpr�tait un angle,
 *         ou <code>true</code> si on interpr�tait une coordonn�e.
 * @throws ParseException Si la cha�ne <code>source</code> n'a pas �t�
 *         interpr�t�e dans sa totalit�.
 */
static void checkComplete(final String source,
                          final ParsePosition pos,