sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1683756 [3/6] - in /sis/branches/JDK7: ./ application/sis-console/src/test/java/org/apache/sis/console/ core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ core/sis-metadata/src/main/java/org/apache/sis/io/wkt/ core/sis-metad...
Date Fri, 05 Jun 2015 13:53:59 GMT
Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java?rev=1683756&r1=1683755&r2=1683756&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java [UTF-8] Fri Jun  5 13:53:58 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/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=1683756&r1=1683755&r2=1683756&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] Fri Jun  5 13:53:58 2015
@@ -16,12 +16,25 @@
  */
 package org.apache.sis.internal.referencing;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.io.ObjectStreamException;
 import javax.xml.bind.annotation.XmlTransient;
+import javax.measure.quantity.Length;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+import org.opengis.util.Record;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.quality.PositionalAccuracy;
 import org.opengis.metadata.quality.EvaluationMethodType;
+import org.opengis.metadata.quality.QuantitativeResult;
+import org.opengis.metadata.quality.Result;
+import org.opengis.referencing.operation.ConcatenatedOperation;
+import org.opengis.referencing.operation.Conversion;
+import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.referencing.operation.SingleOperation;
+import org.opengis.referencing.operation.Transformation;
+import org.apache.sis.measure.Units;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.metadata.iso.quality.DefaultConformanceResult;
 import org.apache.sis.metadata.iso.quality.DefaultAbsoluteExternalPositionalAccuracy;
@@ -55,7 +68,7 @@ public final class PositionalAccuracyCon
      *
      * @see org.apache.sis.referencing.operation.AbstractCoordinateOperation#getLinearAccuracy()
      */
-    public static final double UNKNOWN_ACCURACY = 3000;
+    private static final double UNKNOWN_ACCURACY = 3000;
 
     /**
      * Default accuracy of datum shift, if not explicitly provided in the EPSG database.
@@ -66,7 +79,7 @@ public final class PositionalAccuracyCon
      *
      * @see org.apache.sis.referencing.operation.AbstractCoordinateOperation#getLinearAccuracy()
      */
-    public static final double DATUM_SHIFT_ACCURACY = 25;
+    private static final double DATUM_SHIFT_ACCURACY = 25;
 
     /**
      * Indicates that a {@linkplain org.opengis.referencing.operation.Transformation transformation}
@@ -113,4 +126,95 @@ public final class PositionalAccuracyCon
         if (equals(DATUM_SHIFT_OMITTED)) return DATUM_SHIFT_OMITTED;
         return this;
     }
+
+    /**
+     * 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 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 #DATUM_SHIFT_APPLIED} and {@link #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>
+     *
+     * 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 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;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        /*
+         * 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.
+         */
+        if (operation instanceof Transformation) {
+            if (accuracies.contains(DATUM_SHIFT_APPLIED)) {
+                return DATUM_SHIFT_ACCURACY;
+            }
+            if (accuracies.contains(DATUM_SHIFT_OMITTED)) {
+                return UNKNOWN_ACCURACY;
+            }
+        }
+        /*
+         * 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 accuracy;
+    }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java?rev=1683756&r1=1683755&r2=1683756&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java [UTF-8] Fri Jun  5 13:53:58 2015
@@ -16,23 +16,33 @@
  */
 package org.apache.sis.internal.referencing;
 
-import org.apache.sis.internal.metadata.WKTKeywords;
+import java.util.Map;
 import java.util.Iterator;
 import java.util.Collection;
+import java.util.Collections;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+import javax.measure.quantity.Length;
 
 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.CartesianCS;
 import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.cs.CoordinateSystemAxis;
+import org.opengis.referencing.datum.PrimeMeridian;
 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;
@@ -40,16 +50,25 @@ import org.opengis.metadata.extent.Geogr
 import org.opengis.metadata.extent.VerticalExtent;
 import org.opengis.geometry.Envelope;
 
+import org.opengis.referencing.cs.AxisDirection;
 import org.apache.sis.geometry.Envelopes;
 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.cs.AxisFilter;
+import org.apache.sis.referencing.cs.CoordinateSystems;
+import org.apache.sis.referencing.crs.DefaultDerivedCRS;
 import org.apache.sis.referencing.crs.DefaultTemporalCRS;
+import org.apache.sis.referencing.datum.BursaWolfParameters;
 import org.apache.sis.referencing.operation.transform.MathTransforms;
+import org.apache.sis.referencing.operation.DefaultCoordinateOperationFactory;
 import org.apache.sis.parameter.DefaultParameterDescriptor;
 import org.apache.sis.parameter.Parameterized;
 import org.apache.sis.io.wkt.Formatter;
 import org.apache.sis.io.wkt.FormattableObject;
+import org.apache.sis.internal.metadata.WKTKeywords;
 import org.apache.sis.metadata.iso.extent.DefaultExtent;
 import org.apache.sis.metadata.iso.extent.DefaultVerticalExtent;
 import org.apache.sis.metadata.iso.extent.DefaultTemporalExtent;
@@ -58,6 +77,7 @@ import org.apache.sis.metadata.iso.exten
 import org.apache.sis.internal.metadata.ReferencingServices;
 import org.apache.sis.internal.referencing.provider.Affine;
 import org.apache.sis.internal.system.DefaultFactories;
+import org.apache.sis.util.collection.Containers;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.Utilities;
 
@@ -77,77 +97,14 @@ public final class ServicesForMetadata e
     public ServicesForMetadata() {
     }
 
-    /**
-     * Returns a fully implemented parameter descriptor.
-     *
-     * @param  parameter A partially implemented parameter descriptor, or {@code null}.
-     * @return A fully implemented parameter descriptor, or {@code null} if the given argument was null.
-     */
-    @Override
-    public ParameterDescriptor<?> toImplementation(final ParameterDescriptor<?> parameter) {
-        return DefaultParameterDescriptor.castOrCopy(parameter);
-    }
 
-    /**
-     * Converts the given object in a {@code FormattableObject} instance.
-     *
-     * @param  object The object to wrap.
-     * @return The given object converted to a {@code FormattableObject} instance.
-     */
-    @Override
-    public FormattableObject toFormattableObject(final IdentifiedObject object) {
-        return AbstractIdentifiedObject.castOrCopy(object);
-    }
 
-    /**
-     * Converts the given object in a {@code FormattableObject} instance. Callers should verify that the given
-     * object is not already an instance of {@code FormattableObject} before to invoke this method. This method
-     * returns {@code null} if it can not convert the object.
-     *
-     * @param  object The object to wrap.
-     * @param  internal {@code true} if the formatting convention is {@code Convention.INTERNAL}.
-     * @return The given object converted to a {@code FormattableObject} instance, or {@code null}.
-     *
-     * @since 0.6
-     */
-    @Override
-    public FormattableObject toFormattableObject(final MathTransform object, boolean internal) {
-        Matrix matrix;
-        final ParameterValueGroup parameters;
-        if (internal && (matrix = MathTransforms.getMatrix(object)) != null) {
-            parameters = Affine.parameters(matrix);
-        } else if (object instanceof Parameterized) {
-            parameters = ((Parameterized) object).getParameterValues();
-        } else {
-            matrix = MathTransforms.getMatrix(object);
-            if (matrix == null) {
-                return null;
-            }
-            parameters = Affine.parameters(matrix);
-        }
-        return new FormattableObject() {
-            @Override
-            protected String formatTo(final Formatter formatter) {
-                WKTUtilities.appendParamMT(parameters, formatter);
-                return WKTKeywords.Param_MT;
-            }
-        };
-    }
 
-    /**
-     * Returns the coordinate operation factory to be used for transforming the envelope.
-     * We will fetch a lenient factory because {@link GeographicBoundingBox} are usually for approximative
-     * bounds (e.g. the area of validity of some CRS). If a user wants accurate bounds, he should probably
-     * use an {@link Envelope} with the appropriate CRS.
-     */
-    private static CoordinateOperationFactory getFactory() throws TransformException {
-        // TODO: specify a lenient factory when the API will allow that.
-        final CoordinateOperationFactory factory = DefaultFactories.forClass(CoordinateOperationFactory.class);
-        if (factory != null) {
-            return factory;
-        }
-        throw new TransformException(Errors.format(Errors.Keys.MissingRequiredModule_1, "geotk-referencing")); // This is temporary.
-    }
+    ///////////////////////////////////////////////////////////////////////////////////////
+    ////                                                                               ////
+    ////                        SERVICES FOR ISO 19115 METADATA                        ////
+    ////                                                                               ////
+    ///////////////////////////////////////////////////////////////////////////////////////
 
     /**
      * Creates an exception message for a spatial, vertical or temporal dimension not found.
@@ -182,8 +139,9 @@ public final class ServicesForMetadata e
                 !Utilities.equalsIgnoreMetadata(cs2.getAxis(1), cs1.getAxis(1)))
             {
                 final CoordinateOperation operation;
+                final CoordinateOperationFactory factory = DefaultFactories.forBuildin(CoordinateOperationFactory.class);
                 try {
-                    operation = getFactory().createOperation(crs, normalizedCRS);
+                    operation = factory.createOperation(crs, normalizedCRS);
                 } catch (FactoryException e) {
                     throw new TransformException(Errors.format(Errors.Keys.CanNotTransformEnvelopeToGeodetic), e);
                 }
@@ -414,4 +372,225 @@ public final class ServicesForMetadata e
             target.getTemporalElements().add(extent);
         }
     }
+
+
+
+
+    ///////////////////////////////////////////////////////////////////////////////////////
+    ////                                                                               ////
+    ////                          SERVICES FOR WKT FORMATTING                          ////
+    ////                                                                               ////
+    ///////////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Returns a fully implemented parameter descriptor.
+     *
+     * @param  parameter A partially implemented parameter descriptor, or {@code null}.
+     * @return A fully implemented parameter descriptor, or {@code null} if the given argument was null.
+     */
+    @Override
+    public ParameterDescriptor<?> toImplementation(final ParameterDescriptor<?> parameter) {
+        return DefaultParameterDescriptor.castOrCopy(parameter);
+    }
+
+    /**
+     * Converts the given object in a {@code FormattableObject} instance.
+     *
+     * @param  object The object to wrap.
+     * @return The given object converted to a {@code FormattableObject} instance.
+     */
+    @Override
+    public FormattableObject toFormattableObject(final IdentifiedObject object) {
+        return AbstractIdentifiedObject.castOrCopy(object);
+    }
+
+    /**
+     * Converts the given object in a {@code FormattableObject} instance. Callers should verify that the given
+     * object is not already an instance of {@code FormattableObject} before to invoke this method. This method
+     * returns {@code null} if it can not convert the object.
+     *
+     * @param  object The object to wrap.
+     * @param  internal {@code true} if the formatting convention is {@code Convention.INTERNAL}.
+     * @return The given object converted to a {@code FormattableObject} instance, or {@code null}.
+     *
+     * @since 0.6
+     */
+    @Override
+    public FormattableObject toFormattableObject(final MathTransform object, boolean internal) {
+        Matrix matrix;
+        final ParameterValueGroup parameters;
+        if (internal && (matrix = MathTransforms.getMatrix(object)) != null) {
+            parameters = Affine.parameters(matrix);
+        } else if (object instanceof Parameterized) {
+            parameters = ((Parameterized) object).getParameterValues();
+        } else {
+            matrix = MathTransforms.getMatrix(object);
+            if (matrix == null) {
+                return null;
+            }
+            parameters = Affine.parameters(matrix);
+        }
+        return new FormattableObject() {
+            @Override
+            protected String formatTo(final Formatter formatter) {
+                WKTUtilities.appendParamMT(parameters, formatter);
+                return WKTKeywords.Param_MT;
+            }
+        };
+    }
+
+
+
+
+    ///////////////////////////////////////////////////////////////////////////////////////
+    ////                                                                               ////
+    ////                           SERVICES FOR WKT PARSING                            ////
+    ////                                                                               ////
+    ///////////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Returns the Greenwich prime meridian.
+     *
+     * @return The Greenwich prime meridian.
+     *
+     * @since 0.6
+     */
+    @Override
+    public PrimeMeridian getGreenwich() {
+        return CommonCRS.WGS84.primeMeridian();
+    }
+
+    /**
+     * Returns the coordinate system of a geocentric CRS using axes in the given unit of measurement.
+     *
+     * @param  linearUnit The unit of measurement for the geocentric CRS axes.
+     * @return The coordinate system for a geocentric CRS with axes using the given unit of measurement.
+     *
+     * @since 0.6
+     */
+    @Override
+    public CartesianCS getGeocentricCS(final Unit<Length> linearUnit) {
+        CartesianCS cs = (CartesianCS) CommonCRS.WGS84.geocentric().getCoordinateSystem();
+        if (!SI.METRE.equals(linearUnit)) {
+            cs = (CartesianCS) CoordinateSystems.replaceAxes(cs, new AxisFilter() {
+                @Override public boolean accept(final CoordinateSystemAxis axis) {
+                    return true;
+                }
+
+                @Override public Unit<?> getUnitReplacement(final Unit<?> unit) {
+                    return linearUnit;
+                }
+
+                @Override public AxisDirection getDirectionReplacement(final AxisDirection direction) {
+                    return direction;
+                }
+            });
+        }
+        return cs;
+    }
+
+    /**
+     * Converts a geocentric coordinate system from the legacy WKT 1 to the current ISO 19111 standard.
+     * This method replaces the (Other, East, North) directions by (Geocentric X, Geocentric Y, Geocentric Z).
+     *
+     * @param  cs The geocentric coordinate system to upgrade.
+     * @return The upgraded coordinate system, or {@code cs} if there is no change to apply.
+     *
+     * @since 0.6
+     */
+    @Override
+    public CartesianCS upgradeGeocentricCS(final CartesianCS cs) {
+        return Legacy.forGeocentricCRS(cs, false);
+    }
+
+    /**
+     * 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.
+     *
+     * @since 0.6
+     */
+    @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.
+     *
+     * @since 0.6
+     */
+    @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);
+    }
+
+    /**
+     * Creates the {@code TOWGS84} element during parsing of a WKT version 1.
+     *
+     * @param  values The 7 Bursa-Wolf parameter values.
+     * @return The {@link BursaWolfParameters}.
+     *
+     * @since 0.6
+     */
+    @Override
+    public Object createToWGS84(final double[] values) {
+        final BursaWolfParameters info = new BursaWolfParameters(CommonCRS.WGS84.datum(), null);
+        info.setValues(values);
+        return info;
+    }
+
+    /**
+     * Returns the coordinate operation factory to use for the given properties and math transform factory.
+     * If the given properties are empty and the {@code mtFactory} is the system default, then this method
+     * returns the system default {@code CoordinateOperationFactory} instead of creating a new one.
+     *
+     * @param  properties The default properties.
+     * @param  mtFactory  The math transform factory to use.
+     * @return The coordinate operation factory to use.
+     *
+     * @since 0.6
+     */
+    @Override
+    public CoordinateOperationFactory getCoordinateOperationFactory(Map<String,?> properties, MathTransformFactory mtFactory) {
+        if (Containers.isNullOrEmpty(properties) && DefaultFactories.isDefaultInstance(MathTransformFactory.class, mtFactory)) {
+            return DefaultFactories.forBuildin(CoordinateOperationFactory.class);
+        } else {
+            return new DefaultCoordinateOperationFactory(properties, mtFactory);
+        }
+    }
+
+    /**
+     * Returns {@code true} if the {@linkplain AbstractIdentifiedObject#getName() primary name} or an aliases
+     * of the given object matches the given name.
+     *
+     * @param  object The object for which to check the name or alias.
+     * @param  name The name to compare with the object name or aliases.
+     * @return {@code true} if the primary name of at least one alias matches the specified {@code name}.
+     *
+     * @since 0.6
+     */
+    @Override
+    public boolean isHeuristicMatchForName(final IdentifiedObject object, final String name) {
+        return IdentifiedObjects.isHeuristicMatchForName(object, name);
+    }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java?rev=1683756&r1=1683755&r2=1683756&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java [UTF-8] Fri Jun  5 13:53:58 2015
@@ -36,6 +36,9 @@ import org.apache.sis.util.resources.Err
 
 import static org.apache.sis.referencing.IdentifiedObjects.isHeuristicMatchForName;
 
+// Branch-dependent imports
+import org.apache.sis.internal.jdk8.JDK8;
+
 
 /**
  * Convenience methods for fetching parameter values despite the variations in parameter names, value types and units.
@@ -646,24 +649,19 @@ public abstract class Parameters impleme
     public static void copy(final ParameterValueGroup values, final ParameterValueGroup destination)
             throws InvalidParameterNameException, InvalidParameterValueException
     {
-        final Integer ONE = 1;
+        final Integer ZERO = 0;
         final Map<String,Integer> occurrences = new HashMap<>();
         for (final GeneralParameterValue value : values.values()) {
             final String name = value.getDescriptor().getName().getCode();
+            final int occurrence = JDK8.getOrDefault(occurrences, name, ZERO);
             if (value instanceof ParameterValueGroup) {
                 /*
                  * Contains sub-group - invokes 'copy' recursively.
+                 * The target group may exist, but not necessarily.
                  */
-                final GeneralParameterDescriptor descriptor;
-                descriptor = destination.getDescriptor().descriptor(name);
-                if (descriptor instanceof ParameterDescriptorGroup) {
-                    final ParameterValueGroup groups = (ParameterValueGroup) descriptor.createValue();
-                    copy((ParameterValueGroup) value, groups);
-                    values.groups(name).add(groups);
-                } else {
-                    throw new InvalidParameterNameException(Errors.format(
-                            Errors.Keys.UnexpectedParameter_1, name), name);
-                }
+                final List<ParameterValueGroup> groups = destination.groups(name);
+                copy((ParameterValueGroup) value, (occurrence < groups.size())
+                        ? groups.get(occurrence) : destination.addGroup(name));
             } else {
                 /*
                  * Single parameter - copy the value, with special care for value with units
@@ -672,9 +670,7 @@ public abstract class Parameters impleme
                  */
                 final ParameterValue<?> source = (ParameterValue<?>) value;
                 final ParameterValue<?> target;
-                Integer occurrence = occurrences.get(name);
-                if (occurrence == null) {
-                    occurrence = ONE;
+                if (occurrence == 0) {
                     try {
                         target = destination.parameter(name);
                     } catch (ParameterNotFoundException cause) {
@@ -683,9 +679,7 @@ public abstract class Parameters impleme
                     }
                 } else {
                     target = (ParameterValue<?>) getOrCreate(destination, name, occurrence);
-                    occurrence++;
                 }
-                occurrences.put(name, occurrence);
                 final Object  v    = source.getValue();
                 final Unit<?> unit = source.getUnit();
                 if (unit == null) {
@@ -699,6 +693,7 @@ public abstract class Parameters impleme
                             Errors.Keys.IllegalArgumentValue_2, name, v), name, v);
                 }
             }
+            occurrences.put(name, occurrence + 1);
         }
     }
 

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=1683756&r1=1683755&r2=1683756&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] Fri Jun  5 13:53:58 2015
@@ -43,6 +43,7 @@ import org.apache.sis.internal.metadata.
 import org.apache.sis.internal.jaxb.referencing.Code;
 import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.internal.util.UnmodifiableArrayList;
+import org.apache.sis.internal.metadata.NameToIdentifier;
 import org.apache.sis.internal.referencing.WKTUtilities;
 import org.apache.sis.internal.referencing.ReferencingUtilities;
 import org.apache.sis.internal.system.DefaultFactories;
@@ -55,6 +56,7 @@ import org.apache.sis.util.ComparisonMod
 import org.apache.sis.util.LenientComparable;
 import org.apache.sis.util.Classes;
 import org.apache.sis.util.iso.Types;
+import org.apache.sis.util.iso.DefaultNameFactory;
 import org.apache.sis.util.resources.Errors;
 
 import static org.apache.sis.util.ArgumentChecks.*;
@@ -66,7 +68,6 @@ import static org.apache.sis.internal.ut
 
 // Branch-dependent imports
 import java.util.Objects;
-import org.apache.sis.util.iso.DefaultNameFactory;
 
 
 /**
@@ -788,7 +789,7 @@ public class AbstractIdentifiedObject ex
      * @see IdentifiedObjects#isHeuristicMatchForName(IdentifiedObject, String)
      */
     public boolean isHeuristicMatchForName(final String name) {
-        return IdentifiedObjects.isHeuristicMatchForName(this.name, alias, name);
+        return NameToIdentifier.isHeuristicMatchForName(this.name, alias, name);
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/DeprecatedCode.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/DeprecatedCode.java?rev=1683756&r1=1683755&r2=1683756&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/DeprecatedCode.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/DeprecatedCode.java [UTF-8] Fri Jun  5 13:53:58 2015
@@ -24,9 +24,15 @@ import org.apache.sis.util.resources.Voc
 
 
 /**
- * An identifier for a deprecated identifier.
+ * An identifier which should not be used anymore.
  * This is used mostly for deprecated EPSG codes.
  *
+ * <div class="note"><b>Implementation note:</b>
+ * this class opportunistically recycle the {@linkplain #getDescription() description} property into a
+ * {@linkplain #getRemarks() remarks} property. This is a lazy way to inherit {@link #equals(Object)}
+ * and {@link #hashCode()} implementation without adding code in this class for taking in account a
+ * new field.</div>
+ *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.6
  * @version 0.6
@@ -39,13 +45,6 @@ final class DeprecatedCode extends Immut
     private static final long serialVersionUID = 357222258307746767L;
 
     /**
-     * Information about the replacement for this identifier.
-     *
-     * @see #getRemarks()
-     */
-    private final InternationalString remarks;
-
-    /**
      * Creates a deprecated identifier.
      *
      * @param supersededBy The code that replace this one.
@@ -53,8 +52,8 @@ final class DeprecatedCode extends Immut
     DeprecatedCode(final Citation authority, final String codeSpace,
             final String code, final String version, final CharSequence supersededBy)
     {
-        super(authority, codeSpace, code, version, null);
-        remarks = Vocabulary.formatInternational(Vocabulary.Keys.SupersededBy_1, supersededBy);
+        super(authority, codeSpace, code, version,
+                Vocabulary.formatInternational(Vocabulary.Keys.SupersededBy_1, supersededBy));
     }
 
     /**
@@ -76,6 +75,17 @@ final class DeprecatedCode extends Immut
      */
     @Override
     public InternationalString getRemarks() {
-        return remarks;
+        return super.getDescription();
+    }
+
+    /**
+     * Returns {@code null}, since we used the description for the superseded information.
+     * See <cite>"Implementation note"</cite> in class javadoc.
+     *
+     * @return {@code null}.
+     */
+    @Override
+    public InternationalString getDescription() {
+        return null;
     }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java?rev=1683756&r1=1683755&r2=1683756&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java [UTF-8] Fri Jun  5 13:53:58 2015
@@ -33,9 +33,9 @@ import org.apache.sis.util.Static;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.iso.DefaultNameSpace;
 import org.apache.sis.metadata.iso.citation.Citations; // For javadoc.
+import org.apache.sis.internal.metadata.NameToIdentifier;
 
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
-import static org.apache.sis.util.Characters.Filter.LETTERS_AND_DIGITS;
 import static org.apache.sis.internal.util.Citations.iterator;
 import static org.apache.sis.internal.util.Citations.identifierMatches;
 
@@ -85,6 +85,15 @@ public final class IdentifiedObjects ext
      *       <td>{@link CoordinateOperation#getCoordinateOperationAccuracy()}</td></tr>
      * </table>
      *
+     * <div class="note"><b>Note:</b>
+     * the current implementation does not provide
+     * {@value org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis#MINIMUM_VALUE_KEY},
+     * {@value org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis#MAXIMUM_VALUE_KEY} or
+     * {@value org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis#RANGE_MEANING_KEY} entry for
+     * {@link org.opengis.referencing.cs.CoordinateSystemAxis} instances because the minimum and maximum
+     * values depend on the {@linkplain org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis#getUnit()
+     * units of measurement}.</div>
+     *
      * @param  object The identified object to view as a properties map.
      * @param  excludes The keys of properties to exclude from the map.
      * @return An view of the identified object as an immutable map.
@@ -396,51 +405,8 @@ public final class IdentifiedObjects ext
             return ((AbstractIdentifiedObject) object).isHeuristicMatchForName(name);
         } else {
             ensureNonNull("object", object);
-            return isHeuristicMatchForName(object.getName(), object.getAlias(), name);
-        }
-    }
-
-    /**
-     * Returns {@code true} if the given {@linkplain AbstractIdentifiedObject#getName() primary name} or one
-     * of the given aliases matches the given name. The comparison ignores case, some Latin diacritical signs
-     * and any characters that are not letters or digits.
-     *
-     * @param  name     The name of the {@code IdentifiedObject} to check.
-     * @param  aliases  The list of alias in the {@code IdentifiedObject} (may be {@code null}).
-     *                  This method will never modify this list. Consequently, the
-     *                  given list can be a direct reference to an internal list.
-     * @param  toSearch The name for which to check for equality.
-     * @return {@code true} if the primary name or at least one alias matches the given {@code name}.
-     */
-    static boolean isHeuristicMatchForName(final Identifier name, final Collection<GenericName> aliases,
-            CharSequence toSearch)
-    {
-        toSearch = CharSequences.toASCII(toSearch);
-        if (name != null) { // Paranoiac check.
-            final CharSequence code = CharSequences.toASCII(name.getCode());
-            if (code != null) { // Paranoiac check.
-                if (CharSequences.equalsFiltered(toSearch, code, LETTERS_AND_DIGITS, true)) {
-                    return true;
-                }
-            }
-        }
-        if (aliases != null) {
-            for (final GenericName alias : aliases) {
-                if (alias != null) { // Paranoiac check.
-                    final CharSequence tip = CharSequences.toASCII(alias.tip().toString());
-                    if (CharSequences.equalsFiltered(toSearch, tip, LETTERS_AND_DIGITS, true)) {
-                        return true;
-                    }
-                    /*
-                     * Note: a previous version compared also the scoped names. We removed that part,
-                     * because experience has shown that this method is used only for the "code" part
-                     * of an object name. If we really want to compare scoped name, it would probably
-                     * be better to take a GenericName argument instead than String.
-                     */
-                }
-            }
+            return NameToIdentifier.isHeuristicMatchForName(object.getName(), object.getAlias(), name);
         }
-        return false;
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java?rev=1683756&r1=1683755&r2=1683756&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java [UTF-8] Fri Jun  5 13:53:58 2015
@@ -25,13 +25,15 @@ 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;
 import org.opengis.geometry.MismatchedDimensionException;
 import org.apache.sis.referencing.operation.DefaultConversion;
-import org.apache.sis.internal.referencing.OperationMethods;
+import org.apache.sis.internal.metadata.ReferencingServices;
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.internal.system.Semaphores;
 import org.apache.sis.util.resources.Errors;
@@ -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.
@@ -136,7 +159,7 @@ abstract class AbstractDerivedCRS<C exte
     private C createConversionFromBase(final Map<String,?> properties, final SingleCRS baseCRS, final Conversion conversion) {
         MathTransformFactory factory = null;
         if (properties != null) {
-            factory = (MathTransformFactory) properties.get(OperationMethods.MT_FACTORY);
+            factory = (MathTransformFactory) properties.get(ReferencingServices.MT_FACTORY);
         }
         if (factory == null) {
             factory = DefaultFactories.forBuildin(MathTransformFactory.class);

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java?rev=1683756&r1=1683755&r2=1683756&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java [UTF-8] Fri Jun  5 13:53:58 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/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java?rev=1683756&r1=1683755&r2=1683756&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java [UTF-8] Fri Jun  5 13:53:58 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/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=1683756&r1=1683755&r2=1683756&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] Fri Jun  5 13:53:58 2015
@@ -65,7 +65,7 @@ import static org.apache.sis.util.Utilit
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.4
- * @version 0.5
+ * @version 0.6
  * @module
  *
  * @see DefaultCoordinateSystemAxis
@@ -224,7 +224,7 @@ public class AbstractCS extends Abstract
     protected AbstractCS(final CoordinateSystem cs) {
         super(cs);
         if (cs instanceof AbstractCS) {
-            axes = ((AbstractCS) cs).axes; // Share the array.
+            axes = ((AbstractCS) cs).axes;  // Share the array.
         } else {
             axes = new CoordinateSystemAxis[cs.getDimension()];
             for (int i=0; i<axes.length; i++) {
@@ -340,12 +340,9 @@ public class AbstractCS extends Abstract
         }
         AbstractCS cs = derived.get(convention);
         if (cs == null) {
-            switch (convention) {
-                case NORMALIZED:              cs = Normalizer.normalize(this, true,  true);  break;
-                case CONVENTIONALLY_ORIENTED: cs = Normalizer.normalize(this, true,  false); break;
-                case RIGHT_HANDED:            cs = Normalizer.normalize(this, false, false); break;
-                case POSITIVE_RANGE:          cs = Normalizer.shiftAxisRange(this);          break;
-                default: throw new AssertionError(convention);
+            cs = Normalizer.forConvention(this, convention);
+            if (cs == null) {
+                cs = this;  // This coordinate system is already normalized.
             }
             for (final AbstractCS existing : derived.values()) {
                 if (cs.equals(existing)) {
@@ -359,17 +356,36 @@ public class AbstractCS extends Abstract
     }
 
     /**
-     * Returns a coordinate system of the same type than this CS but with different axes.
+     * Returns a coordinate system usually of the same type than this CS but with different axes.
      * This method shall be overridden by all {@code AbstractCS} subclasses in this package.
      *
+     * <p>This method returns a coordinate system of the same type if the number of axes is unchanged.
+     * But if the given {@code axes} array has less elements than this coordinate system dimension, then
+     * this method may return an other kind of coordinate system. See {@link AxisFilter} for an example.</p>
+     *
      * @param  axes The set of axes to give to the new coordinate system.
      * @return A new coordinate system of the same type than {@code this}, but using the given axes.
      */
-    AbstractCS createSameType(final Map<String,?> properties, final CoordinateSystemAxis[] axes) {
+    AbstractCS createForAxes(final Map<String,?> properties, final CoordinateSystemAxis[] axes) {
         return new AbstractCS(properties, axes);
     }
 
     /**
+     * Convenience method for implementations of {@link #createForAxes(Map, CoordinateSystemAxis[])}
+     * when the resulting coordinate system would have an unexpected number of dimensions.
+     *
+     * @param properties The properties which was supposed to be given to the constructor.
+     * @param axes       The axes which was supposed to be given to the constructor.
+     * @param expected   The minimal expected number of dimensions (may be less than {@link #getDimension()}).
+     */
+    static IllegalArgumentException unexpectedDimension(final Map<String,?> properties,
+            final CoordinateSystemAxis[] axes, final int expected)
+    {
+        return new IllegalArgumentException(Errors.getResources(properties).getString(
+                Errors.Keys.MismatchedDimension_3, "filter(cs)", expected, axes.length));
+    }
+
+    /**
      * Compares the specified object with this coordinate system for equality.
      *
      * @param  object The object to compare to {@code this}.

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java?rev=1683756&r1=1683755&r2=1683756&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java [UTF-8] Fri Jun  5 13:53:58 2015
@@ -16,8 +16,14 @@
  */
 package org.apache.sis.referencing.cs;
 
-import org.opengis.referencing.cs.AxisDirection;    // For javadoc
+import javax.measure.unit.Unit;
+import javax.measure.unit.SI;
+import javax.measure.unit.NonSI;
+import org.opengis.referencing.cs.AxisDirection;
 import org.opengis.referencing.cs.CoordinateSystem; // For javadoc
+import org.opengis.referencing.cs.CoordinateSystemAxis;
+import org.apache.sis.internal.referencing.AxisDirections;
+import org.apache.sis.measure.Units;
 
 
 /**
@@ -102,13 +108,13 @@ import org.opengis.referencing.cs.Coordi
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.5
+ * @version 0.6
  * @module
  *
  * @see AbstractCS#forConvention(AxesConvention)
  * @see org.apache.sis.referencing.crs.AbstractCRS#forConvention(AxesConvention)
  */
-public enum AxesConvention {
+public enum AxesConvention implements AxisFilter {
     /**
      * Axes order, direction and units of measure are forced to commonly used pre-defined values.
      * This enum represents the following changes to apply on a coordinate system:
@@ -140,7 +146,32 @@ public enum AxesConvention {
      * @see CoordinateSystems#normalize(CoordinateSystem)
      * @see org.apache.sis.referencing.CommonCRS#normalizedGeographic()
      */
-    NORMALIZED,
+    NORMALIZED {
+        @Override
+        public boolean accept(final CoordinateSystemAxis axis) {
+            return true;
+        }
+
+        @Override
+        public Unit<?> getUnitReplacement(Unit<?> unit) {
+            if (Units.isLinear(unit)) {
+                unit = SI.METRE;
+            } else if (Units.isAngular(unit)) {
+                unit = NonSI.DEGREE_ANGLE;
+            } else if (Units.isTemporal(unit)) {
+                unit = NonSI.DAY;
+            }
+            return unit;
+        }
+
+        /*
+         * Same policy than AxesConvention.CONVENTIONALLY_ORIENTATED.
+         */
+        @Override
+        public AxisDirection getDirectionReplacement(final AxisDirection direction) {
+            return AxisDirections.isIntercardinal(direction) ? direction : AxisDirections.absolute(direction);
+        }
+    },
 
     /**
      * Axes are oriented toward conventional directions and ordered for a {@linkplain #RIGHT_HANDED right-handed}
@@ -189,7 +220,26 @@ public enum AxesConvention {
      *
      * @since 0.5
      */
-    CONVENTIONALLY_ORIENTED,
+    CONVENTIONALLY_ORIENTED {
+        @Override
+        public boolean accept(final CoordinateSystemAxis axis) {
+            return true;
+        }
+
+        @Override
+        public Unit<?> getUnitReplacement(final Unit<?> unit) {
+            return unit;
+        }
+
+        /*
+         * For now we do not touch to inter-cardinal directions (e.g. "North-East")
+         * because it is not clear which normalization policy would match common usage.
+         */
+        @Override
+        public AxisDirection getDirectionReplacement(final AxisDirection direction) {
+            return AxisDirections.isIntercardinal(direction) ? direction : AxisDirections.absolute(direction);
+        }
+    },
 
     /**
      * Axes are ordered for a <cite>right-handed</cite> coordinate system. Axis directions, ranges or ordinate values
@@ -218,7 +268,22 @@ public enum AxesConvention {
      * @see org.apache.sis.referencing.cs.CoordinateSystems#angle(AxisDirection, AxisDirection)
      * @see <a href="http://en.wikipedia.org/wiki/Right_hand_rule">Right-hand rule on Wikipedia</a>
      */
-    RIGHT_HANDED,
+    RIGHT_HANDED {
+        @Override
+        public boolean accept(final CoordinateSystemAxis axis) {
+            return true;
+        }
+
+        @Override
+        public Unit<?> getUnitReplacement(final Unit<?> unit) {
+            return unit;
+        }
+
+        @Override
+        public AxisDirection getDirectionReplacement(final AxisDirection direction) {
+            return direction;
+        }
+    },
 
     /**
      * Axes having a <cite>wraparound</cite>
@@ -243,5 +308,20 @@ public enum AxesConvention {
      *
      * @see org.opengis.referencing.cs.RangeMeaning#WRAPAROUND
      */
-    POSITIVE_RANGE
+    POSITIVE_RANGE {
+        @Override
+        public boolean accept(final CoordinateSystemAxis axis) {
+            return true;
+        }
+
+        @Override
+        public Unit<?> getUnitReplacement(final Unit<?> unit) {
+            return unit;
+        }
+
+        @Override
+        public AxisDirection getDirectionReplacement(final AxisDirection direction) {
+            return direction;
+        }
+    }
 }

Copied: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxisFilter.java (from r1683748, sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxisFilter.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxisFilter.java?p2=sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxisFilter.java&p1=sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxisFilter.java&r1=1683748&r2=1683756&rev=1683756&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxisFilter.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxisFilter.java [UTF-8] Fri Jun  5 13:53:58 2015
@@ -36,10 +36,6 @@ import javax.measure.unit.Unit;
  * For example excluding the <var>z</var> axis of a {@linkplain DefaultCylindricalCS cylindrical} coordinate system
  * results in a {@linkplain DefaultPolarCS polar} coordinate system.</p>
  *
- * <div class="section">Default implementation</div>
- * All methods in this interface have a default implementation equivalent to <i>no-operation</i>.
- * Implementors need to override only the methods for the aspects to change.
- *
  * <div class="section">Limitations</div>
  * This interface is not for changing axis order.
  * For changing axis order in addition to axis directions or units, see {@link AxesConvention}.
@@ -54,18 +50,14 @@ import javax.measure.unit.Unit;
 public interface AxisFilter {
     /**
      * Returns {@code true} if the given axis shall be included in the new coordinate system.
-     * The default implementation unconditionally returns {@code true}.
      *
      * @param  axis The axis to test.
      * @return {@code true} if the given axis shall be included in the new coordinate system.
      */
-    default boolean accept(CoordinateSystemAxis axis) {
-        return true;
-    }
+    boolean accept(CoordinateSystemAxis axis);
 
     /**
      * Returns a replacement for the given axis direction.
-     * The default implementation unconditionally returns the given {@code direction} unchanged.
      *
      * <div class="note"><b>Example:</b>
      * for forcing the direction of the <var>z</var> axis toward up while leaving other axes unchanged,
@@ -85,13 +77,10 @@ public interface AxisFilter {
      * @param  direction The original axis direction.
      * @return The new axis direction, or {@code direction} if there is no change.
      */
-    default AxisDirection getDirectionReplacement(AxisDirection direction) {
-        return direction;
-    }
+    AxisDirection getDirectionReplacement(AxisDirection direction);
 
     /**
      * Returns a replacement for the given axis unit.
-     * The default implementation unconditionally returns the given {@code unit} unchanged.
      *
      * <div class="note"><b>Example:</b>
      * for replacing all angular units of a coordinate system to degrees (regardless what the original
@@ -111,7 +100,5 @@ public interface AxisFilter {
      * @param  unit The original axis unit.
      * @return The new axis unit, or {@code unit} if there is no change.
      */
-    default Unit<?> getUnitReplacement(Unit<?> unit) {
-        return unit;
-    }
+    Unit<?> getUnitReplacement(Unit<?> unit);
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java?rev=1683756&r1=1683755&r2=1683756&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java [UTF-8] Fri Jun  5 13:53:58 2015
@@ -43,6 +43,9 @@ import java.util.Objects;
 
 /**
  * Utility methods working on {@link CoordinateSystem} objects and their axes.
+ * Those methods allow for example to {@linkplain #angle estimate an angle between two axes}
+ * or {@linkplain #swapAndScaleAxes determining the change of axis directions and units}
+ * between two coordinate systems.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.4
@@ -300,38 +303,71 @@ public final class CoordinateSystems ext
     }
 
     /**
-     * Returns a coordinate system with {@linkplain AxesConvention#NORMALIZED normalized} axis order and units.
-     * This method is typically used together with {@link #swapAndScaleAxes swapAndScaleAxes} for the creation
-     * of a transformation step before some
-     * {@linkplain org.apache.sis.referencing.operation.transform.AbstractMathTransform math transform}.
-     * Example:
+     * Returns a coordinate system derived from the given one but with a modified list of axes.
+     * The axes may be filtered (excluding some axes), reordered or have their unit and direction modified.
      *
-     * {@preformat java
-     *     Matrix step1 = swapAndScaleAxes(sourceCS, normalize(sourceCS));
-     *     Matrix step2 = ... some transform operating on standard axis ...
-     *     Matrix step3 = swapAndScaleAxes(normalize(targetCS), targetCS);
-     * }
+     * <div class="note"><b>Example:</b>
+     * for replacing all angular units of a coordinate system to degrees (regardless what the original
+     * angular units were) while leaving other kinds of units unchanged, one can write:
      *
-     * A rational for normalized axis order and units is explained in the <cite>Axis units and
-     * direction</cite> section in the {@linkplain org.apache.sis.referencing.operation.projection
-     * description of map projection package}.
+     * {@preformat java
+     *     CoordinateSystem cs = ...;
+     *     cs = CoordinateSystems.replaceAxes(cs, new AxisFilter() {
+     *         &#64;Override
+     *         public Unit<?> getUnitReplacement(Unit<?> unit) {
+     *             if (Units.isAngular(unit)) {
+     *                 unit = NonSI.DEGREE_ANGLE;
+     *             }
+     *             return unit;
+     *         }
+     *     });
+     * }</div>
+     *
+     * <div class="section">Coordinate system normalization</div>
+     * This method is often used together with {@link #swapAndScaleAxes swapAndScaleAxes(…)} for normalizing the
+     * coordinate values given to a {@linkplain org.apache.sis.referencing.operation.transform.AbstractMathTransform
+     * math transform}.
      *
-     * @param  cs The coordinate system.
-     * @return A constant similar to the specified {@code cs} with normalized axes.
+     * <div class="note"><b>Example:</b>
+     * {@preformat java
+     *     CoordinateSystem sourceCS = ...;
+     *     CoordinateSystem targetCS = ...;
+     *     Matrix step1 = swapAndScaleAxes(sourceCS, replaceAxes(sourceCS, AxisConvention.NORMALIZED));
+     *     Matrix step2 = ...; // some transform working on coordinates with standard axis order and unit.
+     *     Matrix step3 = swapAndScaleAxes(replaceAxes(targetCS, AxisConvention.NORMALIZED), targetCS);
+     * }</div>
+     *
+     * A rational for normalized axis order and units is explained in the <cite>Axis units and direction</cite> section
+     * in the description of the {@linkplain org.apache.sis.referencing.operation.projection map projection package}.
+     *
+     * @param  cs     The coordinate system, or {@code null}.
+     * @param  filter The modifications to apply on coordinate system axes.
+     * @return The modified coordinate system as a new instance,
+     *         or {@code cs} if the given coordinate system was null or does not need any change.
      * @throws IllegalArgumentException if the specified coordinate system can not be normalized.
      *
      * @see AxesConvention#NORMALIZED
      *
      * @since 0.6
      */
-    public static CoordinateSystem normalize(final CoordinateSystem cs) throws IllegalArgumentException {
-        if (cs == null) {
-            return null;
-        } else if (cs instanceof AbstractCS) {
-            // User may have overridden the 'forConvention' method.
-            return ((AbstractCS) cs).forConvention(AxesConvention.NORMALIZED);
-        } else {
-            return Normalizer.normalize(cs);
+    public static CoordinateSystem replaceAxes(final CoordinateSystem cs, final AxisFilter filter) {
+        ensureNonNull("filter", filter);
+        if (cs != null) {
+            final CoordinateSystem newCS;
+            if (filter instanceof AxesConvention) {
+                if (cs instanceof AbstractCS) {
+                    // User may have overridden the 'forConvention' method.
+                    return ((AbstractCS) cs).forConvention((AxesConvention) filter);
+                } else {
+                    newCS = Normalizer.forConvention(cs, (AxesConvention) filter);
+                }
+            } else {
+                newCS = Normalizer.normalize(cs, filter, false);
+            }
+            if (newCS != null) {
+                return newCS;
+            }
         }
+        return cs;
     }
 }



Mime
View raw message