sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1562800 [1/3] - in /sis/trunk: ./ core/sis-referencing/src/main/java/org/apache/sis/geometry/ core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ core/sis-referencing/src/main/java/org/apache/sis/io/wkt/ core/sis-refere...
Date Thu, 30 Jan 2014 12:37:11 GMT
Author: desruisseaux
Date: Thu Jan 30 12:37:10 2014
New Revision: 1562800

URL: http://svn.apache.org/r1562800
Log:
Merge from the JDK6 branch.

Added:
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Legacy.java
      - copied unchanged from r1562799, sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Legacy.java
Removed:
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Legacy.java
Modified:
    sis/trunk/   (props changed)
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralEnvelope.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/SubEnvelope.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/VerticalDatumTypes.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Colors.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Convention.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/FormattableObject.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Formatter.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Symbols.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/UnformattableObjectException.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/WKTFormat.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/package-info.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeocentricCRS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralDirectPositionTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/ConventionTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/FormatterTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/SymbolsTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/Assert.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/HardCodedCRS.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/HardCodedCRSTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxisTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/HardCodedAxes.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/datum/DefaultEllipsoidTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/datum/DefaultGeodeticDatumTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/datum/DefaultPrimeMeridianTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/datum/DefaultVerticalDatumTest.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/ComparisonMode.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages_fr.properties
    sis/trunk/pom.xml

Propchange: sis/trunk/
------------------------------------------------------------------------------
  Merged /sis/branches/JDK7:r1560379-1562797
  Merged /sis/branches/JDK6:r1560381-1562799

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -526,6 +526,7 @@ public abstract class AbstractEnvelope i
      * @return A representation of this envelope as an array of non-empty envelope.
      *
      * @see Envelope2D#toRectangles()
+     * @see GeneralEnvelope#simplify()
      *
      * @since 0.4
      */
@@ -1035,11 +1036,11 @@ public abstract class AbstractEnvelope i
      * where <var>n</var> is the {@linkplain #getDimension() number of dimensions}.
      * The number of dimension is written only if different than 2.
      *
-     * <p>Example:</p>
-     *
-     * {@preformat wkt
-     *   BOX(-90 -180, 90 180)
-     *   BOX3D(-90 -180 0, 90 180 1)
+     * {@example
+     *   <ul>
+     *     <li><code>BOX(-90 -180, 90 180)</code></li>
+     *     <li><code>BOX3D(-90 -180 0, 90 180 1)</code></li>
+     *   </ul>
      * }
      *
      * {@note The <code>BOX</code> element is not part of the standard <cite>Well Known Text</cite>
@@ -1182,7 +1183,10 @@ public abstract class AbstractEnvelope i
      * @param  dimension The dimension to set.
      * @param  lower     The limit in the direction of decreasing ordinate values.
      * @param  upper     The limit in the direction of increasing ordinate values.
+     * @throws UnmodifiableGeometryException If this envelope is not modifiable.
      * @throws IndexOutOfBoundsException If the given index is out of bounds.
+     * @throws IllegalArgumentException If {@code lower > upper}, this envelope has a CRS
+     *         and the axis range meaning at the given dimension is not "wraparound".
      */
     void setRange(final int dimension, final double lower, final double upper)
             throws IndexOutOfBoundsException

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -27,8 +27,10 @@ import org.opengis.geometry.Envelope;
 import org.opengis.geometry.DirectPosition;
 import org.opengis.geometry.MismatchedDimensionException;
 import org.opengis.metadata.extent.GeographicBoundingBox;
+import org.opengis.referencing.cs.RangeMeaning;
 import org.opengis.referencing.cs.CoordinateSystemAxis;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.apache.sis.referencing.IdentifiedObjects;
 import org.apache.sis.referencing.CommonCRS;
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.CharSequences;
@@ -115,6 +117,7 @@ class ArrayEnvelope extends AbstractEnve
             ordinates[i            ] = lowerCorner.getOrdinate(i);
             ordinates[i + dimension] = upperCorner.getOrdinate(i);
         }
+        verifyRanges(crs, ordinates);
     }
 
     /**
@@ -171,6 +174,7 @@ class ArrayEnvelope extends AbstractEnve
             ordinates[i]           = lowerCorner.getOrdinate(i);
             ordinates[i+dimension] = upperCorner.getOrdinate(i);
         }
+        verifyRanges(crs, ordinates);
     }
 
     /**
@@ -196,6 +200,7 @@ class ArrayEnvelope extends AbstractEnve
             }
         }
         crs = CommonCRS.defaultGeographic();
+        verifyRanges(crs, ordinates);
     }
 
     /**
@@ -316,6 +321,59 @@ scanNumber: while ((i += Character.charC
     }
 
     /**
+     * Verifies the validity of the range of ordinates values in the given array.
+     * If the given CRS is null, then this method conservatively does nothing.
+     * Otherwise this method performs the following verifications:
+     *
+     * <ul>
+     *   <li>{@code lower > upper} is allowed only for axes having {@link RangeMeaning#WRAPAROUND}.</li>
+     * </ul>
+     *
+     * This method does <strong>not</strong> verify if the ordinate values are between the axis minimum and
+     * maximum values. This is because out-of-range values exist in practice but do not impact the working
+     * of {@code add(…)}, {@code intersect(…)}, {@code contains(…)} and similar methods. This in contrast
+     * with the checks listed above, where failure to meet those conditions will cause the methods to
+     * behave in an unexpected way.
+     *
+     * {@section Implementation consistency}
+     * The checks performed by this method shall be consistent with the checks performed by the following methods:
+     * <ul>
+     *   <li>{@link GeneralEnvelope#setCoordinateReferenceSystem(CoordinateReferenceSystem)}</li>
+     *   <li>{@link GeneralEnvelope#setRange(int, double, double)}</li>
+     *   <li>{@link SubEnvelope#setRange(int, double, double)}</li>
+     * </ul>
+     *
+     * @param crs The coordinate reference system, or {@code null}.
+     * @param ordinates The array of ordinate values to verify.
+     */
+    static void verifyRanges(final CoordinateReferenceSystem crs, final double[] ordinates) {
+        if (crs != null) {
+            final int dimension = ordinates.length >>> 1;
+            for (int i=0; i<dimension; i++) {
+                final double lower = ordinates[i];
+                final double upper = ordinates[i + dimension];
+                if (lower > upper && !isWrapAround(crs, i)) {
+                    throw new IllegalArgumentException(illegalRange(crs, i, lower, upper));
+                }
+            }
+        }
+    }
+
+    /**
+     * Creates an error message for an illegal ordinates range at the given dimension.
+     * This is used for formatting the exception message.
+     */
+    static String illegalRange(final CoordinateReferenceSystem crs,
+            final int dimension, final double lower, final double upper)
+    {
+        Object name = IdentifiedObjects.getName(getAxis(crs, dimension), null);
+        if (name == null) {
+            name = dimension; // Paranoiac fallback (name should never be null).
+        }
+        return Errors.format(Errors.Keys.IllegalOrdinateRange_3, lower, upper, name);
+    }
+
+    /**
      * Returns the index of the first valid ordinate value of the lower corner in the {@link #ordinates} array.
      * This is always 0, unless this envelope is a {@link SubEnvelope}.
      *

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -93,7 +93,7 @@ public final class Envelopes extends Sta
         ensureNonNull("wkt", wkt);
         try {
             return new GeneralEnvelope(wkt);
-        } catch (RuntimeException e) {
+        } catch (IllegalArgumentException e) {
             throw new FactoryException(Errors.format(
                     Errors.Keys.UnparsableStringForClass_2, Envelope.class), e);
         }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralEnvelope.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralEnvelope.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralEnvelope.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralEnvelope.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -90,6 +90,24 @@ import static org.apache.sis.math.MathFu
  * </ul>
  * </td></tr></table>
  *
+ * {@section Envelope validation}
+ * If and only if this envelope is associated to a non-null CRS, then constructors and setter methods
+ * in this class perform the following checks:
+ *
+ * <ul>
+ *   <li>The number of CRS dimensions must be equals to <code>this.{@linkplain #getDimension()}</code>.</li>
+ *   <li>For each dimension <var>i</var>,
+ *       <code>{@linkplain #getLower(int) getLower}(i) &gt; {@linkplain #getUpper(int) getUpper}(i)</code> is allowed
+ *       only if the {@linkplain org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis#getRangeMeaning() coordinate
+ *       system axis range meaning} is {@code WRAPAROUND}.</li>
+ * </ul>
+ *
+ * Note that this class does <em>not</em> require the ordinate values to be between the axis minimum and
+ * maximum values. This flexibility exists because out-of-range values happen in practice, while they do
+ * not hurt the working of {@code add(…)}, {@code intersect(…)}, {@code contains(…)} and similar methods.
+ * This in contrast with the {@code lower > upper} case, which cause the above-cited methods to behave in
+ * an unexpected way if the axis does not have wraparound range meaning.
+ *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Johann Sorel (Geomatys)
  * @since   0.3 (derived from geotk-2.4)
@@ -218,14 +236,14 @@ public class GeneralEnvelope extends Arr
      * check that every points in a {@code LINESTRING} have the same dimension. However this
      * constructor ensures that the parenthesis are balanced, in order to catch some malformed WKT.
      *
-     * <p>The following examples can be parsed by this constructor in addition of the usual
-     * {@code BOX} element. This constructor creates the bounding box of those geometries:</p>
+     * {@example The following texts can be parsed by this constructor in addition of the usual
+     * <code>BOX</code> element. This constructor creates the bounding box of those geometries:
      *
      * <ul>
-     *   <li>{@code POINT(6 10)}</li>
-     *   <li>{@code MULTIPOLYGON(((1 1, 5 1, 1 5, 1 1),(2 2, 3 2, 3 3, 2 2)))}</li>
-     *   <li>{@code GEOMETRYCOLLECTION(POINT(4 6),LINESTRING(3 8,7 10))}</li>
-     * </ul>
+     *   <li><code>POINT(6 10)</code></li>
+     *   <li><code>MULTIPOLYGON(((1 1, 5 1, 1 5, 1 1),(2 2, 3 2, 3 3, 2 2)))</code></li>
+     *   <li><code>GEOMETRYCOLLECTION(POINT(4 6),LINESTRING(3 8,7 10))</code></li>
+     * </ul>}
      *
      * @param  wkt The {@code BOX}, {@code POLYGON} or other kind of element to parse.
      * @throws IllegalArgumentException If the given string can not be parsed.
@@ -258,21 +276,42 @@ public class GeneralEnvelope extends Arr
 
     /**
      * Sets the coordinate reference system in which the coordinate are given.
-     * This method <strong>does not</strong> reproject the envelope, and do not
-     * check if the envelope is contained in the new domain of validity.
+     * This method <strong>does not</strong> reproject the envelope, and does
+     * not check if the envelope is contained in the new domain of validity.
      *
      * <p>If the envelope coordinates need to be transformed to the new CRS, consider
      * using {@link Envelopes#transform(Envelope, CoordinateReferenceSystem)} instead.</p>
      *
      * @param  crs The new coordinate reference system, or {@code null}.
-     * @throws MismatchedDimensionException if the specified CRS doesn't have the expected
-     *         number of dimensions.
+     * @throws MismatchedDimensionException if the specified CRS doesn't have the expected number of dimensions.
+     * @throws IllegalStateException if a range of ordinate values in this envelope is compatible with the given CRS.
+     *         See <cite>Envelope validation</cite> in class javadoc for more details.
      */
     public void setCoordinateReferenceSystem(final CoordinateReferenceSystem crs)
             throws MismatchedDimensionException
     {
         ensureDimensionMatches("crs", getDimension(), crs);
-        this.crs = crs;
+        /*
+         * The check performed here shall be identical to ArrayEnvelope.verifyRanges(crs, ordinates)
+         * except that it may verify only a subset of the ordinate array and throws a different kind
+         * of exception in caseo of failure.
+         */
+        if (crs != null) {
+            final int beginIndex = beginIndex();
+            final int endIndex = endIndex();
+            final int d = ordinates.length >>> 1;
+            for (int i=beginIndex; i<endIndex; i++) {
+                final double lower = ordinates[i];
+                final double upper = ordinates[i + d];
+                if (lower > upper) {
+                    final int j = i - beginIndex;
+                    if (!isWrapAround(crs, j)) {
+                        throw new IllegalStateException(illegalRange(crs, j, lower, upper));
+                    }
+                }
+            }
+        }
+        this.crs = crs; // Set only on success.
     }
 
     /**
@@ -282,6 +321,8 @@ public class GeneralEnvelope extends Arr
      * @param  lower     The limit in the direction of decreasing ordinate values.
      * @param  upper     The limit in the direction of increasing ordinate values.
      * @throws IndexOutOfBoundsException If the given index is out of bounds.
+     * @throws IllegalArgumentException If {@code lower > upper} and the axis range meaning at the given dimension
+     *         is not "wraparound". See <cite>Envelope validation</cite> in class javadoc for more details.
      */
     @Override // Must also be overridden in SubEnvelope
     public void setRange(final int dimension, final double lower, final double upper)
@@ -289,6 +330,13 @@ public class GeneralEnvelope extends Arr
     {
         final int d = ordinates.length >>> 1;
         ensureValidIndex(d, dimension);
+        /*
+         * The check performed here shall be identical to ArrayEnvelope.verifyRanges(crs, ordinates),
+         * except that there is no loop.
+         */
+        if (lower > upper && crs != null && !isWrapAround(crs, dimension)) {
+            throw new IllegalArgumentException(illegalRange(crs, dimension, lower, upper));
+        }
         ordinates[dimension + d] = upper;
         ordinates[dimension]     = lower;
     }
@@ -299,14 +347,16 @@ public class GeneralEnvelope extends Arr
      * this {@linkplain #getDimension() envelope dimension}, and minimum shall not be greater
      * than maximum.
      *
-     * <p><b>Example:</b></p>
+     * {@example
      * (<var>x</var><sub>min</sub>, <var>y</var><sub>min</sub>, <var>z</var><sub>min</sub>,
      *  <var>x</var><sub>max</sub>, <var>y</var><sub>max</sub>, <var>z</var><sub>max</sub>)
+     * }
      *
      * @param corners Ordinates of the new lower corner followed by the new upper corner.
      */
     public void setEnvelope(final double... corners) {
         verifyArrayLength(ordinates.length >>> 1, corners);
+        verifyRanges(crs, corners);
         System.arraycopy(corners, 0, ordinates, 0, ordinates.length);
     }
 
@@ -876,6 +926,8 @@ public class GeneralEnvelope extends Arr
      *         or {@code false} if no change has been done.
      * @throws IllegalStateException If a upper ordinate value is less than a lower ordinate
      *         value on an axis which does not have the {@code WRAPAROUND} range meaning.
+     *
+     * @see #toSimpleEnvelopes()
      */
     public boolean simplify() throws IllegalStateException {
         boolean changed = false;

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/SubEnvelope.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/SubEnvelope.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/SubEnvelope.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/SubEnvelope.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -126,6 +126,13 @@ final class SubEnvelope extends GeneralE
             throws IndexOutOfBoundsException
     {
         ensureValidIndex(endIndex, dimension);
+        /*
+         * The check performed here shall be identical to the super-class method, which is itself
+         * identical to ArrayEnvelope.verifyRanges(crs, ordinates) except that there is no loop.
+         */
+        if (lower > upper && crs != null && !isWrapAround(crs, dimension)) {
+            throw new IllegalArgumentException(illegalRange(crs, dimension, lower, upper));
+        }
         dimension += beginIndex;
         ordinates[dimension + (ordinates.length >>> 1)] = upper;
         ordinates[dimension] = lower;
@@ -138,6 +145,7 @@ final class SubEnvelope extends GeneralE
     public void setEnvelope(final double... corners) {
         final int dimension = getDimension();
         verifyArrayLength(dimension, corners);
+        verifyRanges(crs, corners);
         final int d = ordinates.length >>> 1;
         System.arraycopy(corners, 0,         ordinates, beginIndex,     dimension);
         System.arraycopy(corners, dimension, ordinates, beginIndex + d, dimension);

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -334,17 +334,16 @@ public final class AxisDirections extend
      * @param  direction The direction of the axis to search.
      * @return The dimension of the axis using the given direction or its opposite, or -1 if none.
      */
-    public static int indexOf(final CoordinateSystem cs, final AxisDirection direction) {
+    public static int indexOfColinear(final CoordinateSystem cs, final AxisDirection direction) {
         int fallback = -1;
         if (cs != null) {
-            final AxisDirection opposite = opposite(direction);
             final int dimension = cs.getDimension();
             for (int i=0; i<dimension; i++) {
                 final AxisDirection d = cs.getAxis(i).getDirection();
                 if (direction.equals(d)) {
                     return i;
                 }
-                if (fallback < 0 && opposite != null && opposite.equals(d)) {
+                if (fallback < 0 && d.equals(opposite(direction))) {
                     fallback = i;
                 }
             }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -122,7 +122,7 @@ public final class ReferencingUtilities 
     /**
      * Returns the unit used for all axes in the given coordinate system.
      * If not all axes use the same unit, then this method returns {@code null}.
-     * This convenience method is often used for Well Know Text (WKT) version 1 formatting.
+     * This convenience method is used for Well Know Text version 1 (WKT 1) formatting.
      *
      * @param cs The coordinate system for which to get the unit, or {@code null}.
      * @return The unit for all axis in the given coordinate system, or {@code null}.

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/VerticalDatumTypes.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/VerticalDatumTypes.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/VerticalDatumTypes.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/VerticalDatumTypes.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -87,10 +87,10 @@ public final class VerticalDatumTypes im
 
     /**
      * Returns the vertical datum type from a legacy code. The legacy codes were defined in
-     * <a href="http://www.opengis.org/docs/01-009.pdf">Coordinate Transformation Services</a>
-     * (OGC 01-009), which also defined the
+     * <a href="http://www.opengeospatial.org/standards/ct">OGC 01-009</a>
+     * (<cite>Coordinate Transformation Services)</cite>, which also defined the version 1 of
      * <a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well
-     * Known Text</cite> (WKT)</a> format. This method is used for WKT parsing.
+     * Known Text</cite></a> format (WKT 1). This method is used for WKT 1 parsing.
      *
      * @param  code The legacy vertical datum code.
      * @return The vertical datum type, or {@code null} if the code is unrecognized.

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Colors.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Colors.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Colors.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Colors.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -50,13 +50,15 @@ public class Colors implements Serializa
     private static final long serialVersionUID = 256160285861027191L;
 
     /**
-     * The immutable default set of colors.
+     * A map of colors for outputs to the {@link java.io.Console}.
+     * Those colors give better results on a black background.
+     * This map is immutable.
      *
-     * @see Symbols#DEFAULT
+     * @see FormattableObject#print()
      */
-    public static final Colors DEFAULT = new Immutable();
+    public static final Colors CONSOLE = new Immutable();
     static {
-        final EnumMap<ElementKind,X364> map = DEFAULT.map;
+        final EnumMap<ElementKind,X364> map = CONSOLE.map;
         map.put(ElementKind.NUMBER,     X364.FOREGROUND_YELLOW);
         map.put(ElementKind.INTEGER,    X364.FOREGROUND_YELLOW);
         map.put(ElementKind.UNIT,       X364.FOREGROUND_YELLOW);
@@ -134,7 +136,7 @@ public class Colors implements Serializa
     }
 
     /**
-     * An immutable subclass of {@link Colors} for the {@link Colors#DEFAULT} constant
+     * An immutable subclass of {@link Colors} for the {@link Colors#CONSOLE} constant
      * or for the object to be used by {@link WKTFormat}.
      */
     private static final class Immutable extends Colors {
@@ -174,10 +176,10 @@ public class Colors implements Serializa
         }
 
         /**
-         * Replaces the deserialized instance by {@link #DEFAULT} one if possible.
+         * Replaces the deserialized instance by {@link #CONSOLE} one if possible.
          */
         Object readResolve() throws ObjectStreamException {
-            return super.map.equals(DEFAULT.map) ? DEFAULT : this;
+            return super.map.equals(CONSOLE.map) ? CONSOLE : this;
         }
     }
 }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Convention.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Convention.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Convention.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Convention.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -20,11 +20,7 @@ import javax.measure.unit.Unit;
 import javax.measure.quantity.Angle;
 import javax.measure.quantity.Quantity;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.referencing.cs.CartesianCS;
-import org.opengis.referencing.cs.CoordinateSystem;
 import org.opengis.referencing.crs.GeocentricCRS;
-import org.opengis.referencing.operation.OperationMethod;
-import org.opengis.referencing.operation.CoordinateOperation;
 import org.apache.sis.util.Debug;
 import org.apache.sis.metadata.iso.citation.Citations;
 
@@ -33,21 +29,26 @@ import static javax.measure.unit.NonSI.D
 
 /**
  * The convention to use for WKT formatting.
- * This enumeration attempts to address some of the variability documented in the Frank Warmerdam's
- * <a href="http://home.gdal.org/projects/opengis/wktproblems.html">OGC WKT Coordinate System Issues</a> page.
- * The various conventions enumerated in this class differ mostly in:
+ * This enumeration specifies whether to use the <cite>Well Known Text</cite> format defined by ISO 19162
+ * (also known as “WKT 2”), or whether to use the format previously defined in OGC 01-009 (referenced as “WKT 1”).
+ *
+ * {@section WKT 1 variants}
+ * The WKT 2 format should be parsed and formatted consistently by all softwares.
+ * But the WKT 1 format has been interpreted differently by various implementors.
+ * Apache SIS can adapt itself to different WKT variants, sometime automatically. But some aspects can not be guessed.
+ * One noticeable source of confusion is the unit of measurement of {@code PRIMEM[…]} and {@code PARAMETER[…]} elements:
  *
  * <ul>
- *   <li><em>Parameter names</em> - for example a parameter named "<cite>Longitude of natural origin</cite>"
- *       according {@linkplain #EPSG} may be named "{@code central_meridian}" according {@linkplain #OGC}
- *       and "{@code NatOriginLong}" according {@linkplain #GEOTIFF GeoTIFF}.</li>
- *   <li><em>WKT syntax</em> - for example {@linkplain #ORACLE Oracle} does not enclose Bursa-Wolf parameters in a
- *       {@code TOWGS84[…]} element.</li>
- *   <li><em>Unit of measurement</em> - for example the unit of the Prime Meridian shall be the angular unit of the
- *       enclosing Geographic CRS according the {@linkplain #OGC} standard, but is restricted to decimal degrees by
- *       {@linkplain #ESRI}.</li>
+ *   <li>The unit of the Prime Meridian shall be the angular unit of the enclosing Geographic CRS
+ *       according the OGC 01-009 (<cite>Coordinate transformation services</cite>) specification.</li>
+ *   <li>An older specification — <cite>Simple Features</cite> — was unclear on this matter and has been
+ *       interpreted by many softwares as fixing the unit to decimal degrees.</li>
  * </ul>
  *
+ * Despite the first interpretation being specified by both OGC 01-009 and ISO 19162 standards, the second
+ * interpretation appears to be in wide use for WKT 1. Apache SIS uses the standard interpretation by default,
+ * but the {@link #WKT1_COMMON_UNITS} enumeration allows parsing and formatting using the older interpretation.
+ *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4 (derived from geotk-3.20)
  * @version 0.4
@@ -58,219 +59,139 @@ import static javax.measure.unit.NonSI.D
  */
 public enum Convention {
     /**
-     * The <a href="http://www.opengeospatial.org">Open Geospatial consortium</a> convention.
+     * The ISO 19162 format, also known as “WKT 2”.
      * This is the default convention for all WKT formatting in the Apache SIS library.
-     * Some worthy aspects to note:
-     *
-     * <ul>
-     *   <li>For {@link GeocentricCRS}, this convention uses the legacy set of Cartesian axes.
-     *     Those axes were defined in OGC 01-009 as <var>Other</var>, <var>Easting</var> and <var>Northing</var>
-     *     in metres, where the "<var>Other</var>" axis is toward prime meridian.</li>
-     * </ul>
-     *
-     * @see Citations#OGC
-     * @see #toConformCS(CoordinateSystem)
-     */
-    OGC(Citations.OGC, null, false),
-
-    /**
-     * The <a href="http://www.epsg.org">European Petroleum Survey Group</a> convention.
-     * This convention uses the most descriptive parameter and projection names.
-     * Some worthy aspects to note:
      *
-     * <ul>
-     *   <li>For {@link GeocentricCRS}, this convention uses the new set of Cartesian axes.
-     *     Those axes are defined in ISO 19111 as <var>Geocentric X</var>, <var>Geocentric Y</var>
-     *     and <var>Geocentric Z</var> in metres.</li>
-     * </ul>
+     * <p>Unless otherwise specified by {@link WKTFormat#setNameAuthority(Citation)}, when using
+     * this convention SIS will favor {@linkplain Citations#EPSG EPSG} definitions of projection
+     * and parameter names.</p>
+     */
+    WKT2(Citations.EPSG, false, false),
+
+    /**
+     * The OGC 01-009 format, also known as “WKT 1”.
+     * A definition for this format is shown in Extended Backus Naur Form (EBNF)
+     * <a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">on GeoAPI</a>.
+     *
+     * <p>Unless otherwise specified by {@link WKTFormat#setNameAuthority(Citation)}, when using
+     * this convention SIS will favor {@linkplain Citations#OGC OGC} definitions of projection
+     * and parameter names.</p>
+     *
+     * {@section Differences compared to WKT 2}
+     * WKT 1 and WKT 2 differ in their keywords and syntax, but also in more subtle ways regarding parameter
+     * and code list values. For {@link GeocentricCRS}, WKT 1 uses a legacy set of Cartesian axes which were
+     * defined in OGC 01-009. Those axes use the <var>Other</var>, <var>Easting</var> and <var>Northing</var>
+     * {@linkplain org.opengis.referencing.cs.AxisDirection axis directions} instead than the geocentric ones,
+     * as shown in the following table:
      *
-     * @see Citations#EPSG
-     * @see #toConformCS(CoordinateSystem)
+     * <table class="sis">
+     *   <tr><th>ISO 19111</th>    <th>OGC 01-009</th> <th>Description</th></tr>
+     *   <tr><td>Geocentric X</td> <td>Other</td>      <td>Toward prime meridian</td></tr>
+     *   <tr><td>Geocentric Y</td> <td>Easting</td>    <td>Toward 90°E longitude</td></tr>
+     *   <tr><td>Geocentric Z</td> <td>Northing</td>   <td>Toward north pole</td></tr>
+     * </table>
      */
-    EPSG(Citations.EPSG, null, false) {
-        @Override
-        public CoordinateSystem toConformCS(CoordinateSystem cs) {
-            if (cs instanceof CartesianCS) {
-                cs = Legacy.replace((CartesianCS) cs, false);
-            }
-            return cs;
-        }
-    },
+    WKT1(Citations.OGC, true, false),
 
     /**
-     * The <a href="http://www.esri.com">ESRI</a> convention.
-     * This convention is similar to the {@link #OGC} convention except in the following aspects:
+     * The <cite>Simple Feature</cite> format, also known as “WKT 1”.
+     * <cite>Simple Feature</cite> is anterior to OGC 01-009 and defines the same format,
+     * but was unclear about the unit of measurement for prime meridians and projection parameters.
+     * Consequently many implementations interpreted those angular units as fixed to degrees instead
+     * than being context-dependent.
      *
+     * <p>This convention is identical to {@link #WKT1} except for the following aspects:</p>
      * <ul>
      *   <li>The angular units of {@code PRIMEM} and {@code PARAMETER} elements are always degrees,
      *       no matter the units of the enclosing {@code GEOGCS} element.</li>
-     *   <li>The {@code AXIS} elements are ignored at parsing time.</li>
      *   <li>Unit names use American spelling instead than the international ones
      *       (e.g. "<cite>meter</cite>" instead than "<cite>metre</cite>").</li>
-     *   <li>At parsing time, the {@code AXIS} elements are ignored.</li>
      * </ul>
-     *
-     * @see Citations#ESRI
      */
-    ESRI(Citations.ESRI, DEGREE_ANGLE, true),
+    WKT1_COMMON_UNITS(Citations.OGC, true, true),
 
     /**
-     * The <a href="http://www.oracle.com">Oracle</a> convention.
-     * This convention is similar to the {@link #OGC} convention except in the following aspects:
-     *
-     * <ul>
-     *   <li>The Bursa-Wolf parameters are inserted straight into the {@code DATUM} element,
-     *       without enclosing them in a {@code TOWGS84} element.</li>
-     *   <li>The {@code PROJECTION} names are {@linkplain CoordinateOperation Coordinate Operation}
-     *       names instead than {@linkplain OperationMethod Operation Method} names.</li>
-     *   <li>Unit names use American spelling instead than the international ones
-     *       (e.g. "<cite>meter</cite>" instead than "<cite>metre</cite>").</li>
-     * </ul>
+     * A special convention for formatting objects as stored internally by Apache SIS.
+     * In the majority of cases, the result will be identical to the one we would get using the {@link #WKT2} convention.
+     * However in the particular case of map projections, the result may be quite different because of the way
+     * SIS separates the linear from the non-linear parameters.
      *
-     * @see Citations#ORACLE
+     * <p>This convention is used only for debugging purpose.</p>
      */
-    ORACLE(Citations.ORACLE, null, true),
+    @Debug
+    INTERNAL(Citations.OGC, false, false);
 
     /**
-     * The <a href="http://www.unidata.ucar.edu/software/netcdf-java">NetCDF</a> convention.
-     * This convention is similar to the {@link #OGC} convention except in the following aspects:
-     *
-     * <ul>
-     *   <li>Parameter and projection names.</li>
-     * </ul>
+     * The default conventions.
      *
-     * @see Citations#NETCDF
+     * @todo Make final after we completed the migration from Geotk.
      */
-    NETCDF(Citations.NETCDF, null, false),
+    static Convention DEFAULT = WKT2;
 
     /**
-     * The <a href="http://www.remotesensing.org/geotiff/geotiff.html">GeoTIFF</a> convention.
-     * This convention is similar to the {@link #OGC} convention except in the following aspects:
-     *
-     * <ul>
-     *   <li>Parameter and projection names.</li>
-     * </ul>
-     *
-     * @see Citations#GEOTIFF
+     * {@code true} for using WKT 1 syntax, or {@code false} for using WKT 2 syntax.
      */
-    GEOTIFF(Citations.GEOTIFF, null, false),
+    final boolean isWKT1;
 
     /**
-     * The <a href="http://trac.osgeo.org/proj/">Proj.4</a> convention.
-     * This convention is similar to the {@link #OGC} convention except in the following aspects:
-     *
+     * {@code true} for a frequently-used convention about units instead than the standard one.
      * <ul>
-     *   <li>Very short parameter and projection names.</li>
-     *   <li>The angular units of {@code PRIMEM} and {@code PARAMETER} elements are always degrees,
-     *       no matter the units of the enclosing {@code GEOGCS} element.</li>
+     *   <li>If {@code true}, forces {@code PRIMEM} and {@code PARAMETER} angular units to degrees
+     *       instead than inferring the unit from the context. The standard value is {@code false},
+     *       which means that the angular units are inferred from the context as required by the
+     *       WKT 1 specification.</li>
+     *   <li>If {@code true}, uses US unit names instead of the international names.
+     *       For example Americans said {@code "meter"} instead of {@code "metre"}.</li>
      * </ul>
      *
-     * @see Citations#PROJ4
-     */
-    PROJ4(Citations.PROJ4, DEGREE_ANGLE, false),
-
-    /**
-     * A special convention for formatting objects as stored internally by Apache SIS.
-     * In the majority of cases, the result will be identical to the one we would get using the {@link #OGC} convention.
-     * However in the particular case of map projections, the result may be quite different because of the way
-     * SIS separates the linear from the non-linear parameters.
-     *
-     * <p>This convention is used only for debugging purpose.</p>
-     */
-    @Debug
-    INTERNAL(Citations.OGC, null, false) {
-        /**
-         * Declares publicly that this convention is defined by Apache SIS, despite the
-         * package-private {@link #authority} field being set to OGC for {@link Formatter} needs.
-         */
-        @Override
-        public Citation getAuthority() {
-            return Citations.SIS;
-        }
-
-        @Override
-        public CoordinateSystem toConformCS(final CoordinateSystem cs) {
-            return cs; // Prevent any modification on the internal CS.
-        }
-    };
-
-    /**
-     * If non-null, forces {@code PRIMEM} and {@code PARAMETER} angular units to this field
-     * value instead than inferring it from the context. The standard value is {@code null},
-     * which means that the angular units are inferred from the context as required by the
-     * <a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html#PRIMEM">WKT specification</a>.
-     *
      * @see #getForcedUnit(Class)
      */
-    final Unit<Angle> forcedAngularUnit;
+    final boolean commonUnits;
 
     /**
-     * {@code true} if the convention uses US unit names instead of the international names.
-     * For example Americans said [@code "meter"} instead of {@code "metre"}.
+     * The organization, standard or project to look for when fetching Map Projection parameter names.
+     * Should be one of the authorities known to {@link org.apache.sis.referencing.operation.provider}.
      */
-    final boolean unitUS;
-
-    /**
-     * The organization, standard or project to use for fetching Map Projection parameter names.
-     * Shall be one of the authorities known to {@link org.apache.sis.referencing.operation.provider}.
-     */
-    final Citation authority;
+    private final Citation authority;
 
     /**
      * Creates a new enumeration value.
      */
-    private Convention(final Citation authority, final Unit<Angle> angularUnit, final boolean unitUS) {
-        this.authority         = authority;
-        this.forcedAngularUnit = angularUnit;
-        this.unitUS            = unitUS;
+    private Convention(final Citation authority, final boolean isWKT1, final boolean commonUnits) {
+        this.authority   = authority;
+        this.isWKT1      = isWKT1;
+        this.commonUnits = commonUnits;
     }
 
     /**
-     * Returns the convention for the organization, standard or project specified by the given citation.
+     * Returns {@code true} if this convention is one of the WKT 1 variants.
      *
-     * @param  authority The organization, standard or project for which to get the convention, or {@code null}.
-     * @param  defaultConvention The default convention to return if none where found for the given citation.
-     * @return The convention, or {@code null} if no matching convention were found and the
-     *         {@code defaultConvention} argument is {@code null}.
-     */
-    public static Convention forCitation(final Citation authority, final Convention defaultConvention) {
-        if (authority != null) {
-            for (final Convention candidate : values()) {
-                if (Citations.identifierMatches(candidate.getAuthority(), authority)) {
-                    return candidate;
-                }
-            }
-        }
-        return defaultConvention;
+     * @return {@code true} if this convention is one of the WKT 1 variants.
+     */
+    public boolean isWKT1() {
+        return isWKT1;
     }
 
     /**
-     * Returns the convention for the organization, standard or project specified by the given identifier.
+     * Returns the default authority to look for when fetching Map Projection parameter names.
+     * The value returned by this method can be overwritten by {@link WKTFormat#setNameAuthority(Citation)}.
      *
-     * @param  authority The organization, standard or project for which to get the convention, or {@code null}.
-     * @param  defaultConvention The default convention to return if none where found for the given identifier.
-     * @return The convention, or {@code null} if no matching convention were found and the
-     *         {@code defaultConvention} argument is {@code null}.
-     */
-    public static Convention forIdentifier(final String authority, final Convention defaultConvention) {
-        if (authority != null) {
-            for (final Convention candidate : values()) {
-                if (Citations.identifierMatches(candidate.getAuthority(), authority)) {
-                    return candidate;
-                }
-            }
-        }
-        return defaultConvention;
-    }
-
-    /**
-     * Returns the citation for the organization, standard of project that defines this convention.
+     * {@example The following table shows the names given by various organizations or projects for the same projection:
+     *
+     * <table class="sis">
+     *   <tr><th>Authority</th> <th>Projection name</th></tr>
+     *   <tr><td>EPSG</td>      <td>Mercator (variant A)</td></tr>
+     *   <tr><td>OGC</td>       <td>Mercator_1SP</td></tr>
+     *   <tr><td>GEOTIFF</td>   <td>CT_Mercator</td></tr>
+     * </table>}
      *
-     * @return The organization, standard or project that defines this convention.
+     * @return The organization, standard or project to look for when fetching Map Projection parameter names.
      *
-     * @see WKTFormat#getAuthority()
+     * @see WKTFormat#getNameAuthority()
+     * @see Citations#EPSG
+     * @see Citations#OGC
      */
-    public Citation getAuthority() {
+    public Citation getNameAuthority() {
         return authority;
     }
 
@@ -287,35 +208,11 @@ public enum Convention {
      */
     @SuppressWarnings("unchecked")
     public <T extends Quantity> Unit<T> getForcedUnit(final Class<T> quantity) {
-        if (quantity == Angle.class) {
-            return (Unit) forcedAngularUnit;
+        if (commonUnits) {
+            if (quantity == Angle.class) {
+                return (Unit<T>) DEGREE_ANGLE;
+            }
         }
         return null;
     }
-
-    /**
-     * Makes the given coordinate system conform to this convention. This method is used mostly
-     * for converting between the legacy (OGC 01-009) {@link GeocentricCRS} axis directions,
-     * and the new (ISO 19111) directions. Those directions are:
-     *
-     * <table class="sis">
-     *   <tr><th>ISO 19111</th>    <th>OGC 01-009</th></tr>
-     *   <tr><td>Geocentric X</td> <td>Other</td></tr>
-     *   <tr><td>Geocentric Y</td> <td>Easting</td></tr>
-     *   <tr><td>Geocentric Z</td> <td>Northing</td></tr>
-     * </table>
-     *
-     * @param  cs The coordinate system.
-     * @return A coordinate system equivalent to the given one but with conform axis names,
-     *         or the given {@code cs} if no change apply to the given coordinate system.
-     *
-     * @see #OGC
-     * @see #EPSG
-     */
-    public CoordinateSystem toConformCS(CoordinateSystem cs) {
-        if (cs instanceof CartesianCS) {
-            cs = Legacy.replace((CartesianCS) cs, true);
-        }
-        return cs;
-    }
 }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/FormattableObject.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/FormattableObject.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/FormattableObject.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/FormattableObject.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -36,15 +36,14 @@ import org.apache.sis.internal.util.X364
  * representation of this object:</p>
  *
  * <ul>
- *   <li>{@link #toWKT()} returns a strictly compliant WKT or throw an exception.</li>
- *   <li>{@link #toString()} is like {@code toWKT()} with some rules relaxed in order
- *       to never throw exception.</li>
+ *   <li>{@link #toWKT()} returns a strictly compliant WKT or throws {@link UnformattableObjectException}
+ *       if this object contains elements not defined by the ISO 19162 standard.</li>
+ *   <li>{@link #toString()} returns a WKT with some rules relaxed in order to never throw exception,
+ *       using non-standard representation if necessary. In some cases {@code toString()} may also use
+ *       an alternative text representation for better readability, for example a matrix instead of
+ *       a list of {@code PARAMETER["elt_…", …]} elements for linear transforms.</li>
  * </ul>
  *
- * The {@code toWKT()} method may throw {@link UnformattableObjectException} if an object
- * contains elements not defined by the official standard, while {@code toString()} can
- * fallback on a non-standard representation.
- *
  * {@section Syntax coloring}
  * A convenience {@link #print()} method is provided, which is roughly equivalent to
  * {@code System.out.println(this)} except that syntax coloring is automatically applied
@@ -90,25 +89,23 @@ public class FormattableObject {
      * @see org.opengis.referencing.IdentifiedObject#toWKT()
      */
     public String toWKT() throws UnformattableObjectException {
-        return formatWKT(Convention.OGC, WKTFormat.DEFAULT_INDENTATION, false, true);
+        return formatWKT(Convention.DEFAULT, WKTFormat.DEFAULT_INDENTATION, false, true);
     }
 
     /**
-     * Returns a <cite>Well Known Text</cite> (WKT) using the default convention, symbols and indentation.
+     * Returns a <cite>Well Known Text</cite> (WKT) or an alternative text representation for this object.
      * If this object can not be represented in a standard way, then this method fallbacks on a non-standard
      * representation.
      *
-     * @return The Well Known Text (WKT) or a pseudo-WKT representation of this object.
+     * @return The Well Known Text (WKT) or an alternative representation of this object.
      */
     @Override
     public String toString() {
-        return formatWKT(Convention.OGC, WKTFormat.DEFAULT_INDENTATION, false, false);
+        return formatWKT(Convention.DEFAULT, WKTFormat.DEFAULT_INDENTATION, false, false);
     }
 
     /**
      * Returns a <cite>Well Known Text</cite> (WKT) for this object using the specified convention.
-     * The convention is usually {@link Convention#OGC OGC}, but other common conventions are
-     * {@link Convention#GEOTIFF GEOTIFF} and {@link Convention#EPSG EPSG}.
      * The {@link Convention#INTERNAL INTERNAL} convention is a special value for debugging map projections.
      *
      * @param  convention The WKT convention to use.
@@ -126,12 +123,14 @@ public class FormattableObject {
      * the console supports the ANSI escape codes (a.k.a. X3.64), then a syntax coloring will be applied.
      *
      * <p>This is a convenience method for debugging purpose and for console applications.</p>
+     *
+     * @see Colors#CONSOLE
      */
     @Debug
     public void print() {
         final Console console = System.console();
         final PrintWriter out = (console != null) ? console.writer() : null;
-        final String wkt = formatWKT(Convention.OGC, WKTFormat.DEFAULT_INDENTATION,
+        final String wkt = formatWKT(Convention.DEFAULT, WKTFormat.DEFAULT_INDENTATION,
                 (out != null) && X364.isAnsiSupported(), false);
         if (out != null) {
             out.println(wkt);
@@ -144,7 +143,7 @@ public class FormattableObject {
      * Returns a WKT for this object using the specified convention.
      * If {@code strict} is true, then an exception is thrown if the WKT is not standard-compliant.
      *
-     * @param  convention  The convention for choosing WKT entities names.
+     * @param  convention  The convention for choosing WKT element names.
      * @param  indentation The indentation to apply, or {@link WKTFormat#SINGLE_LINE}.
      * @param  colorize    {@code true} for applying syntax coloring, or {@code false} otherwise.
      * @param  strict      {@code true} if an exception shall be thrown for unformattable objects,
@@ -160,7 +159,7 @@ public class FormattableObject {
             formatter = new Formatter();
         }
         formatter.indentation = indentation;
-        formatter.colors = colorize ? Colors.DEFAULT : null;
+        formatter.colors = colorize ? Colors.CONSOLE : null;
         formatter.setConvention(convention, null);
         final String wkt;
         try {
@@ -192,7 +191,7 @@ public class FormattableObject {
      * Formats the inner part of this <cite>Well Known Text</cite> (WKT) element into the given formatter.
      * This method is automatically invoked by {@link WKTFormat} when a formattable element is found.
      *
-     * <p>Element keyword and authority code shall not be formatted here.
+     * <p>Keywords and authority codes shall not be formatted here.
      * For example if this formattable element is for a {@code GEOGCS} element,
      * then this method shall write the content starting at the insertion point shows below:</p>
      *

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Formatter.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Formatter.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Formatter.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Formatter.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -127,8 +127,8 @@ public class Formatter {
     /**
      * The preferred authority for objects or parameter names.
      *
-     * @see WKTFormat#getAuthority(Citation)
-     * @see WKTFormat#setAuthority(Citation)
+     * @see WKTFormat#getNameAuthority()
+     * @see WKTFormat#setNameAuthority(Citation)
      */
     private Citation authority;
 
@@ -191,7 +191,7 @@ public class Formatter {
     private boolean requestNewLine;
 
     /**
-     * {@code true} if the last formatted element was invalid WKT and shall be highlighted with syntatic coloration.
+     * {@code true} if the last formatted element was invalid WKT and shall be highlighted with syntactic coloration.
      * This field has no effect if {@link #colors} is null. This field is reset to {@code false} after the invalid
      * part has been processed by {@link #append(FormattableObject)}, in order to highlight only the first erroneous
      * element without clearing the {@link #invalidElement} value.
@@ -218,7 +218,7 @@ public class Formatter {
      * Creates a new formatter instance with the default symbols, no syntax coloring and the default indentation.
      */
     public Formatter() {
-        this(Convention.OGC, Symbols.DEFAULT, null, WKTFormat.DEFAULT_INDENTATION);
+        this(Convention.DEFAULT, Symbols.DEFAULT, null, WKTFormat.DEFAULT_INDENTATION);
     }
 
     /**
@@ -250,7 +250,7 @@ public class Formatter {
      * This constructor helps to share some objects with {@link Parser}.
      */
     Formatter(final Symbols symbols, final NumberFormat numberFormat) {
-        this.convention   = Convention.OGC;
+        this.convention   = Convention.DEFAULT;
         this.symbols      = symbols;
         this.indentation  = WKTFormat.DEFAULT_INDENTATION;
         this.numberFormat = numberFormat; // No clone needed.
@@ -259,8 +259,7 @@ public class Formatter {
     }
 
     /**
-     * Returns the convention to use for formatting the WKT. The default convention is {@link Convention#OGC OGC}.
-     * A different convention will usually result in different parameter names, but may also change the WKT syntax.
+     * Returns the convention to use for formatting the WKT. The default is {@link Convention#WKT2}.
      *
      * @return The convention (never {@code null}).
      *
@@ -278,30 +277,26 @@ public class Formatter {
      * @param authority  The authority, or {@code null} for inferring it from the convention.
      */
     final void setConvention(Convention convention, final Citation authority) {
-        if (convention == null) {
-            convention = Convention.forCitation(authority, Convention.OGC);
-        }
         this.convention = convention;
-        this.authority  = (authority != null) ? authority : convention.authority; // NOT convention.getAuthority()
+        this.authority  = (authority != null) ? authority : convention.getNameAuthority();
     }
 
     /**
      * Returns the preferred name for the specified object.
-     * If the specified object contains a name from the preferred authority
-     * (usually {@linkplain org.apache.sis.metadata.iso.citation.Citations#OGC Open Geospatial}),
-     * then this name is returned. Otherwise, the first name found is returned.
+     * If the specified object contains a name from the preferred authority, then this name is returned.
+     * Otherwise, the first name found is returned.
      *
-     * <p>The preferred authority can be set by the {@link WKTFormat#setAuthority(Citation)} method.
+     * <p>The preferred authority can be set by the {@link WKTFormat#setNameAuthority(Citation)} method.
      * This is not necessarily the authority of the given {@linkplain IdentifiedObject#getName() object name}.</p>
      *
      * {@example The EPSG name of the <code>EPSG:6326</code> datum is "<cite>World Geodetic System 1984</cite>".
-     *           However if the preferred authority is OGC (which is the case by default), then this method usually
-     *           returns "<cite>WGS84</cite>" (the exact string to be returned depends on the object aliases).}
+     *           However if the preferred authority is OGC, then this method usually returns "<cite>WGS84</cite>"
+     *           (the exact string to be returned depends on the object aliases).}
      *
      * @param  object The object to look for a preferred name.
      * @return The preferred name, or {@code null} if the given object has no name.
      *
-     * @see WKTFormat#getAuthority()
+     * @see WKTFormat#getNameAuthority()
      * @see IdentifiedObjects#getName(IdentifiedObject, Citation)
      */
     public String getName(final IdentifiedObject object) {
@@ -314,9 +309,8 @@ public class Formatter {
 
     /**
      * Returns the preferred identifier for the specified object.
-     * If the specified object contains an identifier from the preferred authority
-     * (usually {@linkplain org.apache.sis.metadata.iso.citation.Citations#OGC Open Geospatial}),
-     * then this identifier is returned. Otherwise, the first identifier is returned.
+     * If the specified object contains an identifier from the preferred authority, then this identifier is returned.
+     * Otherwise, the first identifier is returned.
      * If the specified object contains no identifier, then this method returns {@code null}.
      *
      * @param  info The object to look for a preferred identifier, or {@code null} if none.
@@ -548,8 +542,8 @@ public class Formatter {
         final int numCol = matrix.getNumCol();
         final int openingBracket  = symbols.getOpeningBracket(0);
         final int closingBracket  = symbols.getClosingBracket(0);
-        final int openQuote       = symbols.getOpenQuote();
-        final int closeQuote      = symbols.getCloseQuote();
+        final int openQuote       = symbols.getOpeningQuote(0);
+        final int closeQuote      = symbols.getClosingQuote(0);
         final String separator    = symbols.getSeparator();
         final StringBuffer buffer = this.buffer;
         boolean columns = false;
@@ -601,7 +595,7 @@ public class Formatter {
                 if (contextUnit!=null && unit.isCompatible(contextUnit)) {
                     unit = contextUnit;
                 } else {
-                    contextUnit = convention.forcedAngularUnit;
+                    contextUnit = convention.getForcedUnit(Angle.class);
                     if (contextUnit == null) {
                         contextUnit = angularUnit;
                     }
@@ -710,7 +704,8 @@ public class Formatter {
      * Appends the given string as a quoted text.
      */
     private void quote(final String text) {
-        buffer.appendCodePoint(symbols.getOpenQuote()).append(text).appendCodePoint(symbols.getCloseQuote());
+        buffer.appendCodePoint(symbols.getOpeningQuote(0)).append(text)
+              .appendCodePoint(symbols.getClosingQuote(0));
     }
 
     /**
@@ -775,15 +770,15 @@ public class Formatter {
             appendSeparator(requestNewLine);
             buffer.append("UNIT").appendCodePoint(symbols.getOpeningBracket(0));
             setColor(ElementKind.UNIT);
-            buffer.appendCodePoint(symbols.getOpenQuote());
+            buffer.appendCodePoint(symbols.getOpeningQuote(0));
             if (NonSI.DEGREE_ANGLE.equals(unit)) {
                 buffer.append("degree");
             } else if (SI.METRE.equals(unit)) {
-                buffer.append(convention.unitUS ? "meter" : "metre");
+                buffer.append(convention.commonUnits ? "meter" : "metre");
             } else {
                 unitFormat.format(unit, buffer, dummy);
             }
-            buffer.appendCodePoint(symbols.getCloseQuote());
+            buffer.appendCodePoint(symbols.getClosingQuote(0));
             resetColor();
             append(Units.toStandardUnit(unit));
             buffer.appendCodePoint(symbols.getClosingBracket(0));
@@ -829,10 +824,9 @@ public class Formatter {
     }
 
     /**
-     * Returns {@code true} if the WKT written by this formatter is not strictly compliant to the
-     * <a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">WKT
-     * specification</a>. This method returns {@code true} if {@link #setInvalidWKT(IdentifiedObject)}
-     * has been invoked at least once. The action to take regarding invalid WKT is caller-dependent.
+     * Returns {@code true} if the WKT written by this formatter is not strictly compliant to the WKT specification.
+     * This method returns {@code true} if {@link #setInvalidWKT(IdentifiedObject)} has been invoked at least once.
+     * The action to take regarding invalid WKT is caller-dependent.
      * For example {@link FormattableObject#toString()} will accepts loose WKT formatting and ignore
      * this flag, while {@link FormattableObject#toWKT()} requires strict WKT formatting and will
      * thrown an exception if this flag is set.

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Symbols.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Symbols.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Symbols.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Symbols.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -34,15 +34,16 @@ import static org.apache.sis.util.Argume
  *   <li>An English locale for {@linkplain java.text.DecimalFormatSymbols decimal format symbols}.</li>
  *   <li>Square brackets, as in {@code DATUM["WGS84"]}. An alternative allowed by the WKT
  *       specification is curly brackets as in {@code DATUM("WGS84")}.</li>
- *   <li>English quotation mark ({@code '"'}).</li>
+ *   <li>English quotation mark ({@code '"'}). SIS also accepts {@code “…”} quotation marks
+ *       for more readable {@link String} constants in Java code.</li>
  *   <li>Coma separator followed by a space ({@code ", "}).</li>
  * </ul>
  *
- * {@note <b>Relationship between <code>Symbols</code> locale and <code>WKTFormat</code> locale</b><br>
- *        The <code>WKTFormat</code> <code>Locale</code> property specifies the language to use when
- *        formatting <code>InternationalString</code> instances. This can be set to any value.
- *        On the contrary, the <code>Locale</code> property of this <code>Symbols</code> class controls
- *        the decimal format symbols and is very rarely set to an other locale than an English one.}
+ * {@section Relationship between <code>Symbols</code> locale and <code>WKTFormat</code> locale}
+ * The {@link WKTFormat#getLocale()} property specifies the language to use when formatting
+ * {@link org.opengis.util.InternationalString} instances. This can be set to any value.
+ * On the contrary, the {@code Locale} property of this {@code Symbols} class controls
+ * the decimal format symbols and is very rarely set to an other locale than an English one.
  *
  * @author  Martin Desruisseaux (IRD)
  * @since   0.4 (derived from geotk-2.1)
@@ -62,19 +63,19 @@ public class Symbols implements Localize
      * A set of symbols with values between square brackets, like {@code DATUM["WGS84"]}.
      * This is the most frequently used WKT format.
      */
-    public static final Symbols SQUARE_BRACKETS = new Immutable('[', ']', '(', ')');
+    public static final Symbols SQUARE_BRACKETS = new Immutable(
+            new int[] {'[', ']', '(', ')'}, new int[] {'"', '"', '“', '”'});
 
     /**
      * A set of symbols with values between parentheses, like {@code DATUM("WGS84")}.
      * This is a less frequently used but legal WKT format.
      */
-    public static final Symbols CURLY_BRACKETS = new Immutable('(', ')', '[', ']');
+    public static final Symbols CURLY_BRACKETS = new Immutable(
+            new int[] {'(', ')', '[', ']'}, SQUARE_BRACKETS.quotes);
 
     /**
      * The default set of symbols, as documented in the class javadoc.
      * This is currently set to {@link #SQUARE_BRACKETS}.
-     *
-     * @see Colors#DEFAULT
      */
     public static final Symbols DEFAULT = SQUARE_BRACKETS;
 
@@ -100,16 +101,23 @@ public class Symbols implements Localize
     private int[] brackets;
 
     /**
-     * The character (as Unicode code point) used for opening ({@code openSequence})
-     * or closing ({@code closeSequence}) an array or enumeration.
+     * List of characters (as Unicode code point) used for opening or closing a quoted text.
+     * The array shall comply to the following restrictions:
+     *
+     * <ul>
+     *   <li>The characters at index 0 and 1 are the preferred opening and closing quotes respectively.</li>
+     *   <li>For each even index <var>i</var>, {@code quotes[i+1]} is the closing quote matching {@code quotes[i]}.</li>
+     * </ul>
+     *
+     * Both opening and closing quotes are usually {@code '"'}.
      */
-    private int openSequence, closeSequence;
+    private int[] quotes;
 
     /**
-     * The character (as Unicode code point) used for opening ({@code openQuote}) or
-     * closing ({@code closeQuote}) a quoted text. This is usually {@code '"'}.
+     * The character (as Unicode code point) used for opening ({@code openSequence})
+     * or closing ({@code closeSequence}) an array or enumeration.
      */
-    private int openQuote, closeQuote;
+    private int openSequence, closeSequence;
 
     /**
      * The string used as a separator in a list of values. This is usually {@code ", "},
@@ -132,10 +140,9 @@ public class Symbols implements Localize
     public Symbols(final Symbols symbols) {
         locale        = symbols.locale;
         brackets      = symbols.brackets;
+        quotes        = symbols.quotes;
         openSequence  = symbols.openSequence;
         closeSequence = symbols.closeSequence;
-        openQuote     = symbols.openQuote;
-        closeQuote    = symbols.closeQuote;
         separator     = symbols.separator;
     }
 
@@ -143,13 +150,12 @@ public class Symbols implements Localize
      * Constructor reserved to {@link #SQUARE_BRACKETS} and {@link #CURLY_BRACKETS} constants.
      * The given array is stored by reference - it is not cloned.
      */
-    private Symbols(final int[] brackets) {
+    private Symbols(final int[] brackets, final int[] quotes) {
         this.locale        = Locale.US;
         this.brackets      = brackets;
+        this.quotes        = quotes;
         this.openSequence  = '{';
         this.closeSequence = '}';
-        this.openQuote     = '"';
-        this.closeQuote    = '"';
         this.separator     = ", ";
     }
 
@@ -164,10 +170,10 @@ public class Symbols implements Localize
 
         /**
          * Constructor reserved to {@link Symbols#SQUARE_BRACKETS} and {@link Symbols#CURLY_BRACKETS} constants.
-         * The given array is stored by reference - it is not cloned.
+         * The given arrays are stored by reference - they are not cloned.
          */
-        Immutable(final int... brackets) {
-            super(brackets);
+        Immutable(final int[] brackets, final int[] quotes) {
+            super(brackets, quotes);
         }
 
         /**
@@ -246,12 +252,15 @@ public class Symbols implements Localize
 
     /**
      * Returns the number of paired brackets. For example if the WKT parser accepts both the
-     * {@code [ ]} and {@code ( )} paired brackets, then this method returns 2.
+     * {@code […]} and {@code (…)} bracket pairs, then this method returns 2.
      *
      * @return The number of bracket pairs.
+     *
+     * @see #getOpeningBracket(int)
+     * @see #getClosingBracket(int)
      */
-    public final int getNumPairedBracket() {
-        return brackets.length / 2;
+    public final int getNumPairedBrackets() {
+        return brackets.length >>> 1;
     }
 
     /**
@@ -259,12 +268,12 @@ public class Symbols implements Localize
      * Index 0 stands for the default bracket used at formatting time.
      * All other index are for optional brackets accepted at parsing time.
      *
-     * @param  index Index of the opening bracket to get, from 0 to {@link #getNumPairedBracket()} exclusive.
+     * @param  index Index of the opening bracket to get, from 0 to {@link #getNumPairedBrackets()} exclusive.
      * @return The opening bracket at the given index, as a Unicode code point.
      * @throws IndexOutOfBoundsException if the given index is out of bounds.
      */
     public final int getOpeningBracket(final int index) {
-        return brackets[index*2];
+        return brackets[index << 1];
     }
 
     /**
@@ -272,47 +281,116 @@ public class Symbols implements Localize
      * Index 0 stands for the default bracket used at formatting time.
      * All other index are for optional brackets accepted at parsing time.
      *
-     * @param  index Index of the closing bracket to get, from 0 to {@link #getNumPairedBracket()} exclusive.
+     * @param  index Index of the closing bracket to get, from 0 to {@link #getNumPairedBrackets()} exclusive.
      * @return The closing bracket at the given index, as a Unicode code point.
      * @throws IndexOutOfBoundsException if the given index is out of bounds.
      */
     public final int getClosingBracket(final int index) {
-        return brackets[index*2 + 1];
+        return brackets[(index << 1) | 1];
     }
 
     /**
-     * Sets the opening and closing brackets to the given characters.
-     * The given arrays shall comply to the following constraints:
+     * Sets the opening and closing brackets to the given pairs.
+     * Each string shall contain exactly two code points (usually two characters).
+     * The first code point is taken as the opening bracket, and the second code point as the closing bracket.
      *
-     * <ul>
-     *   <li>The two arrays shall be non-empty and have the same length.</li>
-     *   <li>The characters at index 0 are the preferred opening and closing brackets.</li>
-     *   <li>For each index <var>i</var>, {@code closingBrackets[i]} is the closing bracket
-     *       matching {@code openingBrackets[i]}.</li>
-     * </ul>
+     * {@example The following code will instruct the WKT formatter to use the <code>(…)</code> pair of brackets
+     *           at formatting time, but still accept the more common <code>[…]</code> pair of brackets at parsing
+     *           time:
+     *
+     *           <pre>setPairedBrackets("()", "[]");</pre>}
      *
-     * @param openingBrackets The opening brackets, as a Unicode code point.
-     * @param closingBrackets The closing brackets matching the opening ones.
+     * @param preferred The preferred pair of opening and closing quotes, used at formatting time.
+     * @param alternatives Alternative pairs of opening and closing quotes accepted at parsing time.
      */
-    public void setBrackets(final int[] openingBrackets, final int[] closingBrackets) {
+    public void setPairedBrackets(final String preferred, final String... alternatives) {
         checkWritePermission();
-        ensureNonNull("openingBrackets", openingBrackets);
-        ensureNonNull("closingBrackets", closingBrackets);
-        final int length = openingBrackets.length;
-        if (closingBrackets.length != length) {
-            throw new IllegalArgumentException(Errors.format(Errors.Keys.MismatchedArrayLengths));
-        }
-        if (length == 0) {
-            throw new IllegalArgumentException(Errors.format(Errors.Keys.EmptyArgument_1, "openingBrackets"));
-        }
-        final int[] brackets = new int[length * 2];
-        for (int i=0,j=0; i<length; i++) {
-            ensureValidUnicodeCodePoint("openingBrackets", openingBrackets[i]);
-            ensureValidUnicodeCodePoint("closingBrackets", closingBrackets[i]);
-            brackets[j++] = openingBrackets[i];
-            brackets[j++] = closingBrackets[i];
+        brackets = toCodePoints(preferred, alternatives);
+    }
+
+    /**
+     * Returns the number of paired quotes. For example if the WKT parser accepts both the
+     * {@code "…"} and {@code “…”} quote pairs, then this method returns 2.
+     *
+     * @return The number of quote pairs.
+     *
+     * @see #getOpeningQuote(int)
+     * @see #getClosingQuote(int)
+     */
+    public final int getNumPairedQuotes() {
+        return quotes.length >>> 1;
+    }
+
+    /**
+     * Returns the opening quote character at the given index.
+     * Index 0 stands for the default quote used at formatting time, which is usually {@code '"'}.
+     * All other index are for optional quotes accepted at parsing time.
+     *
+     * @param  index Index of the opening quote to get, from 0 to {@link #getNumPairedQuotes()} exclusive.
+     * @return The opening quote at the given index, as a Unicode code point.
+     * @throws IndexOutOfBoundsException if the given index is out of bounds.
+     */
+    public final int getOpeningQuote(final int index) {
+        return quotes[index << 1];
+    }
+
+    /**
+     * Returns the closing quote character at the given index.
+     * Index 0 stands for the default quote used at formatting time, which is usually {@code '"'}.
+     * All other index are for optional quotes accepted at parsing time.
+     *
+     * @param  index Index of the closing quote to get, from 0 to {@link #getNumPairedQuotes()} exclusive.
+     * @return The closing quote at the given index, as a Unicode code point.
+     * @throws IndexOutOfBoundsException if the given index is out of bounds.
+     */
+    public final int getClosingQuote(final int index) {
+        return quotes[(index << 1) | 1];
+    }
+
+    /**
+     * Sets the opening and closing quotes to the given pairs.
+     * Each string shall contain exactly two code points (usually two characters).
+     * The first code point is taken as the opening quote, and the second code point as the closing quote.
+     *
+     * {@example The following code will instruct the WKT formatter to use the prettier <code>“…”</code>
+     *           quotation marks at formatting time (especially useful for <code>String</code> constants
+     *           in Java code), but still accept the standard <code>"…"</code> quotation marks at parsing
+     *           time:
+     *
+     *           <pre>setPairedQuotes("“”", "\"\"");</pre>}
+     *
+     * @param preferred The preferred pair of opening and closing quotes, used at formatting time.
+     * @param alternatives Alternative pairs of opening and closing quotes accepted at parsing time.
+     */
+    public void setPairedQuotes(final String preferred, final String... alternatives) {
+        checkWritePermission();
+        quotes = toCodePoints(preferred, alternatives);
+    }
+
+    /**
+     * Packs the given pairs of bracket or quotes in a single array of code points.
+     * This method also verifies arguments validity.
+     */
+    private static int[] toCodePoints(final String preferred, final String[] alternatives) {
+        ensureNonNull("preferred", preferred);
+        final int n = (alternatives != null) ? alternatives.length : 0;
+        final int[] array = new int[(n+1) * 2];
+        String name = "preferred";
+        String pair = preferred;
+        int i=0, j=0;
+        while (true) {
+            if (pair.codePointCount(0, pair.length()) != 2) {
+                throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2, name, pair));
+            }
+            final int c = pair.codePointAt(0);
+            ensureValidUnicodeCodePoint(name, array[j++] = c);
+            ensureValidUnicodeCodePoint(name, array[j++] = pair.codePointAt(Character.charCount(c)));
+            if (i >= n) {
+                break;
+            }
+            ensureNonNullElement(name = "alternatives", i, pair = alternatives[i++]);
         }
-        this.brackets = brackets; // Store only on success.
+        return array;
     }
 
     /**
@@ -350,38 +428,6 @@ public class Symbols implements Localize
     }
 
     /**
-     * Returns the character used for opening a quoted text. This is usually {@code '"'}.
-     *
-     * @return The character used for opening a quoted text, as a Unicode code point.
-     */
-    public final int getOpenQuote() {
-        return openQuote;
-    }
-
-    /**
-     * Returns the character used for closing a quoted text. This is usually {@code '"'}.
-     *
-     * @return The character used for closing a quoted text, as a Unicode code point.
-     */
-    public final int getCloseQuote() {
-        return closeQuote;
-    }
-
-    /**
-     * Sets the characters used for opening and closing a quoted text.
-     *
-     * @param openQuote  The character for opening a quoted text, as a Unicode code point.
-     * @param closeQuote The character for closing a quoted text, as a Unicode code point.
-     */
-    public void setQuotes(final int openQuote, final int closeQuote) {
-        checkWritePermission();
-        ensureValidUnicodeCodePoint("openQuote",  openQuote);
-        ensureValidUnicodeCodePoint("closeQuote", closeQuote);
-        this.openQuote  = openQuote;
-        this.closeQuote = closeQuote;
-    }
-
-    /**
      * Returns the string used as a separator in a list of values. This is usually {@code ", "},
      * but may be different if a non-English locale is used for formatting numbers.
      *
@@ -428,8 +474,8 @@ public class Symbols implements Localize
      *
      * <ul>
      *   <li>The search is case-insensitive.</li>
-     *   <li>Characters between the {@linkplain #getOpenQuote() open quote} and the
-     *       {@linkplain #getCloseQuote() close quote} are ignored.</li>
+     *   <li>Characters between {@linkplain #getOpeningQuote(int) opening quotes} and
+     *       {@linkplain #getClosingQuote(int) closing quotes} are ignored.</li>
      *   <li>The element found in the given WKT can not be preceded by other
      *       {@linkplain Character#isUnicodeIdentifierPart(int) Unicode identifier characters}.</li>
      *   <li>The element found in the given WKT must be followed, ignoring space, by an
@@ -457,12 +503,12 @@ public class Symbols implements Localize
      * Invoking this method is equivalent to invoking
      * <code>{@linkplain #containsElement(CharSequence, String) containsElement}(wkt, "AXIS")</code>.
      *
-     * <p>The check for axis elements is of particular interest because the axis order is a frequent cause
+     * {@section Use case}
+     * The check for axis elements is of particular interest because the axis order is a frequent cause
      * of confusion when processing geographic data. Some applications just ignore any declared axis order
      * in favor of their own hard-coded (<var>longitude</var>, <var>latitude</var>) axis order.
      * Consequently, the presence of {@code AXIS[…]} elements in a WKT is an indication that the encoded
      * object may not be understood as intended by some external softwares.
-     * See for example {@link Convention#ESRI}.</p>
      *
      * @param  wkt The WKT to inspect.
      * @return {@code true} if the given WKT contains at least one instance of the {@code AXIS[…]} element.
@@ -480,12 +526,22 @@ public class Symbols implements Localize
      * @param  offset  The index to start the search from.
      */
     private boolean containsElement(final CharSequence wkt, final String element, int offset) {
+        final int[] quotes = this.quotes;
         final int length = wkt.length();
         boolean isQuoting = false;
+        int closeQuote = 0;
         while (offset < length) {
             int c = Character.codePointAt(wkt, offset);
-            if (c == (isQuoting ? closeQuote : openQuote)) {
-                isQuoting = !isQuoting;
+            if (closeQuote != 0) {
+                if (c == closeQuote) {
+                    isQuoting = false;
+                }
+            } else for (int i=0; i<quotes.length; i+=2) {
+                if (c == quotes[i]) {
+                    closeQuote = quotes[i | 1];
+                    isQuoting = true;
+                    break;
+                }
             }
             if (!isQuoting && Character.isUnicodeIdentifierStart(c)) {
                 /*

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/UnformattableObjectException.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/UnformattableObjectException.java?rev=1562800&r1=1562799&r2=1562800&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/UnformattableObjectException.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/UnformattableObjectException.java [UTF-8] Thu Jan 30 12:37:10 2014
@@ -21,7 +21,8 @@ import org.opengis.referencing.Identifie
 
 /**
  * Thrown by {@link FormattableObject#toWKT()} when an object can not be formatted as WKT.
- * A formatting may fail because an object is too complex for the WKT format capability.
+ * A formatting may fail because an object contains properties which can not be represented
+ * by the standard WKT elements.
  *
  * {@example An engineering CRS can not be represented in the WKT 1 format if all axes
  *           do not use the same unit of measurement. However such CRS can be represented



Mime
View raw message