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


Reply via email to