sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1740342 - in /sis/branches/JDK7: ./ core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/ core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/
Date Thu, 21 Apr 2016 15:37:26 GMT
Author: desruisseaux
Date: Thu Apr 21 15:37:26 2016
New Revision: 1740342

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

Modified:
    sis/branches/JDK7/   (props changed)
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java

Propchange: sis/branches/JDK7/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Apr 21 15:37:26 2016
@@ -1,4 +1,4 @@
 /sis/branches/Android:1430670-1480699
 /sis/branches/JDK6:1394913-1508480
-/sis/branches/JDK8:1584960-1740205
+/sis/branches/JDK8:1584960-1740312
 /sis/trunk:1394364-1508466,1519089-1519674

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java?rev=1740342&r1=1740341&r2=1740342&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
[UTF-8] Thu Apr 21 15:37:26 2016
@@ -59,7 +59,7 @@ final class CRSPair {
      */
     @Override
     public int hashCode() {
-        return sourceCRS.hashCode() * 31 + targetCRS.hashCode();
+        return Objects.hashCode(sourceCRS) * 31 + Objects.hashCode(targetCRS);
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java?rev=1740342&r1=1740341&r2=1740342&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
[UTF-8] Thu Apr 21 15:37:26 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<>(8);
         previousSearches    = new HashMap<>(8);
+        useCache = (context == null) && (factory == factorySIS);
     }
 
     /**
@@ -190,13 +196,31 @@ 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 | 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),
@@ -897,8 +921,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);
@@ -911,7 +941,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())
{
@@ -954,6 +984,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/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java?rev=1740342&r1=1740341&r2=1740342&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
[UTF-8] Thu Apr 21 15:37:26 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.class);
+        cache = new Cache<>(12, 50, true);
     }
 
     /**
@@ -699,9 +712,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/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java?rev=1740342&r1=1740341&r2=1740342&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java
[UTF-8] Thu Apr 21 15:37:26 2016
@@ -112,9 +112,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;

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java?rev=1740342&r1=1740341&r2=1740342&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
[UTF-8] Thu Apr 21 15:37:26 2016
@@ -512,6 +512,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.
      *
@@ -639,6 +677,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) {
@@ -712,6 +790,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);



Mime
View raw message