You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2015/06/04 16:39:08 UTC

svn commit: r1683562 - in /sis/branches/JDK8/core: sis-metadata/src/main/java/org/apache/sis/internal/metadata/ sis-referencing/src/main/java/org/apache/sis/internal/referencing/ sis-referencing/src/main/java/org/apache/sis/io/wkt/ sis-referencing/src/...

Author: desruisseaux
Date: Thu Jun  4 14:39:07 2015
New Revision: 1683562

URL: http://svn.apache.org/r1683562
Log:
Referencing: avoid direct usage of AbstractCS and DefaultConversion in GeodeticObjectParser.

Added:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/ConversionKeys.java   (with props)
Modified:
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCompoundCS.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultCompoundCSTest.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/HardCodedAxes.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/Containers.java

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java?rev=1683562&r1=1683561&r2=1683562&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java [UTF-8] Thu Jun  4 14:39:07 2015
@@ -21,6 +21,10 @@ import org.opengis.geometry.Envelope;
 import org.opengis.metadata.Identifier;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.crs.SingleCRS;
+import org.opengis.referencing.crs.DerivedCRS;
+import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.cs.CoordinateSystemAxis;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.operation.CoordinateOperationFactory;
@@ -383,4 +387,38 @@ public class ReferencingServices extends
         }
         return fallback;
     }
+
+    /**
+     * Creates a coordinate system of unknown type. This method is used during parsing of WKT version 1,
+     * since that legacy format did not specified any information about the coordinate system in use.
+     * This method should not need to be invoked for parsing WKT version 2.
+     *
+     * @param  axes The axes of the unknown coordinate system.
+     * @return An "abstract" coordinate system using the given axes.
+     */
+    public CoordinateSystem createAbstractCS(final CoordinateSystemAxis[] axes) {
+        throw referencingModuleNotFound();
+    }
+
+    /**
+     * Creates a derived CRS from the information found in a WKT 1 {@code FITTED_CS} element.
+     * This coordinate system can not be easily constructed from the information provided by the WKT 1 format.
+     * Note that this method is needed only for WKT 1 parsing, since WKT provides enough information for using
+     * the standard factories.
+     *
+     * @param  properties    The properties to be given to the {@code DerivedCRS} and {@code Conversion} objects.
+     * @param  baseCRS       Coordinate reference system to base the derived CRS on.
+     * @param  method        The coordinate operation method (mandatory in all cases).
+     * @param  baseToDerived Transform from positions in the base CRS to positions in this target CRS.
+     * @param  derivedCS     The coordinate system for the derived CRS.
+     * @return The newly created derived CRS, potentially implementing an additional CRS interface.
+     */
+    public DerivedCRS createDerivedCRS(final Map<String,?>    properties,
+                                       final SingleCRS        baseCRS,
+                                       final OperationMethod  method,
+                                       final MathTransform    baseToDerived,
+                                       final CoordinateSystem derivedCS)
+    {
+        throw referencingModuleNotFound();
+    }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java?rev=1683562&r1=1683561&r2=1683562&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java [UTF-8] Thu Jun  4 14:39:07 2015
@@ -18,8 +18,11 @@ package org.apache.sis.internal.referenc
 
 import org.opengis.referencing.cs.AxisDirection;
 import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.cs.CoordinateSystemAxis;
+import org.apache.sis.internal.util.Utilities;
 import org.apache.sis.util.Characters;
 import org.apache.sis.util.Static;
+import org.apache.sis.util.iso.Types;
 
 import static org.opengis.referencing.cs.AxisDirection.*;
 import static org.apache.sis.util.CharSequences.*;
@@ -30,7 +33,7 @@ import static org.apache.sis.util.CharSe
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.5
+ * @version 0.6
  * @module
  */
 public final class AxisDirections extends Static {
@@ -511,4 +514,35 @@ public final class AxisDirections extend
         final int length = upper - lower;
         return (length == keyword.length()) && name.regionMatches(true, lower, keyword, 0, length);
     }
+
+    /**
+     * Builds a coordinate system name from the given array of axes.
+     * This method expects a {@code StringBuilder} pre-filled with the coordinate system name.
+     * The axis directions and abbreviations will be appended after the CS name.
+     * Examples:
+     *
+     * <ul>
+     *   <li>Ellipsoidal CS: North (°), East (°).</li>
+     *   <li>Cartesian CS: East (km), North (km).</li>
+     *   <li>Compound CS: East (km), North (km), Up (m).</li>
+     * </ul>
+     *
+     * @param  buffer A buffer pre-filled with the name header.
+     * @param  axes The axes to append in the given buffer.
+     * @return A name for the given coordinate system type and axes.
+     *
+     * @since 0.6
+     */
+    public static String appendTo(final StringBuilder buffer, final CoordinateSystemAxis[] axes) {
+        String separator = ": ";
+        for (final CoordinateSystemAxis axis : axes) {
+            buffer.append(separator).append(Types.getCodeLabel(axis.getDirection()));
+            separator = ", ";
+            final String symbol = Utilities.toString(axis.getUnit());
+            if (symbol != null && !symbol.isEmpty()) {
+                buffer.append(" (").append(symbol).append(')');
+            }
+        }
+        return buffer.append('.').toString();
+    }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java?rev=1683562&r1=1683561&r2=1683562&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java [UTF-8] Thu Jun  4 14:39:07 2015
@@ -19,21 +19,25 @@ package org.apache.sis.internal.referenc
 import java.util.Map;
 import java.util.Iterator;
 import java.util.Collection;
+import java.util.Collections;
 
 import org.opengis.util.FactoryException;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.referencing.IdentifiedObject;
 import org.opengis.referencing.crs.SingleCRS;
+import org.opengis.referencing.crs.DerivedCRS;
 import org.opengis.referencing.crs.TemporalCRS;
 import org.opengis.referencing.crs.VerticalCRS;
 import org.opengis.referencing.crs.GeographicCRS;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.cs.CoordinateSystemAxis;
 import org.opengis.referencing.operation.Matrix;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.operation.TransformException;
+import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.operation.CoordinateOperationFactory;
 import org.opengis.metadata.extent.GeographicBoundingBox;
@@ -46,6 +50,8 @@ import org.apache.sis.referencing.CRS;
 import org.apache.sis.referencing.CommonCRS;
 import org.apache.sis.referencing.IdentifiedObjects;
 import org.apache.sis.referencing.AbstractIdentifiedObject;
+import org.apache.sis.referencing.cs.AbstractCS;
+import org.apache.sis.referencing.crs.DefaultDerivedCRS;
 import org.apache.sis.referencing.crs.DefaultTemporalCRS;
 import org.apache.sis.referencing.operation.transform.MathTransforms;
 import org.apache.sis.referencing.operation.DefaultCoordinateOperationFactory;
@@ -436,4 +442,41 @@ public final class ServicesForMetadata e
             return new DefaultCoordinateOperationFactory(properties, mtFactory);
         }
     }
+
+    /**
+     * Creates a coordinate system of unknown type. This method is used during parsing of WKT version 1,
+     * since that legacy format did not specified any information about the coordinate system in use.
+     * This method should not need to be invoked for parsing WKT version 2.
+     *
+     * @param  axes The axes of the unknown coordinate system.
+     * @return An "abstract" coordinate system using the given axes.
+     */
+    @Override
+    public CoordinateSystem createAbstractCS(final CoordinateSystemAxis[] axes) {
+        return new AbstractCS(Collections.singletonMap(AbstractCS.NAME_KEY,
+                AxisDirections.appendTo(new StringBuilder("CS"), axes)), axes);
+    }
+
+    /**
+     * Creates a derived CRS from the information found in a WKT 1 {@code FITTED_CS} element.
+     * This coordinate system can not be easily constructed from the information provided by the WKT 1 format.
+     * Note that this method is needed only for WKT 1 parsing, since WKT provides enough information for using
+     * the standard factories.
+     *
+     * @param  properties    The properties to be given to the {@code DerivedCRS} and {@code Conversion} objects.
+     * @param  baseCRS       Coordinate reference system to base the derived CRS on.
+     * @param  method        The coordinate operation method (mandatory in all cases).
+     * @param  baseToDerived Transform from positions in the base CRS to positions in this target CRS.
+     * @param  derivedCS     The coordinate system for the derived CRS.
+     * @return The newly created derived CRS, potentially implementing an additional CRS interface.
+     */
+    @Override
+    public DerivedCRS createDerivedCRS(final Map<String,?>    properties,
+                                       final SingleCRS        baseCRS,
+                                       final OperationMethod  method,
+                                       final MathTransform    baseToDerived,
+                                       final CoordinateSystem derivedCS)
+    {
+        return DefaultDerivedCRS.create(properties, baseCRS, null, method, baseToDerived, derivedCS);
+    }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java?rev=1683562&r1=1683561&r2=1683562&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java [UTF-8] Thu Jun  4 14:39:07 2015
@@ -49,17 +49,16 @@ import org.opengis.referencing.operation
 
 import org.apache.sis.measure.Units;
 import org.apache.sis.referencing.CommonCRS;
-import org.apache.sis.referencing.cs.AbstractCS;
 import org.apache.sis.referencing.cs.AxisFilter;
 import org.apache.sis.referencing.cs.CoordinateSystems;
 import org.apache.sis.referencing.datum.BursaWolfParameters;
-import org.apache.sis.referencing.operation.DefaultConversion;
 import org.apache.sis.metadata.iso.ImmutableIdentifier;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.internal.metadata.WKTKeywords;
 import org.apache.sis.internal.metadata.ReferencingServices;
 import org.apache.sis.internal.referencing.Legacy;
 import org.apache.sis.internal.referencing.VerticalDatumTypes;
+import org.apache.sis.internal.util.LocalizedParseException;
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.iso.Types;
@@ -118,6 +117,11 @@ final class GeodeticObjectParser extends
     private final CoordinateOperationFactory opFactory;
 
     /**
+     * Other services from "sis-referencing" module which can not be provided by the standard factories.
+     */
+    private final ReferencingServices referencing;
+
+    /**
      * The WKT convention to assume for parsing.
      *
      * <ul>
@@ -172,7 +176,8 @@ final class GeodeticObjectParser extends
         crsFactory    = (CRSFactory)   factories;
         csFactory     = (CSFactory)    factories;
         datumFactory  = (DatumFactory) factories;
-        opFactory     = ReferencingServices.getInstance().getCoordinateOperationFactory(defaultProperties, mtFactory);
+        referencing   = ReferencingServices.getInstance();
+        opFactory     = referencing.getCoordinateOperationFactory(defaultProperties, mtFactory);
         convention    = Convention.DEFAULT;
         isAxisIgnored = false;
     }
@@ -200,7 +205,8 @@ final class GeodeticObjectParser extends
         crsFactory   = getFactory(CRSFactory.class,   factories);
         csFactory    = getFactory(CSFactory.class,    factories);
         datumFactory = getFactory(DatumFactory.class, factories);
-        opFactory    = ReferencingServices.getInstance().getCoordinateOperationFactory(null, mtFactory);
+        referencing  = ReferencingServices.getInstance();
+        opFactory    = referencing.getCoordinateOperationFactory(null, mtFactory);
         this.convention = convention;
         this.isAxisIgnored = isAxisIgnored;
     }
@@ -670,8 +676,7 @@ final class GeodeticObjectParser extends
             list.add(axis);
             axis = parseAxis(element, linearUnit, false);
         } while (axis != null);
-        final CoordinateSystem cs = new AbstractCS(singletonMap("name", name),
-                list.toArray(new CoordinateSystemAxis[list.size()]));
+        final CoordinateSystem cs = referencing.createAbstractCS(list.toArray(new CoordinateSystemAxis[list.size()]));
         try {
             return crsFactory.createEngineeringCRS(parseAuthorityAndClose(element, name), datum, cs);
         } catch (FactoryException exception) {
@@ -905,32 +910,37 @@ final class GeodeticObjectParser extends
         final Element                   element = parent.pullElement(WKTKeywords.Fitted_CS);
         final String                    name    = element.pullString("name");
         final MathTransform             toBase  = parseMathTransform(element, true);
-        final CoordinateReferenceSystem base    = parseCoordinateReferenceSystem(element, true);
         final OperationMethod           method  = getOperationMethod();
+        final CoordinateReferenceSystem baseCRS = parseCoordinateReferenceSystem(element, true);
+        if (!(baseCRS instanceof SingleCRS)) {
+            throw new LocalizedParseException(errorLocale, Errors.Keys.UnexpectedValueInElement_2,
+                    new Object[] {WKTKeywords.Fitted_CS, baseCRS.getClass()}, element.offset);
+        }
         /*
-         * WKT 1 provides no informations about the underlying CS of a derived CRS.
+         * WKT 1 provides no information about the underlying CS of a derived CRS.
          * We have to guess some reasonable one with arbitrary units. We try to construct the one which
          * contains as few information as possible, in order to avoid providing wrong informations.
          */
-        final CoordinateSystemAxis[] axis = new CoordinateSystemAxis[toBase.getSourceDimensions()];
-        final StringBuilder buffer = new StringBuilder(name);
-        buffer.append(" axis ");
+        final CoordinateSystemAxis[] axes = new CoordinateSystemAxis[toBase.getSourceDimensions()];
+        final StringBuilder buffer = new StringBuilder(name).append(" axis ");
         final int start = buffer.length();
         try {
-            for (int i=0; i<axis.length; i++) {
+            for (int i=0; i<axes.length; i++) {
                 final String number = String.valueOf(i);
                 buffer.setLength(start);
                 buffer.append(number);
-                axis[i] = csFactory.createCoordinateSystemAxis(
+                axes[i] = csFactory.createCoordinateSystemAxis(
                         singletonMap(IdentifiedObject.NAME_KEY, buffer.toString()),
                         number, AxisDirection.OTHER, Unit.ONE);
             }
-            final Conversion conversion = new DefaultConversion(    // TODO: use opFactory
-                    singletonMap(IdentifiedObject.NAME_KEY, method.getName().getCode()),
-                    method, toBase.inverse(), null);
-            final Map<String,?> properties = parseAuthorityAndClose(element, name);
-            final CoordinateSystem cs = new AbstractCS(properties, axis);
-            return crsFactory.createDerivedCRS(properties, base, conversion, cs);
+            final Map<String,Object> properties = parseAuthorityAndClose(element, name);
+            final CoordinateSystem derivedCS = referencing.createAbstractCS(axes);
+            /*
+             * We do not know which name to give to the conversion method.
+             * For now, use the CRS name.
+             */
+            properties.put("conversion.name", name);
+            return referencing.createDerivedCRS(properties, (SingleCRS) baseCRS, method, toBase.inverse(), derivedCS);
         } catch (FactoryException | NoninvertibleTransformException exception) {
             throw element.parseFailed(exception);
         }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java?rev=1683562&r1=1683561&r2=1683562&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java [UTF-8] Thu Jun  4 14:39:07 2015
@@ -25,7 +25,9 @@ import org.opengis.util.FactoryException
 import org.opengis.referencing.datum.Datum;
 import org.opengis.referencing.crs.SingleCRS;
 import org.opengis.referencing.crs.GeneralDerivedCRS;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.referencing.operation.Conversion;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
@@ -90,8 +92,8 @@ abstract class AbstractDerivedCRS<C exte
      * @param  conversion The defining conversion from a normalized base to a normalized derived CRS.
      * @param  derivedCS  The coordinate system for the derived CRS. The number of axes
      *         must match the target dimension of the {@code baseToDerived} transform.
-     * @throws MismatchedDimensionException if the source and target dimension of {@code baseToDerived}
-     *         do not match the dimension of {@code base} and {@code derivedCS} respectively.
+     * @throws MismatchedDimensionException if the source and target dimensions of {@code baseToDerived}
+     *         do not match the dimensions of {@code base} and {@code derivedCS} respectively.
      */
     AbstractDerivedCRS(final Map<String,?>    properties,
                        final SingleCRS        baseCRS,
@@ -111,6 +113,27 @@ abstract class AbstractDerivedCRS<C exte
     }
 
     /**
+     * For {@link DefaultDerivedCRS#DefaultDerivedCRS(Map, SingleCRS, CoordinateReferenceSystem, OperationMethod,
+     * MathTransform, CoordinateSystem)} constructor only (<strong>not legal for {@code ProjectedCRS}</strong>).
+     */
+    @SuppressWarnings("unchecked")
+    AbstractDerivedCRS(final Map<String,?>             properties,
+                       final SingleCRS                 baseCRS,
+                       final CoordinateReferenceSystem interpolationCRS,
+                       final OperationMethod           method,
+                       final MathTransform             baseToDerived,
+                       final CoordinateSystem          derivedCS)
+            throws MismatchedDimensionException
+    {
+        super(properties, derivedCS);
+        ArgumentChecks.ensureNonNull("baseCRS", baseCRS);
+        ArgumentChecks.ensureNonNull("method", method);
+        ArgumentChecks.ensureNonNull("baseToDerived", baseToDerived);
+        conversionFromBase = (C) new DefaultConversion(   // Cast to (C) is valid only for DefaultDerivedCRS.
+                ConversionKeys.unprefix(properties), baseCRS, this, interpolationCRS, method, baseToDerived);
+    }
+
+    /**
      * Constructs a new coordinate reference system with the same values than the specified one.
      * This copy constructor provides a way to convert an arbitrary implementation into a SIS one
      * or a user-defined one (as a subclass), usually in order to leverage some implementation-specific API.

Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/ConversionKeys.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/ConversionKeys.java?rev=1683562&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/ConversionKeys.java (added)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/ConversionKeys.java [UTF-8] Thu Jun  4 14:39:07 2015
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.referencing.crs;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.EnumSet;
+import org.apache.sis.util.ObjectConverter;
+import org.apache.sis.util.ObjectConverters;
+import org.apache.sis.math.FunctionProperty;
+
+
+/**
+ * Provides a map without the {@code "conversion."} prefix in front of property keys.
+ * The method to invoke is {@link #unprefix(Map)}.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.6
+ * @version 0.6
+ * @module
+ */
+final class ConversionKeys implements ObjectConverter<String,String> {
+    /**
+     * The prefix to add or remove to the keys.
+     */
+    private static final String PREFIX = "conversion.";
+
+    /**
+     * The converter for adding or removing the {@link #PREFIX} in keys.
+     */
+    private static final ConversionKeys ADD = new ConversionKeys(true), REMOVE = new ConversionKeys(false);
+
+    /**
+     * {@code true} if this converter adds the prefix, or {@code false} if it removes it.
+     */
+    private final boolean add;
+
+    /**
+     * Creates a new converter which will add or remove the prefix.
+     */
+    private ConversionKeys(final boolean add) {
+        this.add = add;
+    }
+
+    /**
+     * Provides a map without the {@code "conversion."} prefix in the keys.
+     *
+     * @param <V> Type of values in the map.
+     * @param properties The user-supplied properties.
+     */
+    @SuppressWarnings("unchecked")
+    static <V> Map<String,V> unprefix(final Map<String,V> properties) {
+        /*
+         * The cast to (Class<V>) is not correct, but it not a problem in this particular case
+         * because this converter will be used for a map which will be read only (not written)
+         * by DefaultConversion. The returned map should never escape the SIS private space.
+         */
+        return ObjectConverters.derivedKeys(properties, REMOVE, (Class<V>) Object.class);
+    }
+
+    /**
+     * Returns the type of keys in the user-supplied properties map.
+     */
+    @Override
+    public Class<String> getSourceClass() {
+        return String.class;
+    }
+
+    /**
+     * Returns the type of keys in the derived properties.
+     */
+    @Override
+    public Class<String> getTargetClass() {
+        return String.class;
+    }
+
+    /**
+     * Returns the manner in which source keys are mapped to target keys.
+     */
+    @Override
+    public Set<FunctionProperty> properties() {
+        return EnumSet.of(FunctionProperty.INVERTIBLE, FunctionProperty.ORDER_PRESERVING,
+                add ? FunctionProperty.INJECTIVE : FunctionProperty.SURJECTIVE);
+    }
+
+    /**
+     * Adds or removes the prefix from the specified key.
+     * In the removal case if the key does not begin with the prefix, then this method returns {@code null}.
+     *
+     * @param  key A key from the user-supplied properties map.
+     * @return The key to show in the derived map.
+     */
+    @Override
+    public String apply(final String key) {
+        if (add) {
+            return PREFIX + key;
+        } else {
+            return key.startsWith(PREFIX) ? key.substring(PREFIX.length()) : null;
+        }
+    }
+
+    /**
+     * Returns the inverse of this converter.
+     */
+    @Override
+    public ObjectConverter<String,String> inverse() {
+        return add ? REMOVE : ADD;
+    }
+}

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/ConversionKeys.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/ConversionKeys.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java?rev=1683562&r1=1683561&r2=1683562&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java [UTF-8] Thu Jun  4 14:39:07 2015
@@ -31,15 +31,18 @@ import org.opengis.referencing.crs.Verti
 import org.opengis.referencing.crs.TemporalCRS;
 import org.opengis.referencing.crs.ProjectedCRS;
 import org.opengis.referencing.crs.EngineeringCRS;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.cs.CoordinateSystem;
 import org.opengis.referencing.cs.EllipsoidalCS;
 import org.opengis.referencing.cs.VerticalCS;
 import org.opengis.referencing.cs.TimeCS;
 import org.opengis.referencing.operation.Conversion;
+import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.NoninvertibleTransformException;
 import org.opengis.geometry.MismatchedDimensionException;
 import org.apache.sis.referencing.AbstractIdentifiedObject;
+import org.apache.sis.referencing.operation.DefaultConversion;
 import org.apache.sis.referencing.operation.DefaultOperationMethod;
 import org.apache.sis.referencing.cs.AxesConvention;
 import org.apache.sis.internal.referencing.WKTUtilities;
@@ -51,9 +54,8 @@ import org.apache.sis.util.Classes;
 
 
 /**
- * A coordinate reference system that is defined by its coordinate
- * {@linkplain org.apache.sis.referencing.operation.DefaultConversion conversion} from another CRS
- * (not by a {@linkplain org.apache.sis.referencing.datum.AbstractDatum datum}). {@code DerivedCRS}
+ * A coordinate reference system that is defined by its coordinate {@linkplain DefaultConversion conversion}
+ * from another CRS (not by a {@linkplain org.apache.sis.referencing.datum.AbstractDatum datum}). {@code DerivedCRS}
  * can not be {@linkplain DefaultProjectedCRS projected CRS} themselves, but may be derived from a projected CRS
  * (for example in order to use a {@linkplain org.apache.sis.referencing.cs.DefaultPolarCS polar coordinate system}).
  *
@@ -154,8 +156,8 @@ public class DefaultDerivedCRS extends A
      *                    to a normalized derived CRS.
      * @param  derivedCS  The coordinate system for the derived CRS. The number of axes
      *         must match the target dimension of the {@code baseToDerived} transform.
-     * @throws MismatchedDimensionException if the source and target dimension of {@code baseToDerived}
-     *         do not match the dimension of {@code base} and {@code derivedCS} respectively.
+     * @throws MismatchedDimensionException if the source and target dimensions of {@code baseToDerived}
+     *         do not match the dimensions of {@code base} and {@code derivedCS} respectively.
      *
      * @see #create(Map, SingleCRS, Conversion, CoordinateSystem)
      */
@@ -169,6 +171,72 @@ public class DefaultDerivedCRS extends A
     }
 
     /**
+     * Creates a derived CRS from a math transform. The given {@code MathTransform} shall transform coordinate
+     * values specifically from the {@code baseCRS} to {@code this} CRS (optionally with an interpolation CRS);
+     * there is no consideration about <cite>“normalized CRS”</cite> in this constructor.
+     *
+     * <div class="section">Conversion properties</div>
+     * The {@code properties} map given in argument can contain any entries documented in the
+     * {@linkplain #DefaultDerivedCRS(Map, SingleCRS, Conversion, CoordinateSystem) above constructor},
+     * together with any entries documented by the {@linkplain DefaultConversion#DefaultConversion(Map,
+     * CoordinateReferenceSystem, CoordinateReferenceSystem, CoordinateReferenceSystem, OperationMethod, MathTransform)
+     * conversion constructor} provided that the {@code Conversion} entry keys are prefixed by {@code "conversion."}.
+     * In particular, the two first properties listed below are mandatory:
+     *
+     * <table class="sis">
+     *   <caption>Mandatory properties and some optional properties</caption>
+     *   <tr>
+     *     <th>Property name</th>
+     *     <th>Value type</th>
+     *     <th>Returned by</th>
+     *   </tr>
+     *   <tr>
+     *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
+     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@code this.getName()}</td>
+     *   </tr>
+     *   <tr>
+     *     <td>"conversion.name"</td>
+     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@code conversionFromBase.getName()}</td>
+     *   </tr>
+     *   <tr>
+     *     <th colspan="3" class="hsep">Optional properties (non exhaustive list)</th>
+     *   </tr>
+     *   <tr>
+     *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
+     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@code this.getIdentifiers()}</td>
+     *   </tr>
+     *   <tr>
+     *     <td>{@value org.opengis.referencing.operation.CoordinateOperation#DOMAIN_OF_VALIDITY_KEY}</td>
+     *     <td>{@link org.opengis.metadata.extent.Extent}</td>
+     *     <td>{@code conversionFromBase.getDomainOfValidity()}</td>
+     *   </tr>
+     * </table>
+     *
+     * @param  properties       The properties to be given to the {@link DefaultConversion} object
+     *                          (with keys prefixed by {@code "conversion."}) and to the new derived CRS object.
+     * @param  baseCRS          Coordinate reference system to base the derived CRS on.
+     * @param  interpolationCRS The CRS of additional coordinates needed for the operation, or {@code null} if none.
+     * @param  method           The coordinate operation method (mandatory in all cases).
+     * @param  baseToDerived    Transform from positions in the base CRS to positions in this target CRS.
+     * @param  derivedCS        The coordinate system for the derived CRS.
+     * @throws IllegalArgumentException if at least one argument has an incompatible number of dimensions.
+     *
+     * @see #create(Map, SingleCRS, CoordinateReferenceSystem, OperationMethod, MathTransform, CoordinateSystem)
+     */
+    protected DefaultDerivedCRS(final Map<String,?>             properties,
+                                final SingleCRS                 baseCRS,
+                                final CoordinateReferenceSystem interpolationCRS,
+                                final OperationMethod           method,
+                                final MathTransform             baseToDerived,
+                                final CoordinateSystem          derivedCS)
+    {
+        super(properties, baseCRS, interpolationCRS, method, baseToDerived, derivedCS);
+    }
+
+    /**
      * Constructs a new coordinate reference system with the same values than the specified one.
      * This copy constructor provides a way to convert an arbitrary implementation into a SIS one
      * or a user-defined one (as a subclass), usually in order to leverage some implementation-specific API.
@@ -197,8 +265,8 @@ public class DefaultDerivedCRS extends A
      * @param  derivedCS  The coordinate system for the derived CRS. The number of axes
      *         must match the target dimension of the {@code baseToDerived} transform.
      * @return The newly created derived CRS, potentially implementing an additional CRS interface.
-     * @throws MismatchedDimensionException if the source and target dimension of {@code baseToDerived}
-     *         do not match the dimension of {@code base} and {@code derivedCS} respectively.
+     * @throws MismatchedDimensionException if the source and target dimensions of {@code baseToDerived}
+     *         do not match the dimensions of {@code base} and {@code derivedCS} respectively.
      *
      * @see #DefaultDerivedCRS(Map, SingleCRS, Conversion, CoordinateSystem)
      */
@@ -211,16 +279,75 @@ public class DefaultDerivedCRS extends A
         if (baseCRS != null && derivedCS != null) {
             final String type = getType(baseCRS, derivedCS);
             if (type != null) switch (type) {
-                case WKTKeywords.GeodeticCRS:    return new Geodetic   (properties, (GeodeticCRS) baseCRS, conversion, (EllipsoidalCS) derivedCS);
-                case WKTKeywords.VerticalCRS:    return new Vertical   (properties, (VerticalCRS) baseCRS, conversion,    (VerticalCS) derivedCS);
-                case WKTKeywords.TimeCRS:        return new Temporal   (properties, (TemporalCRS) baseCRS, conversion,        (TimeCS) derivedCS);
-                case WKTKeywords.EngineeringCRS: return new Engineering(properties,               baseCRS, conversion,                 derivedCS);
+                case WKTKeywords.GeodeticCRS: return new Geodetic(properties, (GeodeticCRS) baseCRS, conversion, (EllipsoidalCS) derivedCS);
+                case WKTKeywords.VerticalCRS: return new Vertical(properties, (VerticalCRS) baseCRS, conversion,    (VerticalCS) derivedCS);
+                case WKTKeywords.TimeCRS:     return new Temporal(properties, (TemporalCRS) baseCRS, conversion,        (TimeCS) derivedCS);
+                case WKTKeywords.EngineeringCRS: {
+                    /*
+                     * This case may happen for baseCRS of kind GeodeticCRS, ProjectedCRS or EngineeringCRS.
+                     * But only the later is associated to EngineeringDatum; the two formers are associated
+                     * to GeodeticDatum. Consequently we can implement the EngineeringCRS.getDatum() method
+                     * only if the base CRS is itself of kind EngineeringCRS.  Otherwise we will return the
+                     * "type-neutral" DefaultDerivedCRS implementation.   Note that even in the later case,
+                     * the WKT format will still be able to detect that the WKT keyword is "EngineeringCRS".
+                     */
+                    if (baseCRS instanceof EngineeringCRS) {
+                        return new Engineering(properties, (EngineeringCRS) baseCRS, conversion, derivedCS);
+                    }
+                    break;
+                }
             }
         }
         return new DefaultDerivedCRS(properties, baseCRS, conversion, derivedCS);
     }
 
     /**
+     * Creates a derived CRS from a math transform and a type inferred from the given arguments.
+     * This method expects the same arguments and performs the same work than the
+     * {@linkplain #DefaultDerivedCRS(Map, SingleCRS, CoordinateReferenceSystem, OperationMethod, MathTransform,
+     * CoordinateSystem) above constructor},
+     * except that the {@code DerivedCRS} instance returned by this method may additionally implement
+     * the {@link GeodeticCRS}, {@link VerticalCRS}, {@link TemporalCRS} or {@link EngineeringCRS} interface.
+     * See the class javadoc for more information.
+     *
+     * @param  properties       The properties to be given to the {@link DefaultConversion} object
+     *                          (with keys prefixed by {@code "conversion."}) and to the new derived CRS object.
+     * @param  baseCRS          Coordinate reference system to base the derived CRS on.
+     * @param  interpolationCRS The CRS of additional coordinates needed for the operation, or {@code null} if none.
+     * @param  method           The coordinate operation method (mandatory in all cases).
+     * @param  baseToDerived    Transform from positions in the base CRS to positions in this target CRS.
+     * @param  derivedCS        The coordinate system for the derived CRS.
+     * @return The newly created derived CRS, potentially implementing an additional CRS interface.
+     * @throws IllegalArgumentException if at least one argument has an incompatible number of dimensions.
+     *
+     * @see #DefaultDerivedCRS(Map, SingleCRS, CoordinateReferenceSystem, OperationMethod, MathTransform, CoordinateSystem)
+     */
+    public static DefaultDerivedCRS create(final Map<String,?>             properties,
+                                           final SingleCRS                 baseCRS,
+                                           final CoordinateReferenceSystem interpolationCRS,
+                                           final OperationMethod           method,
+                                           final MathTransform             baseToDerived,
+                                           final CoordinateSystem          derivedCS)
+    {
+        if (baseCRS != null && derivedCS != null) {
+            final String type = getType(baseCRS, derivedCS);
+            if (type != null) switch (type) {
+                case WKTKeywords.GeodeticCRS: return new Geodetic(properties, (GeodeticCRS) baseCRS, interpolationCRS, method, baseToDerived, (EllipsoidalCS) derivedCS);
+                case WKTKeywords.VerticalCRS: return new Vertical(properties, (VerticalCRS) baseCRS, interpolationCRS, method, baseToDerived,    (VerticalCS) derivedCS);
+                case WKTKeywords.TimeCRS:     return new Temporal(properties, (TemporalCRS) baseCRS, interpolationCRS, method, baseToDerived,        (TimeCS) derivedCS);
+                case WKTKeywords.EngineeringCRS: {
+                    if (baseCRS instanceof EngineeringCRS) {
+                        // See the comment in create(Map, SingleCRS, Conversion, CoordinateSystem)
+                        return new Engineering(properties, (EngineeringCRS) baseCRS, interpolationCRS, method, baseToDerived, derivedCS);
+                    }
+                    break;
+                }
+            }
+        }
+        return new DefaultDerivedCRS(properties, baseCRS, interpolationCRS, method, baseToDerived, derivedCS);
+    }
+
+    /**
      * Returns a SIS coordinate reference system implementation with the same values than the given
      * arbitrary implementation. If the given object is {@code null}, then this method returns {@code null}.
      * Otherwise if the given object is already a SIS implementation, then the given object is returned unchanged.
@@ -283,8 +410,8 @@ public class DefaultDerivedCRS extends A
     /**
      * Returns the CRS on which the conversion is applied.
      * This CRS defines the {@linkplain #getDatum() datum} of this CRS and (at least implicitly)
-     * the {@linkplain org.apache.sis.referencing.operation.DefaultConversion#getSourceCRS() source}
-     * of the {@linkplain #getConversionFromBase() conversion from base}.
+     * the {@linkplain DefaultConversion#getSourceCRS() source} of
+     * the {@linkplain #getConversionFromBase() conversion from base}.
      *
      * @return The base coordinate reference system.
      */
@@ -298,10 +425,9 @@ public class DefaultDerivedCRS extends A
      * In Apache SIS, the conversion source and target CRS are set to the following values:
      *
      * <ul>
-     *   <li>The conversion {@linkplain org.apache.sis.referencing.operation.DefaultConversion#getSourceCRS()
-     *       source CRS} is the {@linkplain #getBaseCRS() base CRS} of {@code this} CRS.</li>
-     *   <li>The conversion {@linkplain org.apache.sis.referencing.operation.DefaultConversion#getTargetCRS()
-     *       target CRS} is {@code this} CRS.
+     *   <li>The conversion {@linkplain DefaultConversion#getSourceCRS() source CRS}
+     *       is the {@linkplain #getBaseCRS() base CRS} of {@code this} CRS.</li>
+     *   <li>The conversion {@linkplain DefaultConversion#getTargetCRS() target CRS} is {@code this} CRS.
      * </ul>
      *
      * <div class="note"><b>Note:</b>
@@ -478,11 +604,18 @@ public class DefaultDerivedCRS extends A
             super(other);
         }
 
-        /** Creates a new geodetic CRS derived from the given one. */
+        /** Creates a new geodetic CRS from the given properties. */
         Geodetic(Map<String,?> properties, GeodeticCRS baseCRS, Conversion conversion, EllipsoidalCS derivedCS) {
             super(properties, baseCRS, conversion, derivedCS);
         }
 
+        /** Creates a new geodetic CRS from the given properties. */
+        Geodetic(Map<String,?> properties, GeodeticCRS baseCRS, CoordinateReferenceSystem interpolationCRS,
+                OperationMethod method, MathTransform baseToDerived, EllipsoidalCS derivedCS)
+        {
+            super(properties, baseCRS, interpolationCRS, method, baseToDerived, derivedCS);
+        }
+
         /** Returns the datum of the base geodetic CRS. */
         @Override public GeodeticDatum getDatum() {
             return (GeodeticDatum) super.getDatum();
@@ -519,11 +652,18 @@ public class DefaultDerivedCRS extends A
             super(other);
         }
 
-        /** Creates a new vertical CRS derived from the given one. */
+        /** Creates a new vertical CRS from the given properties. */
         Vertical(Map<String,?> properties, VerticalCRS baseCRS, Conversion conversion, VerticalCS derivedCS) {
             super(properties, baseCRS, conversion, derivedCS);
         }
 
+        /** Creates a new vertical CRS from the given properties. */
+        Vertical(Map<String,?> properties, VerticalCRS baseCRS, CoordinateReferenceSystem interpolationCRS,
+                OperationMethod method, MathTransform baseToDerived, VerticalCS derivedCS)
+        {
+            super(properties, baseCRS, interpolationCRS, method, baseToDerived, derivedCS);
+        }
+
         /** Returns the datum of the base vertical CRS. */
         @Override public VerticalDatum getDatum() {
             return (VerticalDatum) super.getDatum();
@@ -560,11 +700,18 @@ public class DefaultDerivedCRS extends A
             super(other);
         }
 
-        /** Creates a new temporal CRS derived from the given one. */
+        /** Creates a new temporal CRS from the given properties. */
         Temporal(Map<String,?> properties, TemporalCRS baseCRS, Conversion conversion, TimeCS derivedCS) {
             super(properties, baseCRS, conversion, derivedCS);
         }
 
+        /** Creates a new temporal CRS from the given properties. */
+        Temporal(Map<String,?> properties, TemporalCRS baseCRS, CoordinateReferenceSystem interpolationCRS,
+                OperationMethod method, MathTransform baseToDerived, TimeCS derivedCS)
+        {
+            super(properties, baseCRS, interpolationCRS, method, baseToDerived, derivedCS);
+        }
+
         /** Returns the datum of the base temporal CRS. */
         @Override public TemporalDatum getDatum() {
             return (TemporalDatum) super.getDatum();
@@ -604,21 +751,27 @@ public class DefaultDerivedCRS extends A
             super(other);
         }
 
-        /** Creates a new temporal CRS derived from the given one. */
-        Engineering(Map<String,?> properties, SingleCRS baseCRS, Conversion conversion, CoordinateSystem derivedCS) {
+        /** Creates a new engineering CRS from the given properties. */
+        Engineering(Map<String,?> properties, EngineeringCRS baseCRS, Conversion conversion, CoordinateSystem derivedCS) {
             super(properties, baseCRS, conversion, derivedCS);
         }
 
+        /** Creates a new engineering CRS from the given properties. */
+        Engineering(Map<String,?> properties, EngineeringCRS baseCRS, CoordinateReferenceSystem interpolationCRS,
+                OperationMethod method, MathTransform baseToDerived, CoordinateSystem derivedCS)
+        {
+            super(properties, baseCRS, interpolationCRS, method, baseToDerived, derivedCS);
+        }
+
         /** Returns the datum of the base engineering CRS. */
         @Override public EngineeringDatum getDatum() {
-            final Datum datum = super.getDatum();
-            return (datum instanceof EngineeringDatum) ? (EngineeringDatum) datum : null;
+            return (EngineeringDatum) super.getDatum();
         }
 
         /** Returns a coordinate reference system of the same type than this CRS but with different axes. */
         @Override AbstractCRS createSameType(final Map<String,?> properties, final CoordinateSystem derivedCS) {
             final Conversion conversionFromBase = getConversionFromBase();
-            return new Engineering(properties, (SingleCRS) conversionFromBase.getSourceCRS(), conversionFromBase, derivedCS);
+            return new Engineering(properties, (EngineeringCRS) conversionFromBase.getSourceCRS(), conversionFromBase, derivedCS);
         }
 
         /** Returns the WKT keyword for this derived CRS type.*/

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java?rev=1683562&r1=1683561&r2=1683562&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java [UTF-8] Thu Jun  4 14:39:07 2015
@@ -145,8 +145,8 @@ public class DefaultProjectedCRS extends
      *                    to a normalized derived CRS.
      * @param  derivedCS  The coordinate system for the derived CRS. The number of axes
      *         must match the target dimension of the {@code baseToDerived} transform.
-     * @throws MismatchedDimensionException if the source and target dimension of {@code baseToDerived}
-     *         do not match the dimension of {@code base} and {@code derivedCS} respectively.
+     * @throws MismatchedDimensionException if the source and target dimensions of {@code baseToDerived}
+     *         do not match the dimensions of {@code base} and {@code derivedCS} respectively.
      */
     public DefaultProjectedCRS(final Map<String,?> properties,
                                final GeographicCRS baseCRS,

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCompoundCS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCompoundCS.java?rev=1683562&r1=1683561&r2=1683562&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCompoundCS.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCompoundCS.java [UTF-8] Thu Jun  4 14:39:07 2015
@@ -20,11 +20,10 @@ import java.util.Map;
 import java.util.List;
 import org.opengis.referencing.cs.CoordinateSystem;
 import org.opengis.referencing.cs.CoordinateSystemAxis;
+import org.apache.sis.internal.referencing.AxisDirections;
 import org.apache.sis.internal.util.UnmodifiableArrayList;
-import org.apache.sis.internal.util.Utilities;
 import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.Workaround;
-import org.apache.sis.util.iso.Types;
 
 import static java.util.Collections.singletonMap;
 import static org.apache.sis.util.ArgumentChecks.*;
@@ -52,7 +51,7 @@ import static org.apache.sis.util.Utilit
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.4
- * @version 0.4
+ * @version 0.6
  * @module
  */
 public class DefaultCompoundCS extends AbstractCS {
@@ -127,38 +126,11 @@ public class DefaultCompoundCS extends A
      */
     @Workaround(library="JDK", version="1.7")
     private DefaultCompoundCS(final CoordinateSystem[] components, final CoordinateSystemAxis[] axes) {
-        super(singletonMap(NAME_KEY, createName(new StringBuilder(60).append("Compound CS"), axes)), axes);
+        super(singletonMap(NAME_KEY, AxisDirections.appendTo(new StringBuilder(60).append("Compound CS"), axes)), axes);
         this.components = UnmodifiableArrayList.wrap(components);
     }
 
     /**
-     * Returns a name for a coordinate system.
-     * Examples:
-     *
-     * <ul>
-     *   <li>Ellipsoidal CS: North (°), East (°).</li>
-     *   <li>Cartesian CS: East (km), North (km).</li>
-     *   <li>Compound CS: East (km), North (km), Up (m).</li>
-     * </ul>
-     *
-     * @param  buffer A buffer filled with the name header.
-     * @param  axes The axes.
-     * @return A name for the given coordinate system type and axes.
-     */
-    static String createName(final StringBuilder buffer, final CoordinateSystemAxis[] axes) {
-        String separator = ": ";
-        for (final CoordinateSystemAxis axis : axes) {
-            buffer.append(separator).append(Types.getCodeLabel(axis.getDirection()));
-            separator = ", ";
-            final String symbol = Utilities.toString(axis.getUnit());
-            if (symbol != null && !symbol.isEmpty()) {
-                buffer.append(" (").append(symbol).append(')');
-            }
-        }
-        return buffer.append('.').toString();
-    }
-
-    /**
      * Returns a clone of the given array, making sure that it contains only non-null elements.
      */
     private static CoordinateSystem[] clone(CoordinateSystem[] components) {

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java?rev=1683562&r1=1683561&r2=1683562&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java [UTF-8] Thu Jun  4 14:39:07 2015
@@ -224,7 +224,7 @@ final class Normalizer implements Compar
          */
         final AbstractCS impl = castOrCopy(cs);
         final StringBuilder buffer = (StringBuilder) CharSequences.camelCaseToSentence(impl.getInterface().getSimpleName());
-        return impl.createForAxes(singletonMap(AbstractCS.NAME_KEY, DefaultCompoundCS.createName(buffer, axes)), axes);
+        return impl.createForAxes(singletonMap(AbstractCS.NAME_KEY, AxisDirections.appendTo(buffer, axes)), axes);
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java?rev=1683562&r1=1683561&r2=1683562&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java [UTF-8] Thu Jun  4 14:39:07 2015
@@ -18,6 +18,8 @@ package org.apache.sis.internal.referenc
 
 import org.opengis.referencing.cs.AxisDirection;
 import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.cs.CoordinateSystemAxis;
+import org.apache.sis.referencing.cs.HardCodedAxes;
 import org.apache.sis.referencing.cs.HardCodedCS;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.TestCase;
@@ -33,7 +35,7 @@ import static org.opengis.referencing.cs
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.5
+ * @version 0.6
  * @module
  */
 public final strictfp class AxisDirectionsTest extends TestCase {
@@ -357,4 +359,18 @@ public final strictfp class AxisDirectio
                 HardCodedCS.GEODETIC_3D,
                 HardCodedCS.DAYS));
     }
+
+    /**
+     * Tests {@link AxisDirections#appendTo(StringBuilder, CoordinateSystemAxis[])}.
+     *
+     * @since 0.6
+     */
+    @Test
+    public void testAppendTo() {
+        final StringBuilder buffer = new StringBuilder("Compound CS");
+        final String name = AxisDirections.appendTo(buffer, new CoordinateSystemAxis[] {
+            HardCodedAxes.EASTING, HardCodedAxes.NORTHING, HardCodedAxes.HEIGHT_cm, HardCodedAxes.TIME
+        });
+        assertEquals("Compound CS: East (m), North (m), Up (cm), Future (d).", name);
+    }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultCompoundCSTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultCompoundCSTest.java?rev=1683562&r1=1683561&r2=1683562&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultCompoundCSTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultCompoundCSTest.java [UTF-8] Thu Jun  4 14:39:07 2015
@@ -16,7 +16,8 @@
  */
 package org.apache.sis.referencing.cs;
 
-import org.opengis.referencing.cs.CoordinateSystemAxis;
+import java.util.Collections;
+import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
@@ -28,19 +29,22 @@ import static org.junit.Assert.*;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.4
+ * @version 0.6
  * @module
  */
+@DependsOn(org.apache.sis.internal.referencing.AxisDirectionsTest.class)
 public final strictfp class DefaultCompoundCSTest extends TestCase {
     /**
-     * Tests {@link DefaultCompoundCS#createName(StringBuilder, CoordinateSystemAxis[])}.
+     * Tests {@link DefaultCompoundCS} construction.
      */
     @Test
-    public void testCreateName() {
-        final StringBuilder buffer = new StringBuilder("Compound CS");
-        final String name = DefaultCompoundCS.createName(buffer, new CoordinateSystemAxis[] {
-            HardCodedAxes.EASTING, HardCodedAxes.NORTHING, HardCodedAxes.HEIGHT_cm, HardCodedAxes.TIME
-        });
-        assertEquals("Compound CS: East (m), North (m), Up (cm), Future (d).", name);
+    public void testConstruction() {
+        final DefaultCompoundCS cs = new DefaultCompoundCS(
+                HardCodedCS.PROJECTED,
+                new DefaultVerticalCS(Collections.singletonMap(DefaultVerticalCS.NAME_KEY,
+                        HardCodedAxes.HEIGHT_cm.getName()), HardCodedAxes.HEIGHT_cm),
+                HardCodedCS.DAYS
+        );
+        assertEquals("Compound CS: East (m), North (m), Up (cm), Future (d).", cs.getName().getCode());
     }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/HardCodedAxes.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/HardCodedAxes.java?rev=1683562&r1=1683561&r2=1683562&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/HardCodedAxes.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/HardCodedAxes.java [UTF-8] Thu Jun  4 14:39:07 2015
@@ -30,7 +30,7 @@ import org.opengis.referencing.cs.RangeM
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.4
+ * @version 0.6
  * @module
  */
 public final strictfp class HardCodedAxes {
@@ -125,9 +125,9 @@ public final strictfp class HardCodedAxe
             AxisDirection.UP, SI.METRE, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, null);
 
     /**
-     * A height in centimetres, for {@link CoordinateSystemsTest} only.
+     * A height in centimetres.
      */
-    static final DefaultCoordinateSystemAxis HEIGHT_cm = create("Height", "h",
+    public static final DefaultCoordinateSystemAxis HEIGHT_cm = create("Height", "h",
             AxisDirection.UP, SI.CENTIMETRE, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, null);
 
     /**

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/Containers.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/Containers.java?rev=1683562&r1=1683561&r2=1683562&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/Containers.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/Containers.java [UTF-8] Thu Jun  4 14:39:07 2015
@@ -174,20 +174,19 @@ public final class Containers extends St
      *
      * <p>The {@link Map#put(Object,Object) Map.put(K,V)} method is supported only if the given
      * converters are {@linkplain org.apache.sis.math.FunctionProperty#INVERTIBLE invertible}.
-     * An invertible converter is not mandatory for other {@code Map} operations.
-     * However some of them are likely to be faster if the inverse converters are available.</p>
+     * An invertible converter is not mandatory for other {@code Map} operations like {@link Map#get(Object)},
+     * but some of them may be faster if the inverse converters are available.</p>
      *
-     * <p>The derived map may contain fewer entries than the original map if some keys
-     * are not convertible. Non-convertible keys are <var>K</var> values for which
-     * {@code keyConverter.apply(K)} returns {@code null}. As a consequence of this sentinel
-     * value usage, the derived map can not contain {@code null} keys.
+     * <p>The derived map may contain fewer entries than the original map if some keys are not convertible.
+     * A key <var>K</var> is non-convertible if {@code keyConverter.apply(K)} returns {@code null}.
+     * As a consequence of this sentinel key usage, the derived map can not contain {@code null} keys.
      * It may contain {@code null} values however.</p>
      *
      * <p>The returned map can be serialized if the given map and converters are serializable.
      * The returned map is <strong>not</strong> thread-safe.</p>
      *
      * <p>The returned map does not implement the {@link CheckedContainer} interface since {@code Map}
-     * is not {@code Collection} sub-type, but the derived map {@linkplain Map#keySet() key set} and
+     * is not a {@code Collection} sub-type, but the derived map {@linkplain Map#keySet() key set} and
      * {@linkplain Map#entrySet() entry set} do.</p>
      *
      * @param <SK>         The type of keys   in the storage map.