sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1740399 - in /sis/trunk: ./ core/sis-feature/src/main/java/org/apache/sis/feature/ core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/ core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/ core/sis-referenc...
Date Thu, 21 Apr 2016 20:07:44 GMT
Author: desruisseaux
Date: Thu Apr 21 20:07:44 2016
New Revision: 1740399

URL: http://svn.apache.org/viewvc?rev=1740399&view=rev
Log:
Merge bug fixes from JDK6 branch.

Modified:
    sis/trunk/   (props changed)
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/NamedFeatureType.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/InverseOperationMethod.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationRegistryTest.java

Propchange: sis/trunk/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Apr 21 20:07:44 2016
@@ -1,4 +1,4 @@
 /sis/branches/Android:1430670-1480699
-/sis/branches/JDK6:1394364-1740152
-/sis/branches/JDK7:1394913-1740146
-/sis/branches/JDK8:1584960-1740143
+/sis/branches/JDK6:1394364-1740397
+/sis/branches/JDK7:1394913-1740391
+/sis/branches/JDK8:1584960-1740312

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/NamedFeatureType.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/NamedFeatureType.java?rev=1740399&r1=1740398&r2=1740399&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/NamedFeatureType.java
[UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/NamedFeatureType.java
[UTF-8] Thu Apr 21 20:07:44 2016
@@ -67,7 +67,7 @@ final class NamedFeatureType implements
     }
 
     /**
-     * This feature type is considered to all other features except itself.
+     * This feature type is considered independent of all other feature types except itself.
      */
     @Override
     public boolean isAssignableFrom(final DefaultFeatureType type) {

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java?rev=1740399&r1=1740398&r2=1740399&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java
[UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java
[UTF-8] Thu Apr 21 20:07:44 2016
@@ -391,9 +391,10 @@ public class AbstractCS extends Abstract
      * @return {@code true} if both objects are equal.
      */
     @Override
+    @SuppressWarnings("fallthrough")
     public boolean equals(final Object object, final ComparisonMode mode) {
         if (object == this) {
-            return true; // Slight optimization.
+            return true;                                            // Slight optimization.
         }
         if (!super.equals(object, mode)) {
             return false;
@@ -403,6 +404,14 @@ public class AbstractCS extends Abstract
                 // No need to check the class - this check has been done by super.equals(…).
                 return Arrays.equals(axes, ((AbstractCS) object).axes);
             }
+            case DEBUG: {
+                final int d1 = axes.length;
+                final int d2 = ((CoordinateSystem) object).getDimension();
+                if (d1 != d2) {
+                    throw new AssertionError(Errors.format(Errors.Keys.MismatchedDimension_2,
d1, d2));
+                }
+                // Fall through
+            }
             default: {
                 final CoordinateSystem that = (CoordinateSystem) object;
                 final int dimension = getDimension();

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java?rev=1740399&r1=1740398&r2=1740399&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
[UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
[UTF-8] Thu Apr 21 20:07:44 2016
@@ -16,6 +16,8 @@
  */
 package org.apache.sis.referencing.operation;
 
+import org.opengis.referencing.cs.EllipsoidalCS;
+import org.opengis.referencing.cs.CoordinateSystem;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.IdentifiedObject;
 import org.apache.sis.referencing.AbstractIdentifiedObject;
@@ -57,7 +59,7 @@ final class CRSPair {
      */
     @Override
     public int hashCode() {
-        return sourceCRS.hashCode() * 31 + targetCRS.hashCode();
+        return Objects.hashCode(sourceCRS) * 31 + Objects.hashCode(targetCRS);
     }
 
     /**
@@ -79,8 +81,9 @@ final class CRSPair {
     }
 
     /**
-     * Returns the name of the GeoAPI interface implemented by the specified object,
-     * followed by the name between brackets.
+     * Returns the name of the GeoAPI interface implemented by the specified object. In the
GeographicCRS
+     * or EllipsoidalCS cases, the trailing CRS or CS suffix is replaced by the number of
dimensions
+     * (e.g. "Geographic3D").
      */
     static String label(final IdentifiedObject object) {
         if (object == null) {
@@ -92,7 +95,18 @@ final class CRSPair {
         } else {
             type = Classes.getLeafInterfaces(object.getClass(), IdentifiedObject.class)[0];
         }
-        String label = Classes.getShortName(type);
+        String suffix, label = Classes.getShortName(type);
+        if (label.endsWith((suffix = "CRS")) || label.endsWith(suffix = "CS")) {
+            Object cs = object;
+            if (object instanceof CoordinateReferenceSystem) {
+                cs = ((CoordinateReferenceSystem) object).getCoordinateSystem();
+            }
+            if (cs instanceof EllipsoidalCS) {
+                final StringBuilder sb = new StringBuilder(label);
+                sb.setLength(label.length() - suffix.length());
+                label = sb.append(((CoordinateSystem) cs).getDimension()).append('D').toString();
+            }
+        }
         String name = IdentifiedObjects.getName(object, null);
         if (name != null) {
             int i = 30;                                         // Arbitrary length threshold.

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java?rev=1740399&r1=1740398&r2=1740399&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
[UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
[UTF-8] Thu Apr 21 20:07:44 2016
@@ -146,6 +146,11 @@ public class CoordinateOperationFinder e
     private final Map<CRSPair,Boolean> previousSearches;
 
     /**
+     * Whether this finder instance is allowed to use {@link DefaultCoordinateOperationFactory#cache}.
+     */
+    private final boolean useCache;
+
+    /**
      * Creates a new instance for the given factory and context.
      *
      * @param  registry  the factory to use for creating operations as defined by authority,
or {@code null} if none.
@@ -160,6 +165,7 @@ public class CoordinateOperationFinder e
         super(registry, factory, context);
         identifierOfStepCRS = new HashMap<Identifier,Object>(8);
         previousSearches    = new HashMap<CRSPair,Boolean>(8);
+        useCache = (context == null) && (factory == factorySIS);
     }
 
     /**
@@ -190,13 +196,33 @@ public class CoordinateOperationFinder e
     {
         ArgumentChecks.ensureNonNull("sourceCRS", sourceCRS);
         ArgumentChecks.ensureNonNull("targetCRS", targetCRS);
-        if (!previousSearches.isEmpty()) {
-            // TODO: verify here if the path is defined in EPSG database.
+        if (equalsIgnoreMetadata(sourceCRS, targetCRS)) try {
+            return createFromAffineTransform(AXIS_CHANGES, sourceCRS, targetCRS,
+                    CoordinateSystems.swapAndScaleAxes(sourceCRS.getCoordinateSystem(), targetCRS.getCoordinateSystem()));
+        } catch (IllegalArgumentException e) {
+            throw new FactoryException(Errors.format(Errors.Keys.CanNotInstantiate_1, new
CRSPair(sourceCRS, targetCRS)), e);
+        } catch (ConversionException e) {
+            throw new FactoryException(Errors.format(Errors.Keys.CanNotInstantiate_1, new
CRSPair(sourceCRS, targetCRS)), e);
         }
+        /*
+         * If this method is invoked recursively, verify if the requested operation is already
in the cache.
+         * We do not perform this verification on the first invocation because it was already
verified by
+         * DefaultCoordinateOperationFactory.createOperation(…). We do not block if the
operation is in
+         * process of being computed in another thread because of the risk of deadlock. If
the operation
+         * is not in the cache, store the key in our internal map for preventing infinite
recursivity.
+         */
         final CRSPair key = new CRSPair(sourceCRS, targetCRS);
+        if (useCache && !previousSearches.isEmpty()) {
+            final CoordinateOperation op = factorySIS.cache.peek(key);
+            if (op != null) return op;
+        }
         if (previousSearches.put(key, Boolean.TRUE) != null) {
             throw new FactoryException(Errors.format(Errors.Keys.RecursiveCreateCallForCode_2,
CoordinateOperation.class, key));
         }
+        /*
+         * If the user did not specified an area of interest, use the domain of validity
of the CRS.
+         * Then verify in the EPSG dataset if the operation is explicitely defined by an
authority.
+         */
         GeographicBoundingBox bbox = Extents.getGeographicBoundingBox(areaOfInterest);
         if (bbox == null) {
             bbox = Extents.intersection(CRS.getGeographicBoundingBox(sourceCRS),
@@ -901,8 +927,14 @@ public class CoordinateOperationFinder e
          * trivial operations.
          */
         CoordinateOperation main = null;
-        if (step1.getName() == AXIS_CHANGES && mt1.getSourceDimensions() == mt1.getTargetDimensions())
main = step2;
-        if (step2.getName() == AXIS_CHANGES && mt2.getSourceDimensions() == mt2.getTargetDimensions())
main = step1;
+        final boolean isAxisChange1 = (step1.getName() == AXIS_CHANGES);
+        final boolean isAxisChange2 = (step2.getName() == AXIS_CHANGES);
+        if (isAxisChange1 && isAxisChange2 && isAffine(step1) &&
isAffine(step2)) {
+            main = step2;                                           // Arbitrarily take the
last step.
+        } else {
+            if (isAxisChange1 && mt1.getSourceDimensions() == mt1.getTargetDimensions())
main = step2;
+            if (isAxisChange2 && mt2.getSourceDimensions() == mt2.getTargetDimensions())
main = step1;
+        }
         if (main instanceof SingleOperation) {
             final SingleOperation op = (SingleOperation) main;
             final MathTransform mt = factorySIS.getMathTransformFactory().createConcatenatedTransform(mt1,
mt2);
@@ -915,7 +947,7 @@ public class CoordinateOperationFinder e
         }
         /*
          * Sometime we get a concatenated operation made of an operation followed by its
inverse.
-         * We can identity those case when the associated MathTransform is the identity transform.
+         * We can identify thoses case when the associated MathTransform is the identity
transform.
          * In such case, simplify by replacing the ConcatenatedTransform by a SingleTransform.
          */
         if (main instanceof ConcatenatedOperation && main.getMathTransform().isIdentity())
{
@@ -958,6 +990,18 @@ public class CoordinateOperationFinder e
     }
 
     /**
+     * Returns {@code true} if the given operation is non-null and use the affine operation
method.
+     */
+    private static boolean isAffine(final CoordinateOperation operation) {
+        if (operation instanceof SingleOperation) {
+            if (IdentifiedObjects.isHeuristicMatchForName(((SingleOperation) operation).getMethod(),
Constants.AFFINE)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
      * Returns {@code true} if the specified operation is an identity conversion.
      * This method always returns {@code false} for transformations even if their
      * associated math transform is an identity one, because such transformations

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java?rev=1740399&r1=1740398&r2=1740399&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
[UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
[UTF-8] Thu Apr 21 20:07:44 2016
@@ -38,6 +38,7 @@ import org.opengis.referencing.Identifie
 import org.opengis.referencing.NoSuchAuthorityCodeException;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.crs.GeodeticCRS;
+import org.opengis.referencing.crs.SingleCRS;
 import org.opengis.referencing.cs.EllipsoidalCS;
 import org.opengis.referencing.operation.*;
 
@@ -295,7 +296,8 @@ class CoordinateOperationRegistry {
                      * need to modify the coordinate operation in order to match the new
number of dimensions.
                      */
                     if (combine != 0) {
-                        operation = propagateVertical(operation, source != sourceCRS, target
!= targetCRS);
+                        operation = propagateVertical(sourceCRS, source != sourceCRS,
+                                                      targetCRS, target != targetCRS, operation);
                         if (operation == null) {
                             continue;
                         }
@@ -304,8 +306,12 @@ class CoordinateOperationRegistry {
                     return operation;
                 }
             } catch (IllegalArgumentException e) {
-                throw new FactoryException(Errors.format(
-                        Errors.Keys.CanNotInstantiate_1, new CRSPair(sourceCRS, targetCRS)),
e);
+                String message = Errors.format(Errors.Keys.CanNotInstantiate_1, new CRSPair(sourceCRS,
targetCRS));
+                String details = e.getLocalizedMessage();
+                if (details != null) {
+                    message = message + ' ' + details;
+                }
+                throw new FactoryException(message, e);
             } catch (ConversionException e) {
                 throw new FactoryException(Errors.format(
                         Errors.Keys.CanNotInstantiate_1, new CRSPair(sourceCRS, targetCRS)),
e);
@@ -545,7 +551,8 @@ class CoordinateOperationRegistry {
                                                   final MathTransformFactory      mtFactory)
             throws IllegalArgumentException, ConversionException, FactoryException
     {
-        assert Utilities.deepEquals(sourceCRS, targetCRS, ComparisonMode.ALLOW_VARIANT);
+        assert ReferencingUtilities.getDimension(sourceCRS) != ReferencingUtilities.getDimension(targetCRS)
+                || Utilities.deepEquals(sourceCRS, targetCRS, ComparisonMode.ALLOW_VARIANT);
         final Matrix m = CoordinateSystems.swapAndScaleAxes(sourceCRS.getCoordinateSystem(),
targetCRS.getCoordinateSystem());
         return (m.isIdentity()) ? null : mtFactory.createAffineTransform(m);
     }
@@ -702,16 +709,20 @@ class CoordinateOperationRegistry {
      * <cite>best effort</cite> basis. In any cases, the {@link #complete} method
should be invoked
      * after this one in order to ensure that the source and target CRS are the expected
ones.</p>
      *
-     * @param  operation the original (typically two-dimensional) coordinate operation.
+     * @param  sourceCRS the potentially three-dimensional source CRS
      * @param  source3D  {@code true} for adding ellipsoidal height in source coordinates.
+     * @param  targetCRS the potentially three-dimensional target CRS
      * @param  target3D  {@code true} for adding ellipsoidal height in target coordinates.
+     * @param  operation the original (typically two-dimensional) coordinate operation.
      * @return a coordinate operation with the source and/or target coordinates made 3D,
      *         or {@code null} if this method does not know how to create the operation.
      * @throws IllegalArgumentException if the operation method can not have the desired
number of dimensions.
      * @throws FactoryException if an error occurred while creating the coordinate operation.
      */
-    private CoordinateOperation propagateVertical(final CoordinateOperation operation,
-            final boolean source3D, final boolean target3D) throws IllegalArgumentException,
FactoryException
+    private CoordinateOperation propagateVertical(final CoordinateReferenceSystem sourceCRS,
final boolean source3D,
+                                                  final CoordinateReferenceSystem targetCRS,
final boolean target3D,
+                                                  final CoordinateOperation operation)
+            throws IllegalArgumentException, FactoryException
     {
         final List<CoordinateOperation> operations = new ArrayList<CoordinateOperation>();
         if (operation instanceof ConcatenatedOperation) {
@@ -719,8 +730,8 @@ class CoordinateOperationRegistry {
         } else {
             operations.add(operation);
         }
-        if ((source3D && !propagateVertical(operations.listIterator(), true)) ||
-            (target3D && !propagateVertical(operations.listIterator(operations.size()),
false)))
+        if ((source3D && !propagateVertical(sourceCRS, targetCRS, operations.listIterator(),
true)) ||
+            (target3D && !propagateVertical(sourceCRS, targetCRS, operations.listIterator(operations.size()),
false)))
         {
             return null;
         }
@@ -737,13 +748,18 @@ class CoordinateOperationRegistry {
      * Appends a vertical axis in the source CRS of the first step {@code forward = true}
or in
      * the target CRS of the last step {@code forward = false} of the given operations chain.
      *
+     * @param  source3D    the potentially three-dimensional source CRS
+     * @param  target3D    the potentially three-dimensional target CRS
      * @param  operations  the chain of operations in which to add a vertical axis.
      * @param  forward     {@code true} for adding the vertical axis at the beginning, or
      *                     {@code false} for adding the vertical axis at the end.
      * @return {@code true} on success.
      * @throws IllegalArgumentException if the operation method can not have the desired
number of dimensions.
      */
-    private boolean propagateVertical(final ListIterator<CoordinateOperation> operations,
final boolean forward)
+    private boolean propagateVertical(final CoordinateReferenceSystem source3D,
+                                      final CoordinateReferenceSystem target3D,
+                                      final ListIterator<CoordinateOperation> operations,
+                                      final boolean forward)
             throws IllegalArgumentException, FactoryException
     {
         while (forward ? operations.hasNext() : operations.hasPrevious()) {
@@ -781,18 +797,18 @@ class CoordinateOperationRegistry {
                 if (op instanceof SingleOperation) {
                     final MathTransformFactory mtFactory = factorySIS.getMathTransformFactory();
                     if (mtFactory instanceof DefaultMathTransformFactory) {
-                        final CoordinateReferenceSystem source3D = toGeodetic3D(sourceCRS);
-                        final CoordinateReferenceSystem target3D = toGeodetic3D(targetCRS);
+                        if (forward) sourceCRS = toGeodetic3D(sourceCRS, source3D);
+                        else         targetCRS = toGeodetic3D(targetCRS, target3D);
                         final MathTransform mt;
                         try {
                             mt = ((DefaultMathTransformFactory) mtFactory).createParameterizedTransform(
                                     ((SingleOperation) op).getParameterValues(),
-                                    ReferencingUtilities.createTransformContext(source3D,
target3D, null));
+                                    ReferencingUtilities.createTransformContext(sourceCRS,
targetCRS, null));
                         } catch (InvalidGeodeticParameterException e) {
                             log(e);
                             break;
                         }
-                        operations.set(recreate(op, source3D, target3D, mt, mtFactory.getLastMethodUsed()));
+                        operations.set(recreate(op, sourceCRS, targetCRS, mt, mtFactory.getLastMethodUsed()));
                         return true;
                     }
                 }
@@ -823,7 +839,7 @@ class CoordinateOperationRegistry {
                  * conform to the definition provided by the authority.
                  */
                 final MathTransform mt = factorySIS.getMathTransformFactory().createAffineTransform(matrix);
-                operations.set(recreate(op, toGeodetic3D(sourceCRS), toGeodetic3D(targetCRS),
mt, null));
+                operations.set(recreate(op, toGeodetic3D(sourceCRS, source3D), toGeodetic3D(targetCRS,
target3D), mt, null));
             }
             /*
              * If we processed the operation that change the number of dimensions, we are
done.
@@ -839,13 +855,27 @@ class CoordinateOperationRegistry {
      * If the given CRS is two-dimensional, append an ellipsoidal height to it.
      * It is caller's responsibility to ensure that the given CRS is geographic.
      */
-    private CoordinateReferenceSystem toGeodetic3D(CoordinateReferenceSystem crs) throws
FactoryException {
+    private CoordinateReferenceSystem toGeodetic3D(CoordinateReferenceSystem crs,
+            final CoordinateReferenceSystem candidate) throws FactoryException
+    {
         assert (crs instanceof GeodeticCRS) && (crs.getCoordinateSystem() instanceof
EllipsoidalCS) : crs;
-        if (crs.getCoordinateSystem().getDimension() == 2) {
-            crs = ReferencingServices.getInstance().createCompoundCRS(factorySIS.getCRSFactory(),
factorySIS.getCSFactory(),
-                    derivedFrom(crs), crs, CommonCRS.Vertical.ELLIPSOIDAL.crs());
+        if (crs.getCoordinateSystem().getDimension() != 2) {
+            return crs;
+        }
+        /*
+         * The check for same class is a cheap way to ensure that the two CRS implement the
same GeoAPI interface.
+         * This test is stricter than necessary, but the result should still not wrong if
we miss an opportunity
+         * to return the existing instance.
+         */
+        if (crs.getClass() == candidate.getClass() && candidate.getCoordinateSystem().getDimension()
== 3) {
+            if (Utilities.equalsIgnoreMetadata(((SingleCRS) crs).getDatum(), ((SingleCRS)
candidate).getDatum())) {
+                return candidate;               // Keep the existing instance since it may
contain useful metadata.
+            }
         }
-        return crs;
+        return ReferencingServices.getInstance().createCompoundCRS(
+                factorySIS.getCRSFactory(),
+                factorySIS.getCSFactory(),
+                derivedFrom(crs), crs, CommonCRS.Vertical.ELLIPSOIDAL.crs());
     }
 
     /**

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java?rev=1740399&r1=1740398&r2=1740399&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
[UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
[UTF-8] Thu Apr 21 20:07:44 2016
@@ -44,6 +44,7 @@ import org.apache.sis.referencing.factor
 import org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory;
 import org.apache.sis.util.collection.WeakHashSet;
 import org.apache.sis.util.collection.Containers;
+import org.apache.sis.util.collection.Cache;
 import org.apache.sis.util.iso.AbstractFactory;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.ArgumentChecks;
@@ -121,10 +122,21 @@ public class DefaultCoordinateOperationF
     /**
      * Weak references to existing objects.
      * This set is used in order to return a pre-existing object instead of creating a new
one.
+     * This apply to object created explicitly, not to coordinate operations inferred by
a call
+     * to {@link #createOperation(CoordinateReferenceSystem, CoordinateReferenceSystem)}.
      */
     private final WeakHashSet<IdentifiedObject> pool;
 
     /**
+     * The cache of coordinate operations found for a given pair of source and target CRS.
+     * If current implementation, we cache only operations found without context (otherwise
+     * we would need to take in account the area of interest and desired accuracy in the
key).
+     *
+     * @see #createOperation(CoordinateReferenceSystem, CoordinateReferenceSystem, CoordinateOperationContext)
+     */
+    final Cache<CRSPair,CoordinateOperation> cache;
+
+    /**
      * Constructs a factory with no default properties.
      */
     public DefaultCoordinateOperationFactory() {
@@ -167,6 +179,7 @@ public class DefaultCoordinateOperationF
             mtFactory = factory;
         }
         pool = new WeakHashSet<IdentifiedObject>(IdentifiedObject.class);
+        cache = new Cache<CRSPair,CoordinateOperation>(12, 50, true);
     }
 
     /**
@@ -697,9 +710,32 @@ next:   for (int i=components.size(); --
                                                final CoordinateOperationContext context)
             throws OperationNotFoundException, FactoryException
     {
-        final AuthorityFactory registry = USE_EPSG_FACTORY ? CRS.getAuthorityFactory(Constants.EPSG)
: null;
-        return new CoordinateOperationFinder((registry instanceof CoordinateOperationAuthorityFactory)
?
-                (CoordinateOperationAuthorityFactory) registry : null, this, context).createOperation(sourceCRS,
targetCRS);
+        final Cache.Handler<CoordinateOperation> handler;
+        CoordinateOperation op;
+        if (context == null) {
+            final CRSPair key = new CRSPair(sourceCRS, targetCRS);
+            op = cache.peek(key);
+            if (op != null) {
+                return op;
+            }
+            handler = cache.lock(key);
+        } else {
+            // We currently do not cache the operation when the result may depend on the
context (see 'this.cache' javadoc).
+            handler = null;
+            op = null;
+        }
+        try {
+            if (handler == null || (op = handler.peek()) == null) {
+                final AuthorityFactory registry = USE_EPSG_FACTORY ? CRS.getAuthorityFactory(Constants.EPSG)
: null;
+                op = new CoordinateOperationFinder((registry instanceof CoordinateOperationAuthorityFactory)
?
+                        (CoordinateOperationAuthorityFactory) registry : null, this, context).createOperation(sourceCRS,
targetCRS);
+            }
+        } finally {
+            if (handler != null) {
+                handler.putAndUnlock(op);
+            }
+        }
+        return op;
     }
 
     /**

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/InverseOperationMethod.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/InverseOperationMethod.java?rev=1740399&r1=1740398&r2=1740399&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/InverseOperationMethod.java
[UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/InverseOperationMethod.java
[UTF-8] Thu Apr 21 20:07:44 2016
@@ -20,6 +20,7 @@ import java.util.Map;
 import java.util.HashMap;
 import javax.xml.bind.annotation.XmlTransient;
 import javax.measure.unit.Unit;
+import org.opengis.metadata.Identifier;
 import org.opengis.util.InternationalString;
 import org.opengis.parameter.ParameterValue;
 import org.opengis.parameter.ParameterValueGroup;
@@ -34,9 +35,6 @@ import org.apache.sis.internal.referenci
 import org.apache.sis.metadata.iso.ImmutableIdentifier;
 import org.apache.sis.util.Deprecable;
 
-// Branch-dependent imports
-import org.opengis.metadata.Identifier;
-
 
 /**
  * Description of the inverse of another method. This class should be used only when no operation
is defined

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java?rev=1740399&r1=1740398&r2=1740399&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java
[UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java
[UTF-8] Thu Apr 21 20:07:44 2016
@@ -115,9 +115,9 @@ final class SubOperationInfo {
         final Class<?> targetType = type(target);
         for (final Class<?>[] sourceTypes : COMPATIBLE_TYPES) {
             if (sourceTypes[0].isAssignableFrom(targetType)) {
-                int startAtDimension;
-                int endAtDimension = 0;
                 for (final Class<?> sourceType : sourceTypes) {
+                    int startAtDimension;
+                    int endAtDimension = 0;
                     for (int i=0; i<sourceIsUsed.length; i++) {
                         final SingleCRS source = sources.get(i);
                         startAtDimension = endAtDimension;
@@ -130,7 +130,7 @@ final class SubOperationInfo {
                                 if (failure == null) {
                                     failure = exception;
                                 } else {
-                                    // failure.addSuppressed(exception);
+                                    // failure.addSuppressed(exception) on the JDK7 branch.
                                 }
                                 continue;
                             }

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java?rev=1740399&r1=1740398&r2=1740399&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
[UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
[UTF-8] Thu Apr 21 20:07:44 2016
@@ -513,6 +513,44 @@ public final strictfp class CoordinateOp
     //////////////////////////////////////////////////////////////////////////////////
 
     /**
+     * Tests the conversion from a four-dimensional geographic CRS to a two-dimensional geographic
CRS.
+     * The vertical and temporal dimensions are simply dropped.
+     *
+     * @throws FactoryException if the operation can not be created.
+     * @throws TransformException if an error occurred while converting the test points.
+     */
+    @Test
+    @DependsOnMethod("testGeographic3D_to_2D")
+    public void testGeographic4D_to_2D() throws FactoryException, TransformException {
+        // NOTE: make sure that the 'sourceCRS' below is not equal to any other 'sourceCRS'
created in this class.
+        final CompoundCRS   sourceCRS = compound("Test4D", CommonCRS.WGS84.geographic3D(),
CommonCRS.Temporal.UNIX.crs());
+        final GeographicCRS targetCRS = CommonCRS.WGS84.geographic();
+        final CoordinateOperation operation = inference.createOperation(sourceCRS, targetCRS);
+        assertSame      ("sourceCRS", sourceCRS,        operation.getSourceCRS());
+        assertSame      ("targetCRS", targetCRS,        operation.getTargetCRS());
+
+        transform = operation.getMathTransform();
+        assertInstanceOf("transform", LinearTransform.class, transform);
+        assertEquals("sourceDimensions", 4, transform.getSourceDimensions());
+        assertEquals("targetDimensions", 2, transform.getTargetDimensions());
+        Assert.assertMatrixEquals("transform.matrix", Matrices.create(3, 5, new double[]
{
+            1, 0, 0, 0, 0,
+            0, 1, 0, 0, 0,
+            0, 0, 0, 0, 1
+        }), ((LinearTransform) transform).getMatrix(), STRICT);
+
+        isInverseTransformSupported = false;
+        verifyTransform(new double[] {
+            30, 10,  20, 1000,
+            20, 30, -10, 3000
+        }, new double[] {
+            30, 10,
+            20, 30
+        });
+        validate();
+    }
+
+    /**
      * Tests the conversion from a three-dimensional geographic CRS to a two-dimensional
geographic CRS.
      * The vertical dimension is simply dropped.
      *
@@ -640,6 +678,46 @@ public final strictfp class CoordinateOp
     }
 
     /**
+     * Tests extracting the vertical part of a spatio-temporal CRS.
+     *
+     * @throws FactoryException if the operation can not be created.
+     * @throws TransformException if an error occurred while converting the test points.
+     */
+    @Test
+    @DependsOnMethod("testGeographic3D_to_EllipsoidalHeight")
+    public void testGeographic4D_to_EllipsoidalHeight() throws FactoryException, TransformException
{
+        // NOTE: make sure that the 'sourceCRS' below is not equal to any other 'sourceCRS'
created in this class.
+        final CompoundCRS sourceCRS = compound("Test4D", CommonCRS.WGS84.geographic3D(),
CommonCRS.Temporal.JULIAN.crs());
+        final VerticalCRS targetCRS = CommonCRS.Vertical.ELLIPSOIDAL.crs();
+        final CoordinateOperation operation = inference.createOperation(sourceCRS, targetCRS);
+        assertSame      ("sourceCRS", sourceCRS,        operation.getSourceCRS());
+        assertSame      ("targetCRS", targetCRS,        operation.getTargetCRS());
+        assertEquals    ("name",      "Axis changes",   operation.getName().getCode());
+        assertInstanceOf("operation", Conversion.class, operation);
+
+        transform = operation.getMathTransform();
+        assertInstanceOf("transform", LinearTransform.class, transform);
+        assertEquals("sourceDimensions", 4, transform.getSourceDimensions());
+        assertEquals("targetDimensions", 1, transform.getTargetDimensions());
+        Assert.assertMatrixEquals("transform.matrix", Matrices.create(2, 5, new double[]
{
+            0, 0, 1, 0, 0,
+            0, 0, 0, 0, 1
+        }), ((LinearTransform) transform).getMatrix(), STRICT);
+
+        isInverseTransformSupported = false;
+        verifyTransform(new double[] {
+             0,  0,  0,  0,
+             5,  8, 20, 10,
+            -5, -8, 24, 30
+        }, new double[] {
+                     0,
+                    20,
+                    24,
+        });
+        validate();
+    }
+
+    /**
      * Convenience method for creating a compound CRS.
      */
     private static CompoundCRS compound(final String name, final CoordinateReferenceSystem...
components) {
@@ -713,6 +791,7 @@ public final strictfp class CoordinateOp
     @Test
     @DependsOnMethod("testTemporalConversion")
     public void testGeographic3D_to_4D() throws FactoryException, TransformException {
+        // NOTE: make sure that the 'sourceCRS' below is not equal to any other 'sourceCRS'
created in this class.
         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 = inference.createOperation(sourceCRS, targetCRS);

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationRegistryTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationRegistryTest.java?rev=1740399&r1=1740398&r2=1740399&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationRegistryTest.java
[UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationRegistryTest.java
[UTF-8] Thu Apr 21 20:07:44 2016
@@ -328,7 +328,7 @@ public final strictfp class CoordinateOp
         } else {
             assertEpsgNameWithoutIdentifierEqual("NTF (Paris) to WGS 84 (1)", operation);
             assertEpsgNameWithoutIdentifierEqual("NTF (Paris)",               operation.getSourceCRS());
-            assertEpsgNameWithoutIdentifierEqual("WGS 84",                    operation.getTargetCRS());
+            assertEquals("name",                 "WGS 84",                    operation.getTargetCRS().getName().getCode());
             assertEpsgNameWithoutIdentifierEqual("NTF (Paris) to NTF (1)",    step1);
             assertEpsgNameWithoutIdentifierEqual("NTF to WGS 84 (1)",         step2);
         }




Mime
View raw message