sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1738463 - in /sis/branches/JDK8/core: sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/ sis-referencing/src/main/java/org/apache/sis/internal/referencing/ sis-referencing/src/main/java/org/apache/sis/referencing/ sis-referen...
Date Sun, 10 Apr 2016 20:31:21 GMT
Author: desruisseaux
Date: Sun Apr 10 20:31:21 2016
New Revision: 1738463

URL: http://svn.apache.org/viewvc?rev=1738463&view=rev
Log:
Complete CoordinateOperationRegistry (but not yet connected to DefaultCoordinateOperationFactory) and begin tests.

Added:
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationRegistryTest.java   (with props)
Modified:
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Initializer.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/PositionalAccuracyConstant.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationInferenceTest.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Initializer.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Initializer.java?rev=1738463&r1=1738462&r2=1738463&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Initializer.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Initializer.java [UTF-8] Sun Apr 10 20:31:21 2016
@@ -402,7 +402,7 @@ public abstract class Initializer {
             try {
                 ds.getConnection().close();     // Does the actual shutdown.
             } catch (SQLException e) {          // This is the expected exception.
-                final LogRecord record = new LogRecord(Level.CONFIG, e.getLocalizedMessage());
+                final LogRecord record = new LogRecord(Level.FINE, e.getLocalizedMessage());
                 if (!isSuccessfulShutdown(e)) {
                     record.setLevel(Level.WARNING);
                     record.setThrown(e);

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/PositionalAccuracyConstant.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/PositionalAccuracyConstant.java?rev=1738463&r1=1738462&r2=1738463&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/PositionalAccuracyConstant.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/PositionalAccuracyConstant.java [UTF-8] Sun Apr 10 20:31:21 2016
@@ -131,8 +131,8 @@ public final class PositionalAccuracyCon
      * 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>If at least one {@link QuantitativeResult} is found with a linear unit, then the largest
+     *       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
@@ -152,9 +152,10 @@ public final class PositionalAccuracyCon
      * @see org.apache.sis.referencing.operation.AbstractCoordinateOperation#getLinearAccuracy()
      */
     public static double getLinearAccuracy(final CoordinateOperation operation) {
+        double accuracy = Double.NaN;
         final Collection<PositionalAccuracy> accuracies = operation.getCoordinateOperationAccuracy();
-        for (final PositionalAccuracy accuracy : accuracies) {
-            for (final Result result : accuracy.getResults()) {
+        for (final PositionalAccuracy metadata : accuracies) {
+            for (final Result result : metadata.getResults()) {
                 if (result instanceof QuantitativeResult) {
                     final QuantitativeResult quantity = (QuantitativeResult) result;
                     final Collection<? extends Record> records = quantity.getValues();
@@ -167,7 +168,9 @@ public final class PositionalAccuracyCon
                                     if (value instanceof Number) {
                                         double v = ((Number) value).doubleValue();
                                         v = unitOfLength.getConverterTo(SI.METRE).convert(v);
-                                        return v;
+                                        if (v >= 0 && !(v <= accuracy)) {       // '!' is for replacing the NaN value.
+                                            accuracy = v;
+                                        }
                                     }
                                 }
                             }
@@ -176,40 +179,41 @@ public final class PositionalAccuracyCon
                 }
             }
         }
-        /*
-         * 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 (Double.isNaN(accuracy)) {
+            /*
+             * 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 (accuracies.contains(DATUM_SHIFT_OMITTED)) {
-                return UNKNOWN_ACCURACY;
+            /*
+             * 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 CoordinateOperation op : ((ConcatenatedOperation) operation).getOperations()) {
-                final double candidate = Math.abs(getLinearAccuracy(op));
-                if (!Double.isNaN(candidate)) {
-                    if (Double.isNaN(accuracy)) {
-                        accuracy = candidate;
-                    } else {
-                        accuracy += candidate;
+            /*
+             * 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).
+             */
+            if (operation instanceof ConcatenatedOperation) {
+                for (final CoordinateOperation op : ((ConcatenatedOperation) operation).getOperations()) {
+                    final double candidate = Math.abs(getLinearAccuracy(op));
+                    if (!Double.isNaN(candidate)) {
+                        if (Double.isNaN(accuracy)) {
+                            accuracy = candidate;
+                        } else {
+                            accuracy += candidate;
+                        }
                     }
                 }
             }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java?rev=1738463&r1=1738462&r2=1738463&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java [UTF-8] Sun Apr 10 20:31:21 2016
@@ -319,8 +319,8 @@ public final class CRS extends Static {
      *   <li>If the given operation is an instance of {@link AbstractCoordinateOperation}, then delegate to the
      *       operation {@link AbstractCoordinateOperation#getLinearAccuracy() getLinearAccuracy()} method.</li>
      *
-     *   <li>Otherwise if a {@linkplain org.apache.sis.metadata.iso.quality.DefaultQuantitativeResult quantitative result}
-     *       is found with a linear unit, then return the result value converted to metres.</li>
+     *   <li>Otherwise if at least one {@linkplain org.apache.sis.metadata.iso.quality.DefaultQuantitativeResult
+     *       quantitative result} is found with a linear unit, then return the largest value converted to metres.</li>
      *
      *   <li>Otherwise if the operation is a {@linkplain org.apache.sis.referencing.operation.DefaultConversion
      *       conversion}, then returns 0 since a conversion is by definition accurate up to rounding errors.</li>

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java?rev=1738463&r1=1738462&r2=1738463&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java [UTF-8] Sun Apr 10 20:31:21 2016
@@ -558,8 +558,8 @@ check:      for (int isTarget=0; ; isTar
      * Note that those rules may change in any future SIS version.
      *
      * <ul>
-     *   <li>If a {@linkplain org.apache.sis.metadata.iso.quality.DefaultQuantitativeResult quantitative result}
-     *       is found with a linear unit, then returns the result value converted to metres.</li>
+     *   <li>If at least one {@linkplain org.apache.sis.metadata.iso.quality.DefaultQuantitativeResult quantitative
+     *       result} is found with a linear unit, then returns the largest result value converted to metres.</li>
      *
      *   <li>Otherwise if the operation is a {@linkplain DefaultConversion conversion},
      *       then returns 0 since a conversion is by definition accurate up to rounding errors.</li>

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java?rev=1738463&r1=1738462&r2=1738463&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java [UTF-8] Sun Apr 10 20:31:21 2016
@@ -45,8 +45,8 @@ final class CRSPair {
     /**
      * Creates a {@code CRSPair} for the specified source and target CRS.
      */
-    public CRSPair(final CoordinateReferenceSystem sourceCRS,
-                   final CoordinateReferenceSystem targetCRS)
+    CRSPair(final CoordinateReferenceSystem sourceCRS,
+            final CoordinateReferenceSystem targetCRS)
     {
         this.sourceCRS = sourceCRS;
         this.targetCRS = targetCRS;

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java?rev=1738463&r1=1738462&r2=1738463&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java [UTF-8] Sun Apr 10 20:31:21 2016
@@ -54,7 +54,18 @@ import java.util.Objects;
 
 /**
  * Base class of code that search for coordinate operation, either by looking in a registry maintained by an authority
- * or by trying to infer the coordinate operation by itself.
+ * or by trying to infer the coordinate operation by itself.  There is two subclasses which correspond to the two main
+ * strategies for finding coordinate operations:
+ *
+ * <ul>
+ *   <li>{@link CoordinateOperationRegistry} implements the <cite>late-binding</cite> approach
+ *       (i.e. search coordinate operation paths specified by authorities like the ones listed in the EPSG dataset),
+ *       which is the preferred approach.</li>
+ *   <li>{@link CoordinateOperationFinder} implements the <cite>early-binding</cite> approach
+ *       (i.e. find a coordinate operation path by inspecting the properties associated to the CRS,
+ *       including {@code BOUNDCRS} or {@code TOWGS84} WKT elements).
+ *       This approach is used only as a fallback in the late-binding approach gave no result.</li>
+ * </ul>
  *
  * <div class="section">Limitations</div>
  * <ul>
@@ -67,7 +78,7 @@ import java.util.Objects;
  * @version 0.7
  * @module
  */
-class CoordinateOperationFinder {
+abstract class CoordinateOperationFinder {
     /**
      * The identifier for an identity operation.
      */
@@ -132,13 +143,6 @@ class CoordinateOperationFinder {
     GeographicBoundingBox bbox;
 
     /**
-     * The desired accuracy in metres, or 0 for the best accuracy available.
-     *
-     * @see #MOLODENSKY_ACCURACY
-     */
-    double desiredAccuracy;
-
-    /**
      * Creates a new instance for the given factory and context.
      *
      * @param factory The factory to use for creating coordinate operations.
@@ -152,13 +156,31 @@ class CoordinateOperationFinder {
         factorySIS = (factory instanceof DefaultCoordinateOperationFactory)
                      ? (DefaultCoordinateOperationFactory) factory : CoordinateOperations.factory();
         if (context != null) {
-            areaOfInterest  = context.getAreaOfInterest();
-            desiredAccuracy = context.getDesiredAccuracy();
-            bbox            = context.getGeographicBoundingBox();
+            areaOfInterest = context.getAreaOfInterest();
+            bbox           = context.getGeographicBoundingBox();
         }
     }
 
     /**
+     * Finds or infers an operation for conversion or transformation between two coordinate reference systems.
+     * If the subclass implements the <cite>late-binding</cite> approach (see definition of terms in class javadoc),
+     * then this method may return {@code null} if no operation path is defined in the registry for the given pair
+     * of CRS. Note that it does not mean that no path exist.
+     *
+     * <p>If the subclass implements the <cite>early-binding</cite> approach (which is the fallback if late-binding
+     * gave no result), then this method should never return {@code null} since there is no other fallback.
+     * Instead, this method may throw an {@link OperationNotFoundException}.</p>
+     *
+     * @param  sourceCRS  input coordinate reference system.
+     * @param  targetCRS  output coordinate reference system.
+     * @return a coordinate operation from {@code sourceCRS} to {@code targetCRS}, or {@code null} if none.
+     * @throws OperationNotFoundException if no operation path was found from {@code sourceCRS} to {@code targetCRS}.
+     * @throws FactoryException if the operation creation failed for some other reason.
+     */
+    public abstract CoordinateOperation createOperation(CoordinateReferenceSystem sourceCRS,
+                                                        CoordinateReferenceSystem targetCRS) throws FactoryException;
+
+    /**
      * Creates a coordinate operation from a math transform.
      * The method performs the following steps:
      *

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java?rev=1738463&r1=1738462&r2=1738463&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java [UTF-8] Sun Apr 10 20:31:21 2016
@@ -94,6 +94,13 @@ public class CoordinateOperationInferenc
     private static final double MOLODENSKY_ACCURACY = 5;
 
     /**
+     * The desired accuracy in metres, or 0 for the best accuracy available.
+     *
+     * @see #MOLODENSKY_ACCURACY
+     */
+    private final double desiredAccuracy;
+
+    /**
      * Identifiers used as the basis for identifier of CRS used as an intermediate step.
      * The values can be of two kinds:
      *
@@ -126,6 +133,7 @@ public class CoordinateOperationInferenc
         super(factory, context);
         identifierOfStepCRS = new HashMap<>(8);
         previousSearches    = new HashMap<>(8);
+        desiredAccuracy     = (context != null) ? context.getDesiredAccuracy() : 0;
     }
 
     /**
@@ -140,6 +148,7 @@ public class CoordinateOperationInferenc
      * @throws OperationNotFoundException if no operation path was found from {@code sourceCRS} to {@code targetCRS}.
      * @throws FactoryException if the operation creation failed for some other reason.
      */
+    @Override
     public CoordinateOperation createOperation(final CoordinateReferenceSystem sourceCRS,
                                                final CoordinateReferenceSystem targetCRS)
             throws OperationNotFoundException, FactoryException
@@ -950,7 +959,7 @@ public class CoordinateOperationInferenc
      * Returns a name for a transformation between two CRS.
      */
     private static Map<String,?> defaultName(CoordinateReferenceSystem source, CoordinateReferenceSystem target) {
-        return properties(CRSPair.label(source) + " → " + CRSPair.label(target));
+        return properties(new CRSPair(source, target).toString());
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java?rev=1738463&r1=1738462&r2=1738463&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java [UTF-8] Sun Apr 10 20:31:21 2016
@@ -44,6 +44,7 @@ import org.apache.sis.referencing.cs.Coo
 import org.apache.sis.referencing.operation.matrix.Matrices;
 import org.apache.sis.referencing.operation.transform.MathTransforms;
 import org.apache.sis.referencing.factory.IdentifiedObjectFinder;
+import org.apache.sis.referencing.factory.MissingFactoryResourceException;
 import org.apache.sis.metadata.iso.extent.Extents;
 import org.apache.sis.internal.metadata.ReferencingServices;
 import org.apache.sis.internal.system.Loggers;
@@ -55,6 +56,10 @@ import org.apache.sis.util.Deprecable;
 import org.apache.sis.util.logging.Logging;
 import org.apache.sis.util.collection.Containers;
 import org.apache.sis.util.collection.BackingStoreException;
+import org.apache.sis.util.resources.Errors;
+
+// Branch-dependent imports
+import java.util.function.Predicate;
 
 
 /**
@@ -95,6 +100,11 @@ final class CoordinateOperationRegistry
     private final CoordinateOperationAuthorityFactory registry;
 
     /**
+     * Filter the coordinate operation, or {@code null} if none.
+     */
+    private final Predicate<CoordinateOperation> filter;
+
+    /**
      * Creates a new finder for the given factory.
      */
     CoordinateOperationRegistry(final DefaultCoordinateOperationFactory   factory,
@@ -102,11 +112,12 @@ final class CoordinateOperationRegistry
                                 final CoordinateOperationContext          context) throws FactoryException
     {
         super(factory, context);
-        this.registry  = registry;
+        this.registry = registry;
         authority  = registry.getAuthority();
         codeFinder = IdentifiedObjects.newFinder(Citations.getIdentifier(authority, false));
         codeFinder.setSearchDomain(IdentifiedObjectFinder.Domain.ALL_DATASET);
         codeFinder.setIgnoringAxes(true);
+        filter = null;  // TODO
     }
 
     /**
@@ -120,6 +131,66 @@ final class CoordinateOperationRegistry
 
     /**
      * Returns an operation for conversion or transformation between two coordinate reference systems.
+     * The default implementation extracts the authority code from the supplied {@code sourceCRS} and
+     * {@code targetCRS}, and submit them to the
+     * <code>{@linkplain CoordinateOperationAuthorityFactory#createFromCoordinateReferenceSystemCodes
+     * createFromCoordinateReferenceSystemCodes}(sourceCode, targetCode)</code> methods.
+     * If no operation is found for those codes, then this method returns {@code null}.
+     *
+     * @param  sourceCRS  source coordinate reference system.
+     * @param  targetCRS  target coordinate reference system.
+     * @return a coordinate operation from {@code sourceCRS} to {@code targetCRS}, or {@code null}
+     *         if no such operation is explicitly defined in the underlying database.
+     */
+    @Override
+    public CoordinateOperation createOperation(final CoordinateReferenceSystem sourceCRS,
+                                               final CoordinateReferenceSystem targetCRS)
+            throws FactoryException
+    {
+        CoordinateReferenceSystem source = sourceCRS;
+        CoordinateReferenceSystem target = targetCRS;
+        for (int combine=0; ;combine++) {
+            /*
+             * First, try directly the provided (sourceCRS, targetCRS) pair. If that pair does not work,
+             * try to use different combinations of user-provided CRS and two-dimensional components of
+             * those CRS. The code below assumes that the user-provided CRS are three-dimensional, but
+             * actually it works for other kind of CRS too without testing twice the same combinations.
+             */
+            switch (combine) {
+                case 0:  break;                                                         // 3D → 3D
+                case 1:  target = CRS.getHorizontalComponent(targetCRS);                // 3D → 2D
+                         if (target == targetCRS) continue;
+                         break;
+                case 2:  source = CRS.getHorizontalComponent(sourceCRS);                // 2D → 2D
+                         if (source == sourceCRS) continue;
+                         break;
+                case 3:  if (source == sourceCRS || target == targetCRS) continue;
+                         target = targetCRS;                                            // 2D → 3D
+                         break;
+                default: return null;
+            }
+            if (source != null && target != null) try {
+                CoordinateOperation operation = search(source, target);
+                if (operation != null) {
+                    /*
+                     * Found an operation. If we had to extract the horizontal part of some 3D CRS,
+                     * then we need to modify the coordinate operation.
+                     */
+                    if (combine != 0) {
+                        operation = propagateVertical(operation, source != sourceCRS, target != targetCRS);
+                        operation = complete(operation, sourceCRS, targetCRS);
+                    }
+                    return operation;
+                }
+            } catch (IllegalArgumentException | ConversionException e) {
+                throw new FactoryException(Errors.format(
+                        Errors.Keys.CanNotInstantiate_1, new CRSPair(sourceCRS, targetCRS)), e);
+            }
+        }
+    }
+
+    /**
+     * Returns an operation for conversion or transformation between two coordinate reference systems.
      * This method extracts the authority code from the supplied {@code sourceCRS} and {@code targetCRS},
      * and submit them to the {@link #registry}. If no operation is found for those codes, then this method
      * returns {@code null}.
@@ -130,6 +201,7 @@ final class CoordinateOperationRegistry
      *         or {@code null} if no such operation is explicitly defined in the underlying database.
      * @return A coordinate operation from {@code sourceCRS} to {@code targetCRS}, or {@code null}
      *         if no such operation is explicitly defined in the underlying database.
+     * @throws IllegalArgumentException if the coordinate systems are not of the same type or axes do not match.
      * @throws ConversionException if the units are not compatible or a unit conversion is non-linear.
      * @throws FactoryException if an error occurred while creating the operation.
      */
@@ -169,17 +241,17 @@ final class CoordinateOperationRegistry
                  * The EPSG database usually contains transformation paths for geographic to projected CRS only.
                  */
                 operations = registry.createFromCoordinateReferenceSystemCodes(targetID, sourceID);
-                if (operations == null) {
+                if (Containers.isNullOrEmpty(operations)) {
                     return null;
                 }
             }
-        } catch (NoSuchAuthorityCodeException exception) {
+        } catch (NoSuchAuthorityCodeException | MissingFactoryResourceException exception) {
             /*
              * sourceCode or targetCode is unknown to the underlying authority factory.
              * Ignores the exception and fallback on the generic algorithm provided by
              * CoordinateOperationInference.
              */
-            log(exception, false);
+            log(exception);
             return null;
         }
         /*
@@ -195,16 +267,21 @@ final class CoordinateOperationRegistry
         for (final Iterator<CoordinateOperation> it=operations.iterator(); it.hasNext();) {
             CoordinateOperation candidate;
             try {
-                candidate = it.next();
-            } catch (BackingStoreException exception) {
-                throw exception.unwrapOrRethrow(FactoryException.class);
-            }
-            if (inverse) try {
-                candidate = inverse(candidate);
-            } catch (NoninvertibleTransformException exception) {
-                // It may be a normal failure - the operation is not required to be invertible.
-                Logging.recoverableException(Logging.getLogger(Loggers.COORDINATE_OPERATION),
-                        CoordinateOperationRegistry.class, "search", exception);
+                try {
+                    candidate = it.next();
+                } catch (BackingStoreException exception) {
+                    throw exception.unwrapOrRethrow(FactoryException.class);
+                }
+                if (inverse) try {
+                    candidate = inverse(candidate);
+                } catch (NoninvertibleTransformException exception) {
+                    // It may be a normal failure - the operation is not required to be invertible.
+                    Logging.recoverableException(Logging.getLogger(Loggers.COORDINATE_OPERATION),
+                            CoordinateOperationRegistry.class, "search", exception);
+                    continue;
+                }
+            } catch (MissingFactoryResourceException e) {
+                log(e);
                 continue;
             }
             if (candidate != null) {
@@ -233,12 +310,14 @@ final class CoordinateOperationRegistry
                          * the FactoryException propagate.
                          */
                         candidate = complete(candidate, sourceCRS, targetCRS);
-                        bestChoice = candidate;
-                        if (!Double.isNaN(area)) {
-                            largestArea = area;
+                        if (filter == null || filter.test(candidate)) {
+                            bestChoice = candidate;
+                            if (!Double.isNaN(area)) {
+                                largestArea = area;
+                            }
+                            finestAccuracy = Double.isNaN(accuracy) ? Double.POSITIVE_INFINITY : accuracy;
+                            stopAtFirstDeprecated = !isDeprecated;
                         }
-                        finestAccuracy = Double.isNaN(accuracy) ? Double.POSITIVE_INFINITY : accuracy;
-                        stopAtFirstDeprecated = !isDeprecated;
                     }
                 }
             }
@@ -399,19 +478,35 @@ final class CoordinateOperationRegistry
      * @throws FactoryException if an error occurred while creating the new operation.
      */
     private CoordinateOperation recreate(final CoordinateOperation       operation,
-                                         final CoordinateReferenceSystem sourceCRS,
-                                         final CoordinateReferenceSystem targetCRS,
+                                               CoordinateReferenceSystem sourceCRS,
+                                               CoordinateReferenceSystem targetCRS,
                                          final MathTransform             transform) throws FactoryException
     {
-        Class<? extends CoordinateOperation> type;                  // GeoAPI type for the given operation.
+        /*
+         * If the user-provided CRS are approximatively equal to the coordinate operation CRS, keep the later.
+         * The reason is that coordinate operation CRS are built from the definitions provided by the authority,
+         * while the user-provided CRS can be anything (e.g. parsed from a quite approximative WKT).
+         */
+        CoordinateReferenceSystem crs;
+        if (Utilities.equalsApproximatively(sourceCRS, crs = operation.getSourceCRS())) sourceCRS = crs;
+        if (Utilities.equalsApproximatively(targetCRS, crs = operation.getTargetCRS())) targetCRS = crs;
+        /*
+         * Determine whether the operation to create is a Conversion or a Transformation.
+         * Conversion may also be a more accurate type like Projection. We want the GeoAPI
+         * interface. The most reliable way is to ask to the operation, but this is SIS-specific.
+         * The fallback uses reflection.
+         */
+        final Class<? extends CoordinateOperation> type;
         if (operation instanceof AbstractCoordinateOperation) {
             type = ((AbstractCoordinateOperation) operation).getInterface();
         } else {
-            // Fallback (less reliable) for non-SIS implementations.
             final Class<? extends CoordinateOperation>[] types =
                     Classes.getLeafInterfaces(operation.getClass(), CoordinateOperation.class);
             type = (types.length != 0) ? types[0] : SingleOperation.class;
         }
+        /*
+         * Reuse the same operation method, just changing its number of dimension.
+         */
         OperationMethod method = null;
         if (operation instanceof SingleOperation) {
             method = DefaultOperationMethod.redimension(((SingleOperation) operation).getMethod(),
@@ -444,17 +539,27 @@ final class CoordinateOperationRegistry
      *         or {@code null} if this method does not know how to create the operation.
      * @throws FactoryException if an error occurred while creating the coordinate operation.
      */
-    private CoordinateOperation propagateVertical(ConcatenatedOperation operation,
+    private CoordinateOperation propagateVertical(final CoordinateOperation operation,
             final boolean source3D, final boolean target3D) throws FactoryException
     {
-        final List<CoordinateOperation> operations = new ArrayList<>(operation.getOperations());
+        final List<CoordinateOperation> operations = new ArrayList<>();
+        if (operation instanceof ConcatenatedOperation) {
+            operations.addAll(((ConcatenatedOperation) operation).getOperations());
+        } else {
+            operations.add(operation);
+        }
         if ((source3D && !propagateVertical(operations.listIterator(), true)) ||
             (target3D && !propagateVertical(operations.listIterator(operations.size()), false)))
         {
             return null;
         }
-        return factory.createConcatenatedOperation(derivedFrom(operation),
-                operations.toArray(new CoordinateOperation[operations.size()]));
+        switch (operations.size()) {
+            case 0:  return null;
+            case 1:  return operations.get(0);
+            default: return factory.createConcatenatedOperation(derivedFrom(operation),
+                            operations.toArray(new CoordinateOperation[operations.size()]));
+
+        }
     }
 
     /**
@@ -555,17 +660,14 @@ final class CoordinateOperationRegistry
     }
 
     /**
-     * Logs an exception. This method pretends that the logging come from {@link DefaultCoordinateOperationFactory}
-     * since this is the public API which use this {@code CoordinateOperationRegistry} class.
+     * Logs an unexpected but ignorable exception. This method pretends that the logging
+     * come from {@link DefaultCoordinateOperationFactory} since this is the public API
+     * which use this {@code CoordinateOperationRegistry} class.
      *
      * @param exception  the exception which occurred.
-     * @param trace      whether the include the stack trace.
      */
-    private void log(final Exception exception, final boolean trace) {
+    private void log(final FactoryException exception) {
         final LogRecord record = new LogRecord(Level.WARNING, exception.getLocalizedMessage());
-        if (trace) {
-            record.setThrown(exception);
-        }
         record.setLoggerName(Loggers.COORDINATE_OPERATION);
         Logging.log(DefaultCoordinateOperationFactory.class, "createOperation", record);
     }

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationInferenceTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationInferenceTest.java?rev=1738463&r1=1738462&r2=1738463&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationInferenceTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationInferenceTest.java [UTF-8] Sun Apr 10 20:31:21 2016
@@ -53,11 +53,11 @@ import static org.apache.sis.internal.re
 // Test dependencies
 import org.apache.sis.referencing.operation.transform.MathTransformTestCase;
 import org.apache.sis.referencing.crs.HardCodedCRS;
+import org.apache.sis.referencing.cs.HardCodedCS;
 import org.apache.sis.test.TestUtilities;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.opengis.test.Assert;
-import org.apache.sis.referencing.cs.HardCodedCS;
 import org.junit.BeforeClass;
 import org.junit.AfterClass;
 import org.junit.Test;
@@ -101,6 +101,18 @@ public final strictfp class CoordinateOp
     private static WKTFormat parser;
 
     /**
+     * The instance on which to execute the tests.
+     */
+    private CoordinateOperationInference inference;
+
+    /**
+     * Creates a new test case.
+     */
+    public CoordinateOperationInferenceTest() {
+        inference = new CoordinateOperationInference(factory, null);
+    }
+
+    /**
      * Creates a new {@link DefaultCoordinateOperationFactory} to use for testing purpose.
      * The same factory will be used for all tests in this class.
      *
@@ -169,13 +181,14 @@ public final strictfp class CoordinateOp
     /**
      * Implementation of {@link #testIdentityTransform()} using the given CRS.
      */
-    private static void testIdentityTransform(final CoordinateReferenceSystem crs) throws FactoryException {
-        final CoordinateOperation operation = factory.createOperation(crs, crs);
+    private void testIdentityTransform(final CoordinateReferenceSystem crs) throws FactoryException {
+        final CoordinateOperation operation = inference.createOperation(crs, crs);
         assertSame      ("sourceCRS",  crs, operation.getSourceCRS());
         assertSame      ("targetCRS",  crs, operation.getTargetCRS());
         assertTrue      ("isIdentity", operation.getMathTransform().isIdentity());
         assertTrue      ("accuracy",   operation.getCoordinateOperationAccuracy().isEmpty());
         assertInstanceOf("operation",  Conversion.class, operation);
+        inference = new CoordinateOperationInference(factory, null);        // Reset for next call.
     }
 
     /**
@@ -250,7 +263,7 @@ public final strictfp class CoordinateOp
             final GeographicCRS sourceCRS, final GeographicCRS targetCRS)
             throws ParseException, FactoryException, TransformException
     {
-        final CoordinateOperation operation = factory.createOperation(sourceCRS, targetCRS);
+        final CoordinateOperation operation = inference.createOperation(sourceCRS, targetCRS);
         assertSame      ("sourceCRS",  sourceCRS,            operation.getSourceCRS());
         assertSame      ("targetCRS",  targetCRS,            operation.getTargetCRS());
         assertFalse     ("isIdentity",                       operation.getMathTransform().isIdentity());
@@ -310,7 +323,7 @@ public final strictfp class CoordinateOp
                 "  Id[“EPSG”, “4807”]]");
 
         final GeographicCRS       targetCRS = CommonCRS.WGS84.geographic();
-        final CoordinateOperation operation = factory.createOperation(sourceCRS, targetCRS);
+        final CoordinateOperation operation = inference.createOperation(sourceCRS, targetCRS);
 
         assertSame      ("sourceCRS",  sourceCRS,            operation.getSourceCRS());
         assertSame      ("targetCRS",  targetCRS,            operation.getTargetCRS());
@@ -356,7 +369,7 @@ public final strictfp class CoordinateOp
                 "    Unit[“km”, 1000]]");
 
         final GeocentricCRS       targetCRS = CommonCRS.WGS84.geocentric();
-        final CoordinateOperation operation = factory.createOperation(sourceCRS, targetCRS);
+        final CoordinateOperation operation = inference.createOperation(sourceCRS, targetCRS);
 
         assertSame      ("sourceCRS",  sourceCRS,            operation.getSourceCRS());
         assertSame      ("targetCRS",  targetCRS,            operation.getTargetCRS());
@@ -410,7 +423,7 @@ public final strictfp class CoordinateOp
                 "    Axis[“y”, NORTH],\n" +
                 "    Unit[“US survey foot”, 0.304800609601219]]");
 
-        final CoordinateOperation operation = factory.createOperation(sourceCRS, targetCRS);
+        final CoordinateOperation operation = inference.createOperation(sourceCRS, targetCRS);
         assertSame      ("sourceCRS", sourceCRS,        operation.getSourceCRS());
         assertSame      ("targetCRS", targetCRS,        operation.getTargetCRS());
         assertEquals    ("name",      "TM",             operation.getName().getCode());
@@ -448,7 +461,7 @@ public final strictfp class CoordinateOp
         final VerticalCRS sourceCRS = CommonCRS.Vertical.NAVD88.crs();
         final VerticalCRS targetCRS = CommonCRS.Vertical.MEAN_SEA_LEVEL.crs();
         try {
-            factory.createOperation(sourceCRS, targetCRS);
+            inference.createOperation(sourceCRS, targetCRS);
             fail("The operation should have failed.");
         } catch (OperationNotFoundException e) {
             final String message = e.getMessage();
@@ -470,7 +483,7 @@ public final strictfp class CoordinateOp
     public void testTemporalConversion() throws FactoryException, TransformException {
         final TemporalCRS sourceCRS = CommonCRS.Temporal.UNIX.crs();
         final TemporalCRS targetCRS = CommonCRS.Temporal.MODIFIED_JULIAN.crs();
-        final CoordinateOperation operation = factory.createOperation(sourceCRS, targetCRS);
+        final CoordinateOperation operation = inference.createOperation(sourceCRS, targetCRS);
         assertSame      ("sourceCRS", sourceCRS,        operation.getSourceCRS());
         assertSame      ("targetCRS", targetCRS,        operation.getTargetCRS());
         assertEquals    ("name",      "Axis changes",   operation.getName().getCode());
@@ -508,7 +521,7 @@ public final strictfp class CoordinateOp
     public void testGeographic3D_to_2D() throws FactoryException, TransformException {
         final GeographicCRS sourceCRS = CommonCRS.WGS84.geographic3D();
         final GeographicCRS targetCRS = CommonCRS.WGS84.geographic();
-        final CoordinateOperation operation = factory.createOperation(sourceCRS, targetCRS);
+        final CoordinateOperation operation = inference.createOperation(sourceCRS, targetCRS);
         assertSame      ("sourceCRS", sourceCRS,        operation.getSourceCRS());
         assertSame      ("targetCRS", targetCRS,        operation.getTargetCRS());
         assertEquals    ("name",      "Axis changes",   operation.getName().getCode());
@@ -551,7 +564,7 @@ public final strictfp class CoordinateOp
     public void testGeographic2D_to_3D() throws FactoryException, TransformException {
         final GeographicCRS sourceCRS = CommonCRS.WGS84.geographic();
         final GeographicCRS targetCRS = CommonCRS.WGS84.geographic3D();
-        final CoordinateOperation operation = factory.createOperation(sourceCRS, targetCRS);
+        final CoordinateOperation operation = inference.createOperation(sourceCRS, targetCRS);
         assertSame      ("sourceCRS", sourceCRS,        operation.getSourceCRS());
         assertSame      ("targetCRS", targetCRS,        operation.getTargetCRS());
         assertEquals    ("name",      "Axis changes",   operation.getName().getCode());
@@ -595,7 +608,7 @@ public final strictfp class CoordinateOp
     public void testGeographic3D_to_EllipsoidalHeight() throws FactoryException, TransformException {
         final CoordinateReferenceSystem sourceCRS = CommonCRS.WGS84.geographic3D();
         final CoordinateReferenceSystem targetCRS = HardCodedCRS.ELLIPSOIDAL_HEIGHT_cm;
-        final CoordinateOperation operation = factory.createOperation(sourceCRS, targetCRS);
+        final CoordinateOperation operation = inference.createOperation(sourceCRS, targetCRS);
         assertSame      ("sourceCRS", sourceCRS,        operation.getSourceCRS());
         assertSame      ("targetCRS", targetCRS,        operation.getTargetCRS());
         assertEquals    ("name",      "Axis changes",   operation.getName().getCode());
@@ -657,7 +670,7 @@ public final strictfp class CoordinateOp
         sourceCRS = compound("Mercator 3D", sourceCRS, CommonCRS.Vertical.ELLIPSOIDAL.crs());
         sourceCRS = compound("Mercator 4D", sourceCRS, CommonCRS.Temporal.MODIFIED_JULIAN.crs());
 
-        final CoordinateOperation operation = factory.createOperation(sourceCRS, targetCRS);
+        final CoordinateOperation operation = inference.createOperation(sourceCRS, targetCRS);
         assertSame("sourceCRS", sourceCRS, operation.getSourceCRS());
         assertSame("targetCRS", targetCRS, operation.getTargetCRS());
 
@@ -699,7 +712,7 @@ public final strictfp class CoordinateOp
     public void testGeographic3D_to_4D() throws FactoryException, TransformException {
         final CompoundCRS sourceCRS = compound("Test3D", CommonCRS.WGS84.geographic(),   CommonCRS.Temporal.UNIX.crs());
         final CompoundCRS targetCRS = compound("Test4D", CommonCRS.WGS84.geographic3D(), CommonCRS.Temporal.MODIFIED_JULIAN.crs());
-        final CoordinateOperation operation = factory.createOperation(sourceCRS, targetCRS);
+        final CoordinateOperation operation = inference.createOperation(sourceCRS, targetCRS);
         assertSame      ("sourceCRS", sourceCRS, operation.getSourceCRS());
         assertSame      ("targetCRS", targetCRS, operation.getTargetCRS());
         assertInstanceOf("operation", ConcatenatedOperation.class, operation);
@@ -749,7 +762,7 @@ public final strictfp class CoordinateOp
                     0,   0,   1
                 })), HardCodedCS.DISPLAY);
 
-        final CoordinateOperation operation = factory.createOperation(sourceCRS, targetCRS);
+        final CoordinateOperation operation = inference.createOperation(sourceCRS, targetCRS);
         assertSame("sourceCRS", sourceCRS, operation.getSourceCRS());
         assertSame("targetCRS", targetCRS, operation.getTargetCRS());
 

Added: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationRegistryTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationRegistryTest.java?rev=1738463&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationRegistryTest.java (added)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationRegistryTest.java [UTF-8] Sun Apr 10 20:31:21 2016
@@ -0,0 +1,143 @@
+/*
+ * 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.operation;
+
+import java.text.ParseException;
+import org.opengis.util.FactoryException;
+import org.opengis.referencing.crs.CRSAuthorityFactory;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.referencing.operation.CoordinateOperationAuthorityFactory;
+import org.opengis.referencing.operation.TransformException;
+import org.apache.sis.referencing.CommonCRS;
+import org.apache.sis.referencing.CRS;
+import org.apache.sis.io.wkt.WKTFormat;
+
+// Test dependencies
+import org.apache.sis.referencing.operation.transform.MathTransformTestCase;
+import org.junit.BeforeClass;
+import org.junit.AfterClass;
+import org.junit.Test;
+
+import static org.apache.sis.test.ReferencingAssert.*;
+import static org.junit.Assume.*;
+
+
+/**
+ * Tests {@link CoordinateOperationRegistry}.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.7
+ * @version 0.7
+ * @module
+ */
+public final strictfp class CoordinateOperationRegistryTest extends MathTransformTestCase {
+    /**
+     * Tolerance threshold for strict comparisons of floating point numbers.
+     * This constant can be used like below, where {@code expected} and {@code actual} are {@code double} values:
+     *
+     * {@preformat java
+     *     assertEquals(expected, actual, STRICT);
+     * }
+     */
+    private static final double STRICT = 0;
+
+    /**
+     * The transformation factory to use for testing.
+     */
+    private static DefaultCoordinateOperationFactory factory;
+
+    /**
+     * The parser to use for WKT strings used in this test.
+     */
+    private static WKTFormat parser;
+
+    /**
+     * The instance on which to execute the tests.
+     */
+    private final CoordinateOperationRegistry registry;
+
+    /**
+     * Creates a new test case.
+     *
+     * @throws FactoryException if an error occurred while creating the factory to be tested.
+     */
+    public CoordinateOperationRegistryTest() throws FactoryException {
+        final CRSAuthorityFactory crsFactory = CRS.getAuthorityFactory("EPSG");
+        assumeTrue("EPSG factory required.", crsFactory instanceof CoordinateOperationAuthorityFactory);
+        registry = new CoordinateOperationRegistry(factory, (CoordinateOperationAuthorityFactory) crsFactory, null);
+    }
+
+    /**
+     * Creates a new {@link DefaultCoordinateOperationFactory} to use for testing purpose.
+     * The same factory will be used for all tests in this class.
+     *
+     * @throws ParseException if an error occurred while preparing the WKT parser.
+     */
+    @BeforeClass
+    public static void createFactory() throws ParseException {
+        factory = new DefaultCoordinateOperationFactory();
+        parser  = new WKTFormat(null, null);
+    }
+
+    /**
+     * Disposes the factory created by {@link #createFactory()} after all tests have been executed.
+     */
+    @AfterClass
+    public static void disposeFactory() {
+        factory = null;
+        parser  = null;
+    }
+
+    /**
+     * Returns the CRS for the given Well Known Text.
+     */
+    private static CoordinateReferenceSystem parse(final String wkt) throws ParseException {
+        return (CoordinateReferenceSystem) parser.parseObject(wkt);
+    }
+
+    /**
+     * Tests a datum shift between two geographic CRS which also implies a change of prime meridian.
+     * The expected coordinate operation is EPSG:8094.
+     *
+     * @throws ParseException if a CRS used in this test can not be parsed.
+     * @throws FactoryException if the operation can not be created.
+     * @throws TransformException if an error occurred while converting the test points.
+     */
+    @Test
+    public void testDatumShiftWithLongitudeRotation() throws ParseException, FactoryException, TransformException {
+        final CoordinateReferenceSystem sourceCRS = parse(
+                "GeodeticCRS[“NTF (Paris)”,\n" +
+                "  Datum[“Nouvelle Triangulation Française (Paris)”,\n" +
+                "    Ellipsoid[“Clarke 1880 (IGN)”, 6378249.2, 293.4660212936269]],\n" +
+                "    PrimeMeridian[“Paris”, 2.5969213],\n" +
+                "  CS[ellipsoidal, 2],\n" +
+                "    Axis[“Latitude (φ)”, NORTH],\n" +
+                "    Axis[“Longitude (λ)”, EAST],\n" +
+                "    Unit[“grade”, 0.015707963267948967]\n," +
+                "  Id[“EPSG”, 4807]]");
+
+        final CoordinateReferenceSystem targetCRS = CommonCRS.WGS84.geographic();
+        final CoordinateOperation operation = registry.createOperation(sourceCRS, targetCRS);
+        assertEpsgNameAndIdentifierEqual("NTF (Paris) to WGS 84 (1)", 8094, operation);
+        assertEquals("linearAccuracy", 2, CRS.getLinearAccuracy(operation), STRICT);
+
+        transform = operation.getMathTransform();
+        assertFalse(transform.isIdentity());
+        validate();
+    }
+}

Propchange: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationRegistryTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

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

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java?rev=1738463&r1=1738462&r2=1738463&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java [UTF-8] Sun Apr 10 20:31:21 2016
@@ -110,7 +110,7 @@ public strictfp class ReferencingAssert
      * @since 0.6
      */
     public static void assertEpsgNameAndIdentifierEqual(final String name, final int identifier, final IdentifiedObject object) {
-        assertNotNull(object);
+        assertNotNull(name, object);
         assertEpsgIdentifierEquals(name, object.getName());
         assertEpsgIdentifierEquals(String.valueOf(identifier), TestUtilities.getSingleton(object.getIdentifiers()));
     }

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java?rev=1738463&r1=1738462&r2=1738463&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] Sun Apr 10 20:31:21 2016
@@ -171,7 +171,6 @@ import org.junit.BeforeClass;
     org.apache.sis.referencing.operation.SingleOperationMarshallingTest.class,
     org.apache.sis.referencing.operation.DefaultPassThroughOperationTest.class,
     org.apache.sis.referencing.operation.DefaultConcatenatedOperationTest.class,
-    org.apache.sis.referencing.operation.CoordinateOperationInferenceTest.class,
     org.apache.sis.referencing.crs.DefaultProjectedCRSTest.class,
     org.apache.sis.referencing.crs.DefaultDerivedCRSTest.class,
     org.apache.sis.referencing.crs.SubTypesTest.class,
@@ -217,6 +216,12 @@ import org.junit.BeforeClass;
     org.apache.sis.referencing.AuthorityFactoriesTest.class,
     org.apache.sis.referencing.CRSTest.class,
 
+    // Coordinate operation finders are last, since they need everything else.
+    org.apache.sis.referencing.operation.CoordinateOperationInferenceTest.class,
+    org.apache.sis.referencing.operation.CoordinateOperationRegistryTest.class,
+    org.apache.sis.referencing.operation.builder.LinearTransformBuilderTest.class,
+
+    // Geometry
     org.apache.sis.geometry.AbstractDirectPositionTest.class,
     org.apache.sis.geometry.GeneralDirectPositionTest.class,
     org.apache.sis.geometry.DirectPosition1DTest.class,
@@ -228,11 +233,10 @@ import org.junit.BeforeClass;
     org.apache.sis.geometry.Envelope2DTest.class,
     org.apache.sis.geometry.CurveExtremumTest.class,
     org.apache.sis.geometry.EnvelopesTest.class,
+    org.apache.sis.internal.referencing.ServicesForMetadataTest.class,
 
     org.apache.sis.distance.LatLonPointRadiusTest.class,        // Pending refactoring in a geometry package.
 
-    org.apache.sis.referencing.operation.builder.LinearTransformBuilderTest.class,
-    org.apache.sis.internal.referencing.ServicesForMetadataTest.class,
     org.apache.sis.test.integration.DatumShiftTest.class,
     org.apache.sis.test.integration.MetadataTest.class,
     org.apache.sis.test.integration.ConsistencyTest.class



Mime
View raw message