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);