sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1677070 [2/3] - in /sis/branches/JDK7: ./ core/sis-feature/src/main/java/org/apache/sis/feature/ core/sis-feature/src/test/java/org/apache/sis/feature/ core/sis-feature/src/test/java/org/apache/sis/test/suite/ core/sis-metadata/src/main/ja...
Date Thu, 30 Apr 2015 20:57:37 GMT
Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -168,10 +168,11 @@ public class Formatter implements Locali
     private Citation authority;
 
     /**
-     * {@code true} for preserving non-ASCII characters. The default value is {@code false},
-     * which causes replacements like "é" → "e" in all elements except {@code REMARKS["…"]}.
+     * {@link CharEncoding#UNICODE} for preserving non-ASCII characters. The default value is
+     * {@link CharEncoding#DEFAULT}, which causes replacements like "é" → "e" in all elements
+     * except {@code REMARKS["…"]}. May also be a user-supplied encoding.
      */
-    boolean isNonAsciiAllowed;
+    CharEncoding encoding;
 
     /**
      * The enclosing WKT element being formatted.
@@ -383,7 +384,7 @@ public class Formatter implements Locali
         this.colors       = colors;
         this.toUpperCase  = toUpperCase;
         this.indentation  = indentation;
-        isNonAsciiAllowed = (convention == Convention.INTERNAL);
+        this.encoding     = (convention == Convention.INTERNAL) ? CharEncoding.UNICODE : CharEncoding.DEFAULT;
     }
 
     /**
@@ -399,6 +400,28 @@ public class Formatter implements Locali
     }
 
     /**
+     * Returns a mapper between Java character sequences and the characters to write in WKT.
+     * The intend is to specify how to write characters that are not allowed in WKT strings
+     * according ISO 19162 specification. Return values can be:
+     *
+     * <ul>
+     *   <li>{@link CharEncoding#DEFAULT} for performing replacements like "é" → "e"
+     *       in all WKT elements except {@code REMARKS["…"]}.</li>
+     *   <li>{@link CharEncoding#UNICODE} for preserving non-ASCII characters.</li>
+     *   <li>Any other user-supplied mapping.</li>
+     * </ul>
+     *
+     * @return The mapper between Java character sequences and the characters to write in WKT.
+     *
+     * @see WKTFormat#setCharEncoding(CharEncoding)
+     *
+     * @since 0.6
+     */
+    public final CharEncoding getCharEncoding() {
+        return encoding;
+    }
+
+    /**
      * Returns the preferred authority for choosing the projection and parameter names.
      *
      * <p>The preferred authority can be set by the {@link WKTFormat#setNameAuthority(Citation)} method.
@@ -927,10 +950,10 @@ public class Formatter implements Locali
     private void quote(final String text, final ElementKind type) {
         setColor(type);
         final int base = buffer.appendCodePoint(symbols.getOpeningQuote(0)).length();
-        if (isNonAsciiAllowed || (type == ElementKind.REMARKS)) {
+        if (type == ElementKind.REMARKS) {
             buffer.append(text);
         } else {
-            buffer.append(CharSequences.toASCII(text));
+            buffer.append(encoding.filter(text));
         }
         closeQuote(base);
         resetColor();
@@ -1104,7 +1127,9 @@ public class Formatter implements Locali
             openElement(false, keyword);
             setColor(ElementKind.UNIT);
             final int fromIndex = buffer.appendCodePoint(symbols.getOpeningQuote(0)).length();
-            if (NonSI.DEGREE_ANGLE.equals(unit)) {
+            if (Unit.ONE.equals(unit)) {
+                buffer.append("unity");
+            } else if (NonSI.DEGREE_ANGLE.equals(unit)) {
                 buffer.append("degree");
             } else if (SI.METRE.equals(unit)) {
                 buffer.append(convention.usesCommonUnits() ? "meter" : "metre");

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -41,10 +41,11 @@ import org.apache.sis.util.resources.Err
  * {@code WKTFormat} objects allow the following configuration:
  *
  * <ul>
- *   <li>The {@linkplain Symbols symbols} to use (curly braces or brackets, <i>etc</i>).</li>
  *   <li>The preferred authority of {@linkplain IdentifiedObject#getName() object name} to
  *       format (see {@link Formatter#getNameAuthority()} for more information).</li>
- *   <li>Whatever ANSI X3.64 colors are allowed or not (default is not).</li>
+ *   <li>The {@linkplain Symbols symbols} to use (curly braces or brackets, <i>etc</i>).</li>
+ *   <li>The {@linkplain CharEncoding character encoding} (i.e. replacements to use for Unicode characters).</li>
+ *   <li>Whether ANSI X3.64 colors are allowed or not (default is not).</li>
  *   <li>The indentation.</li>
  * </ul>
  *
@@ -78,7 +79,7 @@ import org.apache.sis.util.resources.Err
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Rémi Eve (IRD)
  * @since   0.4
- * @version 0.5
+ * @version 0.6
  * @module
  */
 public class WKTFormat extends CompoundFormat<Object> {
@@ -146,10 +147,13 @@ public class WKTFormat extends CompoundF
     private KeywordCase keywordCase;
 
     /**
-     * {@code true} for preserving non-ASCII characters. The default value is {@code false},
-     * which causes replacements like "é" → "e" in all elements except {@code REMARKS["…"]}.
+     * {@link CharEncoding#UNICODE} for preserving non-ASCII characters. The default value is
+     * {@link CharEncoding#DEFAULT}, which causes replacements like "é" → "e" in all elements
+     * except {@code REMARKS["…"]}. May also be a user-supplied encoding.
+     *
+     * <p>A {@code null} value means to infer this property from the {@linkplain #convention}.</p>
      */
-    private boolean isNonAsciiAllowed;
+    private CharEncoding encoding;
 
     /**
      * The amount of spaces to use in indentation, or {@value #SINGLE_LINE} if indentation is disabled.
@@ -224,6 +228,45 @@ public class WKTFormat extends CompoundF
     }
 
     /**
+     * Returns a mapper between Java character sequences and the characters to write in WKT.
+     * The intend is to specify how to write characters that are not allowed in WKT strings
+     * according ISO 19162 specification. Return values can be:
+     *
+     * <ul>
+     *   <li>{@link CharEncoding#DEFAULT} for performing replacements like "é" → "e"
+     *       in all WKT elements except {@code REMARKS["…"]}.</li>
+     *   <li>{@link CharEncoding#UNICODE} for preserving non-ASCII characters.</li>
+     *   <li>Any other user-supplied mapping.</li>
+     * </ul>
+     *
+     * @return The mapper between Java character sequences and the characters to write in WKT.
+     *
+     * @since 0.6
+     */
+    public CharEncoding getCharEncoding() {
+        CharEncoding result = encoding;
+        if (result == null) {
+            result = (convention == Convention.INTERNAL) ? CharEncoding.UNICODE : CharEncoding.DEFAULT;
+        }
+        return result;
+    }
+
+    /**
+     * Sets the mapper between Java character sequences and the characters to write in WKT.
+     *
+     * <p>If this method is never invoked, or if this method is invoked with a {@code null} value,
+     * then the default mapper is {@link CharEncoding#DEFAULT} except for WKT formatted according
+     * the {@linkplain Convention#INTERNAL internal convention}.</p>
+     *
+     * @param encoding The new mapper to use, or {@code null} for restoring the default value.
+     *
+     * @since 0.6
+     */
+    public void setCharEncoding(final CharEncoding encoding) {
+        this.encoding = encoding;
+    }
+
+    /**
      * Returns whether non-ASCII characters are preserved. The default value is {@code false},
      * which causes replacements like "é" → "e" in all elements except {@link ElementKind#REMARKS}.
      *
@@ -233,9 +276,12 @@ public class WKTFormat extends CompoundF
      * @return Whether non-ASCII characters are preserved.
      *
      * @since 0.5
+     *
+     * @deprecated Replaced by {@link #getCharEncoding()}.
      */
+    @Deprecated
     public boolean isNonAsciiAllowed() {
-        return isNonAsciiAllowed || (convention == Convention.INTERNAL);
+        return getCharEncoding() == CharEncoding.UNICODE;
     }
 
     /**
@@ -246,9 +292,12 @@ public class WKTFormat extends CompoundF
      * @param allowed Whether non-ASCII characters shall be preserved.
      *
      * @since 0.5
+     *
+     * @deprecated Replaced by {@link #setCharEncoding(CharEncoding)}.
      */
+    @Deprecated
     public void setNonAsciiAllowed(final boolean allowed) {
-        isNonAsciiAllowed = allowed;
+        setCharEncoding(allowed ? CharEncoding.UNICODE : CharEncoding.DEFAULT);
     }
 
     /**
@@ -381,7 +430,9 @@ public class WKTFormat extends CompoundF
                 default: toUpperCase = (convention.majorVersion() == 1); break;
             }
             formatter.configure(convention, authority, colors, toUpperCase, indentation);
-            formatter.isNonAsciiAllowed |= isNonAsciiAllowed;
+            if (encoding != null) {
+                formatter.encoding = encoding;
+            }
         }
     }
 

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -541,19 +541,30 @@ public class ImmutableIdentifier extends
     @Override
     protected String formatTo(final Formatter formatter) {
         String keyword = null;
+        /*
+         * The code, codeSpace, authority and version local variables in this method usually have the exact same
+         * value than the fields of the same name in this class.  But we get those values by invoking the public
+         * methods in order to give to users a chance to override those properties.  The intend is also to use a
+         * consistent approach for all 'formatTo' implementations, since some other classes have no choice other
+         * than using the public methods.
+         */
+        final String code = getCode();
         if (code != null) {
+            final String   codeSpace = getCodeSpace();
+            final Citation authority = getAuthority();
             final String cs = (codeSpace != null) ? codeSpace :
                     org.apache.sis.internal.util.Citations.getIdentifier(authority, true);
             if (cs != null) {
                 final Convention convention = formatter.getConvention();
                 if (convention.majorVersion() == 1) {
                     keyword = "Authority";
-                    formatter.append(cs, ElementKind.IDENTIFIER);
+                    formatter.append(cs,   ElementKind.IDENTIFIER);
                     formatter.append(code, ElementKind.IDENTIFIER);
                 } else {
                     keyword = "Id";
                     formatter.append(cs, ElementKind.IDENTIFIER);
                     appendCode(formatter, code);
+                    final String version = getVersion();
                     if (version != null) {
                         appendCode(formatter, version);
                     }

Modified: sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/FormatterTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/FormatterTest.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/FormatterTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/FormatterTest.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -58,6 +58,9 @@ public final strictfp class FormatterTes
     @Test
     public void testQuote() {
         assertWktEquals(Convention.WKT2,
+                "“A \"quote\" to replace”",             // Expect replacement of non-latin characters.
+                 "A “quote” to replace");
+        assertWktEquals(Convention.INTERNAL,
                 "“A “quote”” to double”",               // Expect doubling quotes.
                  "A “quote” to double");
         assertWktEquals(Convention.WKT2,

Modified: sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -93,6 +93,7 @@ import org.junit.BeforeClass;
 
     org.apache.sis.io.wkt.ConventionTest.class,
     org.apache.sis.io.wkt.SymbolsTest.class,
+    org.apache.sis.io.wkt.CharEncodingTest.class,
     org.apache.sis.io.wkt.ColorsTest.class,
     org.apache.sis.io.wkt.FormatterTest.class,
     org.apache.sis.io.wkt.WKTFormatTest.class

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/OperationMethods.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/OperationMethods.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/OperationMethods.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/OperationMethods.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -16,20 +16,17 @@
  */
 package org.apache.sis.internal.referencing;
 
-import java.util.Map;
-import org.opengis.metadata.Identifier;
-import org.opengis.metadata.citation.Citation;
-import org.opengis.referencing.operation.Matrix;
-import org.opengis.referencing.operation.MathTransform;
-import org.opengis.referencing.operation.OperationMethod;
-import org.apache.sis.referencing.AbstractIdentifiedObject;
-import org.apache.sis.referencing.operation.transform.MathTransforms;
-import org.apache.sis.referencing.operation.transform.PassThroughTransform;
-import org.apache.sis.internal.util.Citations;
-import org.apache.sis.util.resources.Errors;
-import org.apache.sis.util.CharSequences;
-import org.apache.sis.util.Characters;
+import java.util.Collection;
+import org.opengis.util.Record;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+import javax.measure.quantity.Length;
+import org.opengis.metadata.quality.Result;
+import org.opengis.metadata.quality.PositionalAccuracy;
+import org.opengis.metadata.quality.QuantitativeResult;
+import org.opengis.referencing.operation.*;
 import org.apache.sis.util.Static;
+import org.apache.sis.measure.Units;
 
 
 /**
@@ -38,173 +35,116 @@ import org.apache.sis.util.Static;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.6
  * @module
  */
 public final class OperationMethods extends Static {
     /**
-     * Do not allow instantiation of this class.
+     * The key for specifying explicitely the value to be returned by
+     * {@link org.apache.sis.referencing.operation.DefaultSingleOperation#getParameterValues()}.
+     * It is usually not necessary to specify those parameters because they are inferred either from
+     * the {@link MathTransform}, or specified explicitely in a {@code DefiningConversion}. However
+     * there is a few cases, for example the Molodenski transform, where none of the above can apply,
+     * because SIS implements those operations as a concatenation of math transforms, and such
+     * concatenations do not have {@link org.opengis.parameter.ParameterValueGroup}.
      */
-    private OperationMethods() {
-    }
+    public static final String PARAMETERS_KEY = "parameters";
 
     /**
-     * Determines whether a match or mismatch is found between the two given collections of identifiers.
-     * If any of the given collections is {@code null} or empty, this method returns {@code null}.
-     *
-     * <p>According ISO 19162 (<cite>Well known text representation of coordinate reference systems</cite>),
-     * {@linkplain AbstractIdentifiedObject#getIdentifier() identifiers} should have precedence over
-     * {@linkplain AbstractIdentifiedObject#getName() name} for identifying {@code IdentifiedObject}s,
-     * at least in the case of {@linkplain org.apache.sis.referencing.operation.DefaultOperationMethod
-     * operation methods} and {@linkplain org.apache.sis.parameter.AbstractParameterDescriptor parameters}.</p>
-     *
-     * @param  id1 The first collection of identifiers, or {@code null}.
-     * @param  id2 The second collection of identifiers, or {@code null}.
-     * @return {@code TRUE} or {@code FALSE} on match or mismatch respectively, or {@code null} if this method
-     *         can not determine if there is a match or mismatch.
-     */
-    public static Boolean hasCommonIdentifier(final Iterable<? extends Identifier> id1,
-                                              final Iterable<? extends Identifier> id2)
-    {
-        if (id1 != null && id2 != null) {
-            boolean hasFound = false;
-            for (final Identifier identifier : id1) {
-                final Citation authority = identifier.getAuthority();
-                final String   codeSpace = identifier.getCodeSpace();
-                for (final Identifier other : id2) {
-                    if (authorityMatches(identifier, authority, codeSpace)) {
-                        if (CharSequences.equalsFiltered(identifier.getCode(), other.getCode(), Characters.Filter.UNICODE_IDENTIFIER, true)) {
-                            return Boolean.TRUE;
-                        }
-                        hasFound = true;
-                    }
-                }
-            }
-            if (hasFound) {
-                return Boolean.FALSE;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Returns {@code true} if the given identifier authority matches the given {@code authority}.
-     * If one of the authority is null, then the comparison fallback on the given {@code codeSpace}.
-     * If the code spaces are also null, then this method conservatively returns {@code false}.
-     *
-     * @param  identifier The identifier to compare.
-     * @param  authority  The desired authority, or {@code null}.
-     * @param  codeSpace  The desired code space or {@code null}, used as a fallback if an authority is null.
-     * @return {@code true} if the authority or code space (as a fallback only) matches.
+     * Do not allow instantiation of this class.
      */
-    private static boolean authorityMatches(final Identifier identifier, final Citation authority, final String codeSpace) {
-        if (authority != null) {
-            final Citation other = identifier.getAuthority();
-            if (other != null) {
-                return Citations.identifierMatches(authority, other);
-            }
-        }
-        if (codeSpace != null) {
-            final String other = identifier.getCodeSpace();
-            if (other != null) {
-                return CharSequences.equalsFiltered(codeSpace, other, Characters.Filter.UNICODE_IDENTIFIER, true);
-            }
-        }
-        return false;
+    private OperationMethods() {
     }
 
     /**
-     * Checks if an operation method and a math transform have a compatible number of source and target dimensions.
-     * In the particular case of a {@linkplain PassThroughTransform pass through transform} with more dimensions
-     * than what we would expect from the given method, the check will rather be performed against the
-     * {@linkplain PassThroughTransform#getSubTransform() sub transform}.
-     *
-     * <p>The intend is to allow creation of a three-dimensional {@code ProjectedCRS} with a two-dimensional
-     * {@code OperationMethod}, where the third-dimension just pass through. This is not a recommended approach
-     * and we do not document that as a supported feature, but we do not prevent it neither.</p>
-     *
-     * <p>This method tries to locates what seems to be the "core" of the given math transform. The definition
-     * of "core" is imprecise and may be adjusted in future SIS versions. The current algorithm is as below:</p>
+     * Convenience method returning the accuracy in meters for the specified operation.
+     * This method tries each of the following procedures and returns the first successful one:
      *
      * <ul>
-     *   <li>If the given transform can be decomposed in {@linkplain MathTransforms#getSteps(MathTransform) steps},
-     *       then the steps for {@linkplain org.apache.sis.referencing.cs.CoordinateSystems#swapAndScaleAxes axis
-     *       swapping and scaling} are ignored.</li>
-     *   <li>If the given transform or its non-ignorable step is a {@link PassThroughTransform}, then its sub-transform
-     *       is taken. Only one non-ignorable step may exist, otherwise we do not try to select any of them.</li>
+     *   <li>If a {@link QuantitativeResult} is found with a linear unit, then this accuracy estimate
+     *       is converted to {@linkplain SI#METRE metres} and returned.</li>
+     *   <li>Otherwise, if the operation is a {@link Conversion}, then returns 0 since a conversion
+     *       is by definition accurate up to rounding errors.</li>
+     *   <li>Otherwise, if the operation is a {@link Transformation}, then checks if the datum shift
+     *       were applied with the help of Bursa-Wolf parameters. This procedure looks for SIS-specific
+     *       {@link PositionalAccuracyConstant#DATUM_SHIFT_APPLIED} and
+     *       {@link PositionalAccuracyConstant#DATUM_SHIFT_OMITTED DATUM_SHIFT_OMITTED} constants.</li>
+     *   <li>Otherwise, if the operation is a {@link ConcatenatedOperation}, returns the sum of the accuracy
+     *       of all components. This is a conservative scenario where we assume that errors cumulate linearly.
+     *       Note that this is not necessarily the "worst case" scenario since the accuracy could be worst
+     *       if the math transforms are highly non-linear.</li>
      * </ul>
      *
-     * @param  method     The operation method to compare to the math transform.
-     * @param  transform  The math transform to compare to the operation method.
-     * @param  properties Properties of the caller object being constructed, used only for formatting error message.
-     * @throws IllegalArgumentException if the number of dimensions are incompatible.
+     * If the above is modified, please update {@code AbstractCoordinateOperation.getLinearAccuracy()} javadoc.
+     *
+     * @param  operation The operation to inspect for accuracy.
+     * @return The accuracy estimate (always in meters), or NaN if unknown.
+     *
+     * @see org.apache.sis.referencing.operation.AbstractCoordinateOperation#getLinearAccuracy()
      */
-    public static void checkDimensions(final OperationMethod method, MathTransform transform,
-            final Map<String,?> properties) throws IllegalArgumentException
-    {
-        int actual = transform.getSourceDimensions();
-        Integer expected = method.getSourceDimensions();
-        if (expected != null && actual > expected) {
-            /*
-             * The given MathTransform use more dimensions than the OperationMethod.
-             * Try to locate one and only one sub-transform, ignoring axis swapping and scaling.
-             */
-            MathTransform subTransform = null;
-            for (final MathTransform step : MathTransforms.getSteps(transform)) {
-                if (!isIgnorable(step)) {
-                    if (subTransform == null && step instanceof PassThroughTransform) {
-                        subTransform = ((PassThroughTransform) step).getSubTransform();
-                    } else {
-                        subTransform = null;
-                        break;
+    public static double getLinearAccuracy(final CoordinateOperation operation) {
+        final Collection<PositionalAccuracy> accuracies = operation.getCoordinateOperationAccuracy();
+        for (final PositionalAccuracy accuracy : accuracies) {
+            for (final Result result : accuracy.getResults()) {
+                if (result instanceof QuantitativeResult) {
+                    final QuantitativeResult quantity = (QuantitativeResult) result;
+                    final Collection<? extends Record> records = quantity.getValues();
+                    if (records != null) {
+                        final Unit<?> unit = quantity.getValueUnit();
+                        if (Units.isLinear(unit)) {
+                            final Unit<Length> unitOfLength = unit.asType(Length.class);
+                            for (final Record record : records) {
+                                for (final Object value : record.getAttributes().values()) {
+                                    if (value instanceof Number) {
+                                        double v = ((Number) value).doubleValue();
+                                        v = unitOfLength.getConverterTo(SI.METRE).convert(v);
+                                        return v;
+                                    }
+                                }
+                            }
+                        }
                     }
                 }
             }
-            if (subTransform != null) {
-                transform = subTransform;
-                actual = transform.getSourceDimensions();
-            }
         }
         /*
-         * Now verify if the MathTransform dimensions are equal to the OperationMethod ones,
-         * ignoring null java.lang.Integer instances.
+         * No quantitative (linear) accuracy were found. If the coordinate operation is actually
+         * a conversion, the accuracy is up to rounding error (i.e. conceptually 0) by definition.
+         */
+        if (operation instanceof Conversion) {
+            return 0;
+        }
+        /*
+         * If the coordinate operation is actually a transformation, checks if Bursa-Wolf parameters
+         * were available for the datum shift. This is SIS-specific. See field javadoc for a rational
+         * about the return values chosen.
          */
-        byte isTarget = 0; // false: wrong dimension is the source one.
-        if (expected == null || actual == expected) {
-            actual = transform.getTargetDimensions();
-            expected = method.getTargetDimensions();
-            if (expected == null || actual == expected) {
-                return;
+        if (operation instanceof Transformation) {
+            if (!accuracies.contains(PositionalAccuracyConstant.DATUM_SHIFT_OMITTED)) {
+                if (accuracies.contains(PositionalAccuracyConstant.DATUM_SHIFT_APPLIED)) {
+                    return PositionalAccuracyConstant.DATUM_SHIFT_ACCURACY;
+                }
             }
-            isTarget = 1; // true: wrong dimension is the target one.
+            return PositionalAccuracyConstant.UNKNOWN_ACCURACY;
         }
-        throw new IllegalArgumentException(Errors.getResources(properties).getString(
-                Errors.Keys.MismatchedTransformDimension_3, isTarget, expected, actual));
-    }
-
-    /**
-     * Returns {@code true} if the specified transform is likely to exists only for axis swapping
-     * and/or unit conversions. The heuristic rule checks if the transform is backed by a square
-     * matrix with exactly one non-null value in each row and each column.
-     */
-    private static boolean isIgnorable(final MathTransform transform) {
-        final Matrix matrix = MathTransforms.getMatrix(transform);
-        if (matrix != null) {
-            final int size = matrix.getNumRow();
-            if (matrix.getNumCol() == size) {
-                for (int j=0; j<size; j++) {
-                    int n1=0, n2=0;
-                    for (int i=0; i<size; i++) {
-                        if (matrix.getElement(j,i) != 0) n1++;
-                        if (matrix.getElement(i,j) != 0) n2++;
-                    }
-                    if (n1 != 1 || n2 != 1) {
-                        return false;
+        /*
+         * If the coordinate operation is a compound of other coordinate operations, returns the sum of their accuracy,
+         * skipping unknown ones. Making the sum is a conservative approach (not exactly the "worst case" scenario,
+         * since it could be worst if the transforms are highly non-linear).
+         */
+        double accuracy = Double.NaN;
+        if (operation instanceof ConcatenatedOperation) {
+            for (final SingleOperation op : ((ConcatenatedOperation) operation).getOperations()) {
+                final double candidate = Math.abs(getLinearAccuracy(op));
+                if (!Double.isNaN(candidate)) {
+                    if (Double.isNaN(accuracy)) {
+                        accuracy = candidate;
+                    } else {
+                        accuracy += candidate;
                     }
                 }
-                return true;
             }
         }
-        return false;
+        return accuracy;
     }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/PositionalAccuracyConstant.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/PositionalAccuracyConstant.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/PositionalAccuracyConstant.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/PositionalAccuracyConstant.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -34,7 +34,7 @@ import org.apache.sis.util.resources.Mes
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.6
  * @module
  *
  * @see org.opengis.referencing.operation.Transformation#getCoordinateOperationAccuracy()
@@ -47,6 +47,28 @@ public final class PositionalAccuracyCon
     private static final long serialVersionUID = -2554090935254116470L;
 
     /**
+     * Presumed worst case error when no datum shift information was found.
+     * The highest value found in the EPSG database 6.7 is 999 metres (worst datum shift), so this error
+     * should be yet higher. I have seen 3 kilometres mentioned in some documentation somewhere.
+     *
+     * <p>If this value is modified, please update {@code getLinearAccuracy()} public javadoc accordingly.</p>
+     *
+     * @see org.apache.sis.referencing.operation.AbstractCoordinateOperation#getLinearAccuracy()
+     */
+    public static final double UNKNOWN_ACCURACY = 3000;
+
+    /**
+     * Default accuracy of datum shift, if not explicitly provided in the EPSG database.
+     * The 25 meters value is the next highest value (after 999 metres) found in the EPSG
+     * database version 6.7 for a significant number of transformations.
+     *
+     * <p>If this value is modified, please update {@code getLinearAccuracy()} public javadoc accordingly.</p>
+     *
+     * @see org.apache.sis.referencing.operation.AbstractCoordinateOperation#getLinearAccuracy()
+     */
+    public static final double DATUM_SHIFT_ACCURACY = 25;
+
+    /**
      * Indicates that a {@linkplain org.opengis.referencing.operation.Transformation transformation}
      * requires a datum shift and some method has been applied. Datum shift methods often use
      * {@linkplain org.apache.sis.referencing.datum.BursaWolfParameters Bursa Wolf parameters},

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -19,6 +19,7 @@ package org.apache.sis.internal.referenc
 import java.util.Collection;
 import java.util.logging.Logger;
 import javax.measure.unit.Unit;
+import javax.measure.unit.NonSI;
 import javax.measure.quantity.Angle;
 import org.opengis.annotation.UML;
 import org.opengis.annotation.Specification;
@@ -36,6 +37,7 @@ import org.apache.sis.referencing.Common
 import org.apache.sis.referencing.datum.DefaultPrimeMeridian;
 import org.apache.sis.referencing.crs.DefaultGeographicCRS;
 import org.apache.sis.referencing.cs.AxesConvention;
+import org.apache.sis.measure.Units;
 
 import static java.util.Collections.singletonMap;
 import static org.apache.sis.internal.util.Numerics.epsilonEqual;
@@ -106,6 +108,32 @@ public final class ReferencingUtilities
     }
 
     /**
+     * Returns the angular unit of the specified coordinate system.
+     * The preference will be given to the longitude axis, if found.
+     *
+     * @param  cs The coordinate system from which to get the angular unit, or {@code null}.
+     * @return The angular unit, of {@link NonSI#DEGREE_ANGLE} if no angular unit was found.
+     *
+     * @since 0.6
+     */
+    public static Unit<Angle> getAngularUnit(final CoordinateSystem cs) {
+        Unit<Angle> unit = NonSI.DEGREE_ANGLE;
+        if (cs != null) {
+            for (int i = cs.getDimension(); --i>=0;) {
+                final CoordinateSystemAxis axis = cs.getAxis(i);
+                final Unit<?> candidate = axis.getUnit();
+                if (Units.isAngular(candidate)) {
+                    unit = candidate.asType(Angle.class);
+                    if (AxisDirection.EAST.equals(AxisDirections.absolute(axis.getDirection()))) {
+                        break; // Found the longitude axis.
+                    }
+                }
+            }
+        }
+        return unit;
+    }
+
+    /**
      * 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}.
      *

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ParameterizedAffine.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ParameterizedAffine.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ParameterizedAffine.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ParameterizedAffine.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -104,7 +104,8 @@ public final class ParameterizedAffine e
      */
     @Override
     public ParameterDescriptorGroup getParameterDescriptors() {
-        return isDefinitive ? parameters.getDescriptor() : super.getParameterDescriptors();
+        return isDefinitive || Semaphores.query(Semaphores.PROJCS)  // See comment in getParameterValues().
+               ? parameters.getDescriptor() : super.getParameterDescriptors();
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -115,6 +115,8 @@ abstract class AbstractProvider extends
 
     /**
      * Creates a descriptor for a constant value in degrees.
+     *
+     * @see MapProjection#validate(ParameterDescriptor, double)
      */
     static ParameterDescriptor<Double> createConstant(final ParameterBuilder builder, final Double constant) {
         return builder.createBounded(MeasurementRange.create(constant, true, constant, true, NonSI.DEGREE_ANGLE), constant);

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -132,6 +132,8 @@ public abstract class MapProjection exte
      * @param  descriptor The descriptor that specify the parameter to validate.
      * @param  value The parameter value in the units given by the descriptor.
      * @throws IllegalArgumentException if the given value is out of bounds.
+     *
+     * @see #createConstant(ParameterBuilder, Double)
      */
     public static void validate(final ParameterDescriptor<Double> descriptor, final double value)
             throws IllegalArgumentException
@@ -149,6 +151,8 @@ public abstract class MapProjection exte
              * because of the way the map projection is defined (see e.g. Mercator1SP.LATITUDE_OF_ORIGIN).
              * But in some cases, it would be possible to deal with non-zero values, even if in principle
              * we should not. In such case we let the caller decides.
+             *
+             * Above check should be revisited if createConstant(ParameterBuilder, Double) is modified.
              */
             if ((min instanceof Number && !(value >= ((Number) min).doubleValue())) ||
                 (max instanceof Number && !(value <= ((Number) max).doubleValue())))

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -827,6 +827,7 @@ public class DefaultParameterValue<T> ex
      */
     @Override
     protected String formatTo(final Formatter formatter) {
+        final ParameterDescriptor<T> descriptor = getDescriptor();  // Gives to users a chance to override this property.
         WKTUtilities.appendName(descriptor, formatter, ElementKind.PARAMETER);
         final Unit<?> targetUnit = formatter.toContextualUnit(descriptor.getUnit());
         final Convention convention = formatter.getConvention();
@@ -836,6 +837,7 @@ public class DefaultParameterValue<T> ex
          * If this parameter value does not use the same unit, then we must convert it.
          * Otherwise we can write the value as-is.
          */
+        final Unit<?> unit = getUnit();  // Gives to users a chance to override this property.
         if (isWKT1 && targetUnit != null) {
             double convertedValue;
             try {
@@ -848,6 +850,13 @@ public class DefaultParameterValue<T> ex
             }
             formatter.append(convertedValue);
         } else {
+            final T value = getValue();  // Gives to users a chance to override this property.
+            if (!isWKT1 && (unit == null) && (value instanceof URI || value instanceof URL
+                    || value instanceof File || value instanceof Path))
+            {
+                formatter.append(value.toString(), null);
+                return "ParameterFile";
+            }
             formatter.appendAny(value);
         }
         /*

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -27,6 +27,7 @@ import java.util.Locale;
 import java.util.TimeZone;
 import java.io.IOException;
 import java.text.Format;
+import java.text.NumberFormat;
 import java.text.FieldPosition;
 import java.text.ParsePosition;
 import java.text.ParseException;
@@ -707,6 +708,9 @@ public class ParameterFormat extends Tab
                          */
                         final Format format = getFormat(value.getClass());
                         if (format != null) {
+                            if (format instanceof NumberFormat && value instanceof Number) {
+                                configure((NumberFormat) format, Math.abs(((Number) value).doubleValue()));
+                            }
                             value = format.format(value, buffer, dummyFP);
                         }
                         table.append(value.toString());
@@ -754,6 +758,42 @@ public class ParameterFormat extends Tab
             }
         }
     }
+
+    /**
+     * Configures the number pattern to use for the given value. The main intend of this method is to ensure that
+     * the map projection scale factor (a value close to 1) is formatted with a sufficient number of fraction digits.
+     * A common default NumberFormat precision is 3 digits, which is not sufficient. For example the scale factor of
+     * Transverse Mercator projections is 0.9996 (4 digits), and the scale factor of "NTF (Paris) / Lambert zone II"
+     * projection is 0.99987742 (8 digits).
+     *
+     * @param format The format to configure.
+     * @param m The absolute value (magnitude) of the value to write.
+     */
+    private static void configure(final NumberFormat format, final double m) {
+        if (format.getMaximumFractionDigits() <= 9) {
+            /*
+             * If the maximum fraction digits is higher than 9, then that value has not been set by this class.
+             * Maybe the user overrides the createFormat(Class<?>) method in his own subclass, in which case we
+             * will respect his wish and not set a lower value here.
+             */
+            final int n;
+            if (m < 10) {
+                n = 9;
+            } else if (m < 1000) {  // No real use case for this threshold yet, but added for more progressive behavior.
+                n = 6;
+            } else {
+                n = 3;
+            }
+            /*
+             * The minimum fraction digits is usually 0. But if we find a higher value (for example because the
+             * user overrides the createFormat(Class<?>) method), then we will respect user's wish and not set
+             * a lower value.
+             */
+            if (n >= format.getMinimumFractionDigits()) {
+                format.setMaximumFractionDigits(n);
+            }
+        }
+    }
 
     /**
      * Implementation of public {@code format(…)} methods for {@code NAME_SUMMARY} content level.

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -431,6 +431,8 @@ public class AbstractIdentifiedObject ex
      *       {@link org.opengis.referencing.datum.Datum},
      *       {@link org.opengis.referencing.datum.Ellipsoid},
      *       {@link org.opengis.referencing.datum.PrimeMeridian},
+     *       {@link org.opengis.referencing.operation.OperationMethod},
+     *       {@link org.opengis.referencing.operation.CoordinateOperation},
      *       {@link org.opengis.parameter.ParameterDescriptor} or
      *       {@link org.opengis.parameter.ParameterDescriptorGroup},
      *       then this method delegates to the {@code castOrCopy(…)} method of the corresponding SIS subclass.

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/SubTypes.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/SubTypes.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/SubTypes.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/SubTypes.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -23,6 +23,8 @@ import org.opengis.referencing.crs.Coord
 import org.opengis.referencing.datum.Datum;
 import org.opengis.referencing.datum.Ellipsoid;
 import org.opengis.referencing.datum.PrimeMeridian;
+import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.apache.sis.referencing.crs.AbstractCRS;
@@ -31,6 +33,8 @@ import org.apache.sis.referencing.cs.Def
 import org.apache.sis.referencing.datum.AbstractDatum;
 import org.apache.sis.referencing.datum.DefaultEllipsoid;
 import org.apache.sis.referencing.datum.DefaultPrimeMeridian;
+import org.apache.sis.referencing.operation.DefaultOperationMethod;
+import org.apache.sis.referencing.operation.AbstractCoordinateOperation;
 import org.apache.sis.parameter.DefaultParameterDescriptor;
 import org.apache.sis.parameter.DefaultParameterDescriptorGroup;
 
@@ -47,7 +51,7 @@ import org.apache.sis.parameter.DefaultP
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.4
+ * @version 0.6
  * @module
  */
 final class SubTypes {
@@ -81,6 +85,12 @@ final class SubTypes {
         if (object instanceof PrimeMeridian) {
             return DefaultPrimeMeridian.castOrCopy((PrimeMeridian) object);
         }
+        if (object instanceof CoordinateOperation) {
+            return AbstractCoordinateOperation.castOrCopy((CoordinateOperation) object);
+        }
+        if (object instanceof OperationMethod) {
+            return DefaultOperationMethod.castOrCopy((OperationMethod) object);
+        }
         if (object instanceof ParameterDescriptor<?>) {
             return DefaultParameterDescriptor.castOrCopy((ParameterDescriptor<?>) object);
         }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -47,9 +47,17 @@ import java.util.Objects;
 
 
 /**
- * Abstract coordinate reference system, usually defined by a coordinate system and a datum.
- * {@code AbstractCRS} can have an arbitrary number of dimensions. The actual dimension of a
- * given instance can be determined as below:
+ * Coordinate reference system, defined by a {@linkplain AbstractCS coordinate system}
+ * and (usually) a {@linkplain org.apache.sis.referencing.datum.AbstractDatum datum}.
+ * A coordinate reference system (CRS) consists of an ordered sequence of
+ * {@linkplain org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis coordinate system axes}
+ * that are related to the earth through the datum.
+ * Most coordinate reference system do not move relative to the earth, except for
+ * {@linkplain DefaultEngineeringCRS engineering coordinate reference systems}
+ * defined on moving platforms such as cars, ships, aircraft, and spacecraft.
+ *
+ * <p>Coordinate reference systems can have an arbitrary number of dimensions.
+ * The actual dimension of a given instance can be determined as below:</p>
  *
  * {@preformat java
  *   int dimension = crs.getCoordinateSystem().getDimension();
@@ -80,6 +88,7 @@ import java.util.Objects;
 @XmlType(name="AbstractCRSType")
 @XmlRootElement(name = "AbstractCRS")
 @XmlSeeAlso({
+    DefaultProjectedCRS.class,
     DefaultGeodeticCRS.class,
     DefaultVerticalCRS.class,
     DefaultTemporalCRS.class,
@@ -384,14 +393,6 @@ public class AbstractCRS extends Abstrac
     }
 
     /**
-     * Returns the unit used for all axis, or {@code null} if not all axis uses the same unit.
-     * This method is often used for formatting according  Well Known Text (WKT) version 1.
-     */
-    final Unit<?> getUnit() {
-        return ReferencingUtilities.getUnit(coordinateSystem);
-    }
-
-    /**
      * Compares this coordinate reference system with the specified object for equality.
      * If the {@code mode} argument value is {@link ComparisonMode#STRICT STRICT} or
      * {@link ComparisonMode#BY_CONTRACT BY_CONTRACT}, then all available properties are
@@ -458,20 +459,30 @@ public class AbstractCRS extends Abstrac
     @Override
     protected String formatTo(final Formatter formatter) {
         final String  keyword = super.formatTo(formatter);
-        final CoordinateSystem cs = coordinateSystem;
-        final boolean isWKT1  = formatter.getConvention().majorVersion() == 1;
-        final Unit<?> unit    = ReferencingUtilities.getUnit(cs);
-        final Unit<?> oldUnit = formatter.addContextualUnit(unit);
         formatter.newLine();
         formatter.append(toFormattable(getDatum()));
         formatter.newLine();
+        formatCS(formatter, getCoordinateSystem(), formatter.getConvention().majorVersion() == 1);
+        return keyword;
+    }
+
+    /**
+     * Formats the given coordinate system.
+     *
+     * @param formatter The formatter where to append the coordinate system.
+     * @param cs        The coordinate system to append.
+     * @param isWKT1    {@code true} if formatting WKT 1, or {@code false} for WKT 2.
+     */
+    final void formatCS(final Formatter formatter, final CoordinateSystem cs, final boolean isWKT1) {
+        final Unit<?> unit    = ReferencingUtilities.getUnit(cs);
+        final Unit<?> oldUnit = formatter.addContextualUnit(unit);
         if (isWKT1) { // WKT 1 writes unit before axes, while WKT 2 writes them after axes.
             formatter.append(unit);
             if (unit == null) {
                 formatter.setInvalidWKT(this, null);
             }
         } else {
-            formatter.append(toFormattable(cs)); // The concept of CoordinateSystem was not explicit in WKT 1.
+            formatter.append(toFormattable(cs)); // WKT2 only, since the concept of CoordinateSystem was not explicit in WKT 1.
             formatter.indent(+1);
         }
         final int dimension = cs.getDimension();
@@ -487,6 +498,5 @@ public class AbstractCRS extends Abstrac
         formatter.removeContextualUnit(unit);
         formatter.addContextualUnit(oldUnit);
         formatter.newLine(); // For writing the ID[…] element on its own line.
-        return keyword;
     }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultCompoundCRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultCompoundCRS.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultCompoundCRS.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultCompoundCRS.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -424,7 +424,7 @@ public class DefaultCompoundCRS extends
         final Convention convention = formatter.getConvention();
         final boolean isWKT1 = convention.majorVersion() == 1;
         for (final CoordinateReferenceSystem element :
-                (isWKT1 || convention == Convention.INTERNAL) ? components : singles)
+                (isWKT1 || convention == Convention.INTERNAL) ? getComponents() : getSingleComponents())
         {
             formatter.newLine();
             formatter.append(toFormattable(element));

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeodeticCRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeodeticCRS.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeodeticCRS.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeodeticCRS.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -17,7 +17,7 @@
 package org.apache.sis.referencing.crs;
 
 import java.util.Map;
-import javax.measure.unit.Unit;
+import javax.measure.unit.NonSI;
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
@@ -27,9 +27,12 @@ import org.opengis.referencing.cs.Ellips
 import org.opengis.referencing.cs.CoordinateSystem;
 import org.opengis.referencing.crs.GeodeticCRS;
 import org.opengis.referencing.datum.GeodeticDatum;
+import org.opengis.referencing.datum.PrimeMeridian;
 import org.apache.sis.internal.referencing.Legacy;
 import org.apache.sis.internal.referencing.WKTUtilities;
+import org.apache.sis.internal.referencing.ReferencingUtilities;
 import org.apache.sis.referencing.AbstractReferenceSystem;
+import org.apache.sis.io.wkt.Convention;
 import org.apache.sis.io.wkt.Formatter;
 
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
@@ -171,22 +174,10 @@ class DefaultGeodeticCRS extends Abstrac
     @Override
     protected String formatTo(final Formatter formatter) {
         WKTUtilities.appendName(this, formatter, null);
-        final boolean isWKT1  = formatter.getConvention().majorVersion() == 1;
-        final Unit<?> unit    = getUnit();
-        final Unit<?> oldUnit = formatter.addContextualUnit(unit);
-        formatter.newLine();
-        formatter.append(toFormattable(datum));
-        formatter.newLine();
-        formatter.indent(isWKT1 ? 0 : +1);
-        formatter.append(toFormattable(datum.getPrimeMeridian()));
-        formatter.indent(isWKT1 ? 0 : -1);
-        formatter.newLine();
-        CoordinateSystem cs = super.getCoordinateSystem();
-        if (isWKT1) { // WKT 1 writes unit before axes, while WKT 2 writes them after axes.
-            formatter.append(unit);
-            if (unit == null) {
-                formatter.setInvalidWKT(this, null);
-            }
+        final boolean isWKT1 = (formatter.getConvention().majorVersion() == 1);
+        formatDatum(formatter, getDatum(), isWKT1);
+        CoordinateSystem cs = getCoordinateSystem();
+        if (isWKT1) {
             /*
              * Replaces the given coordinate system by an instance conform to the conventions used in WKT 1.
              * Note that we can not delegate this task to subclasses, because XML unmarshalling of a geodetic
@@ -200,23 +191,8 @@ class DefaultGeodeticCRS extends Abstrac
                     formatter.setInvalidWKT(cs, null);
                 }
             }
-        } else {
-            formatter.append(toFormattable(cs)); // The concept of CoordinateSystem was not explicit in WKT 1.
-            formatter.indent(+1);
-        }
-        final int dimension = cs.getDimension();
-        for (int i=0; i<dimension; i++) {
-            formatter.newLine();
-            formatter.append(toFormattable(cs.getAxis(i)));
-        }
-        if (!isWKT1) { // WKT 2 writes unit after axes, while WKT 1 wrote them before axes.
-            formatter.newLine();
-            formatter.append(unit);
-            formatter.indent(-1);
         }
-        formatter.removeContextualUnit(unit);
-        formatter.addContextualUnit(oldUnit);
-        formatter.newLine(); // For writing the ID[…] element on its own line.
+        formatCS(formatter, cs, isWKT1);
         if (!isWKT1) {
             return "GeodeticCRS";
         }
@@ -229,4 +205,29 @@ class DefaultGeodeticCRS extends Abstrac
          */
         return (cs instanceof EllipsoidalCS) ? "GeogCS" : "GeocCS";
     }
+
+    /**
+     * Formats the given geodetic datum to the given formatter. This is part of the WKT formatting
+     * for a geodetic CRS, either standalone or as part of a projected CRS.
+     *
+     * @param formatter Where to format the datum.
+     * @param datum     The datum to format.
+     * @param isWKT1    {@code true} if formatting WKT 1, or {@code false} for WKT 2.
+     *
+     * @see #formatCS(Formatter, CoordinateSystem, boolean)
+     */
+    static void formatDatum(final Formatter formatter, final GeodeticDatum datum, final boolean isWKT1) {
+        formatter.newLine();
+        formatter.append(toFormattable(datum));
+        formatter.newLine();
+        formatter.indent(isWKT1 ? 0 : +1);
+        final PrimeMeridian pm = datum.getPrimeMeridian();
+        if (formatter.getConvention() != Convention.WKT2_SIMPLIFIED ||
+                ReferencingUtilities.getGreenwichLongitude(pm, NonSI.DEGREE_ANGLE) != 0)
+        {
+            formatter.append(toFormattable(pm));
+        }
+        formatter.indent(isWKT1 ? 0 : -1);
+        formatter.newLine();
+    }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultImageCRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultImageCRS.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultImageCRS.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultImageCRS.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -226,14 +226,14 @@ public class DefaultImageCRS extends Abs
      * Used by JAXB only (invoked by reflection).
      */
     private void setAffineCS(final AffineCS cs) {
-        super.setCoordinateSystem("affineCS", cs);
+        setCoordinateSystem("affineCS", cs);
     }
 
     /**
      * Used by JAXB only (invoked by reflection).
      */
     private void setCartesianCS(final CartesianCS cs) {
-        super.setCoordinateSystem("cartesianCS", cs);
+        setCoordinateSystem("cartesianCS", cs);
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultTemporalCRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultTemporalCRS.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultTemporalCRS.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultTemporalCRS.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -238,7 +238,7 @@ public class DefaultTemporalCRS extends
      * Used by JAXB only (invoked by reflection).
      */
     private void setCoordinateSystem(final TimeCS cs) {
-        super.setCoordinateSystem("timeCS", cs);
+        setCoordinateSystem("timeCS", cs);
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultVerticalCRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultVerticalCRS.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultVerticalCRS.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultVerticalCRS.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -209,7 +209,7 @@ public class DefaultVerticalCRS extends
      * Used by JAXB only (invoked by reflection).
      */
     private void setCoordinateSystem(final VerticalCS cs) {
-        super.setCoordinateSystem("verticalCS", cs);
+        setCoordinateSystem("verticalCS", cs);
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/SubTypes.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/SubTypes.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/SubTypes.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/SubTypes.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -20,6 +20,7 @@ import java.util.Map;
 import java.util.Comparator;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.crs.CompoundCRS;
+import org.opengis.referencing.crs.DerivedCRS;
 import org.opengis.referencing.crs.EngineeringCRS;
 import org.opengis.referencing.crs.GeocentricCRS;
 import org.opengis.referencing.crs.GeodeticCRS;
@@ -50,7 +51,7 @@ import org.apache.sis.referencing.cs.Axe
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.4
+ * @version 0.6
  * @module
  */
 final class SubTypes implements Comparator<Object> {
@@ -105,6 +106,12 @@ final class SubTypes implements Comparat
      * @see AbstractCRS#castOrCopy(CoordinateReferenceSystem)
      */
     static AbstractCRS castOrCopy(final CoordinateReferenceSystem object) {
+        if (object instanceof DerivedCRS) {
+            return DefaultDerivedCRS.castOrCopy((DerivedCRS) object);
+        }
+        if (object instanceof ProjectedCRS) {
+            return DefaultProjectedCRS.castOrCopy((ProjectedCRS) object);
+        }
         if (object instanceof GeodeticCRS) {
             if (object instanceof GeographicCRS) {
                 return DefaultGeographicCRS.castOrCopy((GeographicCRS) object);

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/package-info.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/package-info.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/package-info.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -74,7 +74,7 @@
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Cédric Briançon (Geomatys)
  * @since   0.4
- * @version 0.4
+ * @version 0.6
  * @module
  */
 @XmlSchema(elementFormDefault= XmlNsForm.QUALIFIED, namespace = Namespaces.GML, xmlns = {

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -446,7 +446,7 @@ public class AbstractCS extends Abstract
             formatter.setInvalidWKT(this, null);
         }
         formatter.append(type, null);
-        formatter.append(axes.length);
+        formatter.append(getDimension());
         return "CS";
     }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -33,7 +33,11 @@ import org.opengis.metadata.Identifier;
 import org.opengis.referencing.crs.GeodeticCRS;
 import org.opengis.referencing.cs.RangeMeaning;
 import org.opengis.referencing.cs.AxisDirection;
+import org.opengis.referencing.cs.PolarCS;
+import org.opengis.referencing.cs.SphericalCS;
+import org.opengis.referencing.cs.CoordinateSystem;
 import org.opengis.referencing.cs.CoordinateSystemAxis;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.apache.sis.internal.referencing.AxisDirections;
 import org.apache.sis.referencing.AbstractIdentifiedObject;
 import org.apache.sis.referencing.IdentifiedObjects;
@@ -48,6 +52,8 @@ import org.apache.sis.internal.jaxb.Cont
 import org.apache.sis.io.wkt.Formatter;
 import org.apache.sis.io.wkt.Convention;
 import org.apache.sis.io.wkt.ElementKind;
+import org.apache.sis.io.wkt.CharEncoding;
+import org.apache.sis.io.wkt.FormattableObject;
 import org.apache.sis.internal.referencing.ReferencingUtilities;
 
 import static java.lang.Double.doubleToLongBits;
@@ -79,7 +85,7 @@ import java.util.Objects;
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.4
- * @version 0.4
+ * @version 0.6
  * @module
  *
  * @see AbstractCS
@@ -733,6 +739,26 @@ public class DefaultCoordinateSystemAxis
     }
 
     /**
+     * Returns the enclosing coordinate system, or {@code null} if none. In ISO 19162 compliant WKT the coordinate
+     * <strong>reference</strong> system should be the first parent ({@code formatter.getEnclosingElement(1)}) and
+     * the coordinate system shall be obtained from that CRS (yes, this is convolved. This is because of historical
+     * reasons, since compatibility with WKT 1 was a requirement of WKT 2). But we nevertheless walk over all parents
+     * in case someone format unusual things.
+     */
+    private static CoordinateSystem getEnclosingCS(final Formatter formatter) {
+        int depth = 1;
+        for (Object e; (e = formatter.getEnclosingElement(depth)) != null; depth++) {
+            if (e instanceof CoordinateReferenceSystem) {   // This is what we expect in standard WKT.
+                return ((CoordinateReferenceSystem) e).getCoordinateSystem();
+            }
+            if (e instanceof CoordinateSystem) {    // In case someone formats something unusual.
+                return (CoordinateSystem) e;
+            }
+        }
+        return null;
+    }
+
+    /**
      * Formats this axis as a <cite>Well Known Text</cite> {@code Axis[…]} element.
      *
      * <div class="section">Constraints for WKT validity</div>
@@ -743,26 +769,34 @@ public class DefaultCoordinateSystemAxis
      * The only actions (derived from ISO 19162 rules) taken by this method are:
      *
      * <ul>
-     *   <li>Replace “<cite>Geodetic latitude</cite>” and “<cite>Geodetic longitude</cite>” names (case insensitive)
-     *       by “<cite>Latitude</cite>” and “<cite>Longitude</cite>” respectively.</li>
+     *   <li>Replace <cite>“Geodetic latitude”</cite> and <cite>“Geodetic longitude”</cite> names (case insensitive)
+     *       by <cite>“latitude”</cite> and <cite>“longitude”</cite> respectively.</li>
+     *   <li>For latitude and longitude axes, replace “φ” and “λ” abbreviations by <var>“B”</var> and <var>“L”</var>
+     *       respectively (from German “Breite” and “Länge”, used in academic texts worldwide).
+     *       Note that <var>“L”</var> is also the transliteration of Greek letter “lambda” (λ).</li>
+     *   <li>In {@link SphericalCS}, replace “φ” and “θ” abbreviations by <var>“U”</var> and <var>“V”</var> respectively.</li>
+     *   <li>In {@link PolarCS}, replace “θ” abbreviation by <var>“U”</var>.</li>
      * </ul>
      *
+     * The above-cited replacements of Greek letters can be modified by calls to
+     * {@link org.apache.sis.io.wkt.WKTFormat#setCharEncoding(CharEncoding)}.
+     *
      * @return {@code "Axis"}.
      */
     @Override
     protected String formatTo(final Formatter formatter) {
         final Convention convention = formatter.getConvention();
-        final boolean isWKT1 = convention.majorVersion() == 1;
-        final boolean isInternal = (convention == Convention.INTERNAL);
+        final boolean    isWKT1     = (convention.majorVersion() == 1);
+        final boolean    isInternal = (convention == Convention.INTERNAL);
         String name = null;
         if (isWKT1 || isInternal || !omitName(formatter)) {
             name = IdentifiedObjects.getName(this, formatter.getNameAuthority());
             if (name == null) {
                 name = IdentifiedObjects.getName(this, null);
             }
-            if (!isInternal && name != null) {
+            if (name != null && !isInternal) {
                 if (name.equalsIgnoreCase("Geodetic latitude")) {
-                    name = "Latitude"; // ISO 19162 §7.5.3(ii)
+                    name = "Latitude";    // ISO 19162 §7.5.3(ii)
                 } else if (name.equalsIgnoreCase("Geodetic longitude")) {
                     name = "Longitude";
                 }
@@ -770,20 +804,31 @@ public class DefaultCoordinateSystemAxis
         }
         /*
          * ISO 19162 §7.5.3 suggests to put abbreviation in parentheses, e.g. "Easting (x)".
+         * The specification also suggests to write only the abbreviation (e.g. "(X)") in the
+         * special case of Geocentric axis, and disallows Greek letters.
          */
-        if (!isWKT1 && (name == null || !name.equals(abbreviation))) {
-            final StringBuilder buffer = new StringBuilder();
-            if (name != null) {
-                buffer.append(name).append(' ');
+        final CoordinateSystem cs;
+        if (isWKT1) {
+            cs = null;
+        } else {
+            cs = getEnclosingCS(formatter);
+            final String a = formatter.getCharEncoding().getAbbreviation(cs, this);
+            if (a != null && !a.equals(name)) {
+                final StringBuilder buffer = new StringBuilder();
+                if (name != null) {
+                    buffer.append(name).append(' ');
+                }
+                name = buffer.append('(').append(a).append(')').toString();
             }
-            name = buffer.append('(').append(abbreviation).append(')').toString();
         }
-        formatter.append(name, ElementKind.AXIS);
+        if (name != null) {
+            formatter.append(name, ElementKind.AXIS);
+        }
         /*
          * Format the axis direction, optionally followed by a MERIDIAN[…] element
          * if the direction is of the kind "South along 90°N" for instance.
          */
-        AxisDirection dir = direction;
+        AxisDirection dir = getDirection();
         DirectionAlongMeridian meridian = null;
         if (!isWKT1 && AxisDirections.isUserDefined(dir)) {
             meridian = DirectionAlongMeridian.parse(dir);
@@ -798,9 +843,73 @@ public class DefaultCoordinateSystemAxis
          * If the enclosing CRS provided a contextual unit, then it is assumed to apply
          * to all axes (we do not verify).
          */
-        if (!isWKT1 && !formatter.hasContextualUnit(1)) {
-            formatter.append(unit);
+        if (!isWKT1) {
+            if (convention == Convention.WKT2 && cs != null) {
+                final Order order = Order.create(cs, this);
+                if (order != null) {
+                    formatter.append(order);
+                } else {
+                    formatter.setInvalidWKT(cs, null);
+                }
+            }
+            if (!formatter.hasContextualUnit(1)) {
+                formatter.append(getUnit());
+            }
         }
         return "Axis";
     }
+
+    /**
+     * The {@code ORDER[…]} element to be formatted inside {@code AXIS[…]} element.
+     * This is an element of WKT 2 only.
+     */
+    private static final class Order extends FormattableObject {
+        /**
+         * The sequence number to format inside the {@code ORDER[…]} element.
+         */
+        private final int index;
+
+        /**
+         * Creates a new {@code ORDER[…]} element for the given axis in the given coordinate system.
+         * If this method does not found exactly one instance of the given axis in the given coordinate system,
+         * then returns {@code null}. In the later case, it is caller's responsibility to declare the WKT as invalid.
+         *
+         * <p>This method is a little bit inefficient since the enclosing {@link AbstractCS#formatTo(Formatter)}
+         * method already know this axis index. But there is currently no API in {@link Formatter} for carrying
+         * this information, and we are a little bit reluctant to introduce such API since it would force us to
+         * introduce lists in a model which is, for everything else, purely based on trees.</p>
+         *
+         * @se <a href="https://issues.apache.org/jira/browse/SIS-163">SIS-163</a>
+         */
+        static Order create(final CoordinateSystem cs, final DefaultCoordinateSystemAxis axis) {
+            Order order = null;
+            final int dimension = cs.getDimension();
+            for (int i=0; i<dimension;) {
+                if (cs.getAxis(i++) == axis) {
+                    if (order == null) {
+                        order = new Order(i);
+                    } else {
+                        return null;
+                    }
+                }
+            }
+            return order;
+        }
+
+        /**
+         * Creates new {@code ORDER[…]} element for the given sequential number.
+         */
+        private Order(final int index) {
+            this.index = index;
+        }
+
+        /**
+         * Formats the {@code ORDER[…]} element.
+         */
+        @Override
+        protected String formatTo(final Formatter formatter) {
+            formatter.append(index);
+            return "Order";
+        }
+    }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -31,8 +31,8 @@ import org.apache.sis.referencing.Abstra
 import org.apache.sis.referencing.IdentifiedObjects;
 import org.apache.sis.util.iso.Types;
 import org.apache.sis.util.ComparisonMode;
+import org.apache.sis.internal.util.Citations;
 import org.apache.sis.internal.metadata.MetadataUtilities;
-import org.apache.sis.internal.referencing.OperationMethods;
 
 import static org.apache.sis.util.Utilities.deepEquals;
 import static org.apache.sis.util.collection.Containers.property;
@@ -414,7 +414,7 @@ public class AbstractDatum extends Abstr
                  * and parameters. We extend this rule to datum as well.
                  */
                 final Datum that = (Datum) object;
-                final Boolean match = OperationMethods.hasCommonIdentifier(getIdentifiers(), that.getIdentifiers());
+                final Boolean match = Citations.hasCommonIdentifier(getIdentifiers(), that.getIdentifiers());
                 if (match != null) {
                     return match;
                 }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -609,7 +609,7 @@ public class BursaWolfParameters extends
             return "ToWGS84";
         }
         formatter.setInvalidWKT(BursaWolfParameters.class, null);
-        String name = IdentifiedObjects.getUnicodeIdentifier(targetDatum);
+        String name = IdentifiedObjects.getUnicodeIdentifier(getTargetDatum());
         if (name == null) {
             name = "Unknown";
         }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -761,13 +761,15 @@ public class DefaultEllipsoid extends Ab
     @Override
     protected String formatTo(final Formatter formatter) {
         super.formatTo(formatter);
-        final Convention convention = formatter.getConvention();
-        final boolean isWKT1 = convention.majorVersion() == 1;
-        double length = semiMajorAxis;
+        final Convention   convention = formatter.getConvention();
+        final boolean      isWKT1     = convention.majorVersion() == 1;
+        final Unit<Length> unit       = getAxisUnit();  // Gives to users a chance to override properties.
+        double length = getSemiMajorAxis();
         if (isWKT1) {
             length = unit.getConverterTo(SI.METRE).convert(length);
         }
         formatter.append(length);
+        final double inverseFlattening = getInverseFlattening();  // Gives to users a chance to override properties.
         formatter.append(isInfinite(inverseFlattening) ? 0 : inverseFlattening);
         if (isWKT1) {
             return "Spheroid";

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -530,13 +530,16 @@ public class DefaultGeodeticDatum extend
      * }
      * </div>
      *
+     * Note that the {@linkplain #getPrimeMeridian() prime meridian} shall be formatted by the caller
+     * as a separated element after the geodetic datum (for compatibility with WKT 1).
+     *
      * @return {@code "Datum"}.
      */
     @Override
     protected String formatTo(final Formatter formatter) {
         super.formatTo(formatter);
         formatter.newLine();
-        formatter.append(toFormattable(ellipsoid));
+        formatter.append(toFormattable(getEllipsoid()));
         if (formatter.getConvention().majorVersion() == 1) {
             /*
              * Note that at the different of other datum (in particular vertical datum),
@@ -552,6 +555,7 @@ public class DefaultGeodeticDatum extend
                 }
             }
         }
+        // For the WKT 2 case, the ANCHOR[…] element is added by Formatter itself.
         formatter.newLine(); // For writing the ID[…] element on its own line.
         return "Datum";
     }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultImageDatum.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultImageDatum.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultImageDatum.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultImageDatum.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -245,7 +245,7 @@ public class DefaultImageDatum extends A
         super.formatTo(formatter);
         final Convention convention = formatter.getConvention();
         if (convention == Convention.INTERNAL) {
-            formatter.append(pixelInCell); // This is an extension compared to ISO 19162.
+            formatter.append(getPixelInCell());         // This is an extension compared to ISO 19162.
         } else if (convention.majorVersion() == 1) {
             formatter.setInvalidWKT(this, null);
         }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -349,10 +349,11 @@ public class DefaultPrimeMeridian extend
         if (targetUnit == null) {
             targetUnit = NonSI.DEGREE_ANGLE;
         }
-        formatter.append(isWKT1 ? getGreenwichLongitude(targetUnit) : greenwichLongitude);
+        formatter.append(isWKT1 ? getGreenwichLongitude(targetUnit) : getGreenwichLongitude());
         if (isWKT1) {
             return "PrimeM";
         }
+        final Unit<Angle> angularUnit = getAngularUnit();   // Gives to users a chance to override properties.
         if (!convention.isSimplified() || !targetUnit.equals(angularUnit)) {
             formatter.append(angularUnit);
         }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultTemporalDatum.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultTemporalDatum.java?rev=1677070&r1=1677069&r2=1677070&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultTemporalDatum.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultTemporalDatum.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -289,7 +289,7 @@ public class DefaultTemporalDatum extend
     @Override
     protected String formatTo(final Formatter formatter) {
         super.formatTo(formatter);
-        formatter.append(new Origin(MetadataUtilities.toDate(origin)));
+        formatter.append(new Origin(getOrigin()));
         if (formatter.getConvention().majorVersion() == 1) {
             formatter.setInvalidWKT(this, null);
         }

Copied: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java (from r1677068, sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java?p2=sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java&p1=sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java&r1=1677068&r2=1677070&rev=1677070&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java [UTF-8] Thu Apr 30 20:57:36 2015
@@ -435,7 +435,7 @@ public class AbstractCoordinateOperation
      */
     @Override
     public Collection<PositionalAccuracy> getCoordinateOperationAccuracy() {
-        return (coordinateOperationAccuracy != null) ? coordinateOperationAccuracy : Collections.emptySet();
+        return (coordinateOperationAccuracy != null) ? coordinateOperationAccuracy : Collections.<PositionalAccuracy>emptySet();
     }
 
     /**



Mime
View raw message