You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2015/04/20 02:22:47 UTC
svn commit: r1674709 - in /sis/branches/JDK8/core/sis-referencing/src:
main/java/org/apache/sis/internal/referencing/j2d/
main/java/org/apache/sis/referencing/operation/transform/
test/java/org/apache/sis/referencing/operation/transform/
Author: desruisseaux
Date: Mon Apr 20 00:22:47 2015
New Revision: 1674709
URL: http://svn.apache.org/r1674709
Log:
Referencing: bug fixes
1) be less aggressive about unmodifiable ContextualParameters (we should be able to get a parameter default value if the parameter is not present).
2) ParameterizedAffine should return the "Equidistant Cylindrical (Spherical)" parameters when queried from a ProjectedCRS element no matter axis swapping.
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ParameterizedAffine.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ContextualParametersTest.java
Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ParameterizedAffine.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ParameterizedAffine.java?rev=1674709&r1=1674708&r2=1674709&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ParameterizedAffine.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ParameterizedAffine.java [UTF-8] Mon Apr 20 00:22:47 2015
@@ -21,6 +21,7 @@ import java.awt.geom.AffineTransform;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.referencing.operation.MathTransform;
+import org.apache.sis.internal.system.Semaphores;
/**
@@ -109,12 +110,35 @@ public final class ParameterizedAffine e
/**
* Returns the parameter values for this map projection.
*
+ * <p><b>Hack:</b> this method normally returns the matrix parameters in case of doubt. However if
+ * {@link Semaphores#PROJCS} is set, then this method returns the map projection parameters even
+ * if they are not a complete description of this math transform. This internal hack shall be used
+ * only by {@link org.apache.sis.referencing.operation.DefaultSingleOperation}.</p>
+ *
+ * <p><b>Use case of above hack:</b> consider an "Equidistant Cylindrical (Spherical)" map projection
+ * from a {@code GeographiCRS} base using (latitude, longitude) axis order. We need to concatenate an
+ * affine transform performing the axis swapping before the actual map projection. The concatenated
+ * transform is part of {@code SingleOperation}, which is itself part of {@code ProjecteCRS}.
+ * Consequently we have two conflicting needs:</p>
+ *
+ * <ul>
+ * <li>If this method is queried from a {@code SingleOperation} instance (usually indirectly as part of a
+ * {@code ProjectedCRS}), then we want to return the "Equidistant Cylindrical (Spherical)" map projection
+ * parameters without bothering about axis swapping, because the later is described by the {@code Axis["…"]}
+ * elements in the enclosing {@code ProjectedCRS} instance.</li>
+ * <li>But if this {@code MathTransform} is formatted directly (not as a component of {@code ProjectedCRS}),
+ * then we want to format it as a matrix, otherwise the users would have no way to see that an axis swapping
+ * has been applied.</li>
+ * </ul>
+ *
+ * The {@code Semaphores.PROJCS} flag is SIS internal mechanism for distinguish the two above-cited cases.
+ *
* @return The map projection parameters if they are an accurate description of this transform,
* or the generic affine parameters in case of doubt.
*/
@Override
public ParameterValueGroup getParameterValues() {
- return isDefinitive ? parameters : super.getParameterValues();
+ return isDefinitive || Semaphores.query(Semaphores.PROJCS) ? parameters : super.getParameterValues();
}
/**
@@ -131,7 +155,8 @@ public final class ParameterizedAffine e
if (super.equals(object)) {
if (object instanceof ParameterizedAffine) {
final ParameterizedAffine that = (ParameterizedAffine) object;
- return Objects.equals(this.parameters, that.parameters);
+ return (this.isDefinitive == that.isDefinitive) &&
+ Objects.equals(this.parameters, that.parameters);
}
return true;
}
Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java?rev=1674709&r1=1674708&r2=1674709&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java [UTF-8] Mon Apr 20 00:22:47 2015
@@ -18,6 +18,9 @@ package org.apache.sis.referencing.opera
import java.util.List;
import java.util.Arrays;
+import java.util.Map;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
import java.util.Objects;
import java.io.Serializable;
import org.opengis.util.FactoryException;
@@ -368,13 +371,44 @@ public class ContextualParameters extend
{
if (!isFrozen) {
isFrozen = true;
- for (int i=0; i < values.length; i++) {
- final ParameterValue<?> p = values[i];
+ /*
+ * Sort the parameter values in the same order than the parameter descriptor. This is not essential,
+ * but makes easier to read 'toString()' output by ensuring a consistent order for most projections.
+ * Some WKT parsers other than SIS may also require the parameter values to be listed in that specific
+ * order. We proceed by first copying all parameters in a temporary HashMap:
+ */
+ final Map<ParameterDescriptor<?>, ParameterValue<?>> parameters = new IdentityHashMap<>(values.length);
+ for (ParameterValue<?> p : values) {
if (p == null) {
- values = Arrays.copyOf(values, i); // Trim extra values.
- break;
+ break; // The first null value in the array indicates the end of sequence.
+ }
+ p = DefaultParameterValue.unmodifiable(p);
+ final ParameterDescriptor<?> desc = p.getDescriptor();
+ if (parameters.put(desc, p) != null) {
+ // Should never happen unless ParameterValue.descriptor changed (contract violation).
+ throw new IllegalStateException(Errors.format(Errors.Keys.ElementAlreadyPresent_1, desc.getName()));
+ }
+ }
+ /*
+ * Then, copy all HashMap values back to the 'values' array in the order they are declared in the
+ * descriptor. Implementation note: the iteration termination condition uses the values array, not
+ * the descriptors list, because the former is often shorter than the later. We should never reach
+ * the end of descriptors list before the end of values array because 'descriptors' contains all
+ * 'parameters' keys. This is verified by the 'assert' below.
+ */
+ values = new ParameterValue<?>[parameters.size()];
+ assert descriptor.descriptors().containsAll(parameters.keySet());
+ final Iterator<GeneralParameterDescriptor> it = descriptor.descriptors().iterator();
+ for (int i=0; i < values.length;) {
+ /*
+ * No need to check for it.hasNext(), since a NoSuchElementException below would be a bug in
+ * our algorithm (or a concurrent change in the 'descriptor.descriptors()' list, which would
+ * be a contract violation). See above 'assert'.
+ */
+ final ParameterValue<?> p = parameters.get(it.next());
+ if (p != null) {
+ values[i++] = p;
}
- values[i] = DefaultParameterValue.unmodifiable(p);
}
}
/*
@@ -418,11 +452,6 @@ public class ContextualParameters extend
for (int i=0; i < values.length; i++) {
ParameterValue<?> p = values[i];
if (p == null) {
- /*
- * No existing parameter instance. Create a new one if this ContextualParameter
- * is still modifiable.
- */
- ensureModifiable();
p = ((ParameterDescriptor<?>) desc).createValue();
values[i] = p;
} else if (p.getDescriptor() != desc) { // Identity comparison should be okay here.
@@ -430,7 +459,17 @@ public class ContextualParameters extend
}
return p; // Found or created a parameter.
}
- ensureModifiable();
+ /*
+ * We may reach this point if map projection construction is completed (i.e. 'completeTransform(…)' has
+ * been invoked) and the user asks for a parameter which is not one of the parameters that we retained.
+ * Returns a parameter initialized to the default value, which is the actual value (otherwise we would
+ * have stored that parameter). Note: we do not bother making the parameter immutable for performance
+ * reason. If the user invokes a setter method on the returned parameter, he may get a false impression
+ * that this ContextualParameters is still modifiable. We presume that such scenario would be rare.
+ */
+ if (isFrozen) {
+ return ((ParameterDescriptor<?>) desc).createValue();
+ }
/*
* Should never reach this point. If it happen anyway, this means that the descriptor now accepts
* more parameters than what it declared at ContextualParameteres construction time, or that some
Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java?rev=1674709&r1=1674708&r2=1674709&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java [UTF-8] Mon Apr 20 00:22:47 2015
@@ -665,7 +665,7 @@ public class DefaultMathTransformFactory
* "elt_0_0", "elt_0_1", etc. The following code just forwards those parameters to the newly
* created transform; it does not change the operation.
*/
- if (parameterized instanceof ParameterizedAffine) {
+ if (parameterized instanceof ParameterizedAffine && !(mt instanceof ParameterizedAffine)) {
mt = ((ParameterizedAffine) parameterized).newTransform(mt);
}
return mt;
Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ContextualParametersTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ContextualParametersTest.java?rev=1674709&r1=1674708&r2=1674709&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ContextualParametersTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ContextualParametersTest.java [UTF-8] Mon Apr 20 00:22:47 2015
@@ -112,15 +112,16 @@ public final strictfp class ContextualPa
@Test
public void testSameTransform() throws FactoryException {
final ContextualParameters p = create(1, 1);
+ p.parameter("Mandatory 1").setValue(4);
final MathTransform kernel = MathTransforms.linear(3, 4);
assertEquals(kernel, p.completeTransform(DefaultMathTransformFactoryTest.factory(), kernel));
try {
- p.parameter("Mandatory 1");
+ p.parameter("Mandatory 1").setValue(10);
fail("Shall not be allowed to modify an immutable instance.");
- } catch (IllegalStateException e) {
+ } catch (UnsupportedOperationException e) {
// This is the expected exception.
final String message = e.getMessage();
- assertTrue(message, message.contains("ContextualParameters"));
+ assertTrue(message, message.contains("ParameterValue"));
}
}