Author: desruisseaux
Date: Wed Apr 6 13:15:00 2016
New Revision: 1737980
URL: http://svn.apache.org/viewvc?rev=1737980&view=rev
Log:
Complete support of coordinate operation between CompoundCRS and enable the
test.
Modified:
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/SourceComponent.java
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationInferenceTest.java
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=1737980&r1=1737979&r2=1737980&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] Wed Apr 6 13:15:00 2016
@@ -745,6 +745,7 @@ public class CoordinateOperationInferenc
final List<SingleCRS> targets = CRS.getSingleComponents(targetCRS);
final SourceComponent[] infos = new SourceComponent[targets.size()];
final boolean[] sourceIsUsed = new boolean[sources.size()];
+ final CoordinateReferenceSystem[] stepComponents = new
CoordinateReferenceSystem[infos.length];
/*
* Operations found are stored in 'infos', but are not yet wrapped in
PassThroughOperations.
* We need to know first if some ordinate values need reordering for
matching the target CRS
@@ -754,13 +755,109 @@ public class CoordinateOperationInferenc
if ((infos[i] = SourceComponent.create(this, sourceIsUsed,
sources, targets.get(i))) == null) {
throw new
OperationNotFoundException(notFoundMessage(sourceCRS, targetCRS));
}
+ stepComponents[i] = infos[i].operation.getSourceCRS();
}
/*
- * A coordinate operation has been found for every target component
CRS.
- * Some reordering of ordinate values may be needed, and some
coordinates may need to be dropped.
+ * At this point, a coordinate operation has been found for all
components of the target CRS.
+ * However the CoordinateOperation.getSourceCRS() values are not
necessarily in the same order
+ * than the components of the source CRS given to this method, and
some dimensions may be dropped.
+ * The matrix computed by sourceToSelected(…) gives us the
rearrangement needed for the coordinate
+ * operations that we just found.
*/
- final Matrix select =
SourceComponent.sourceToSelected(sourceCRS.getCoordinateSystem().getDimension(),
infos);
- throw new UnsupportedOperationException(); // TODO continue work
from here.
+ int remainingSourceDimensions = 0;
+ for (final SourceComponent component : infos) {
+ remainingSourceDimensions += component.endAtDimension -
component.startAtDimension;
+ }
+ final Matrix select = SourceComponent.sourceToSelected(
+ sourceCRS.getCoordinateSystem().getDimension(),
remainingSourceDimensions, infos);
+ /*
+ * First, we need a CRS matching the above-cited rearrangement. That
CRS will be named 'stepSourceCRS'
+ * and its components will be named 'stepComponents'. Then we will
execute a loop in which each component
+ * is progressively (one by one) updated from a source component to a
target component. A new step CRS is
+ * recreated each time, since it will be needed for each
PassThroughOperation.
+ */
+ CoordinateReferenceSystem stepSourceCRS;
+ CoordinateOperation operation;
+ if (select.isIdentity()) {
+ stepSourceCRS = sourceCRS; // No rearrangement - we
can use source CRS as-is.
+ operation = null;
+ } else {
+ if (stepComponents.length == 1) {
+ stepSourceCRS = stepComponents[0]; // Slight optimization
of the next block (in the 'else' case).
+ } else {
+ stepSourceCRS =
factorySIS.getCRSFactory().createCompoundCRS(derivedFrom(sourceCRS),
stepComponents);
+ }
+ operation = createFromAffineTransform(AXIS_CHANGES, sourceCRS,
stepSourceCRS, select);
+ }
+ /*
+ * For each sub-operation, create a PassThroughOperation for the
(stepSourceCRS → stepTargetCRS) operation.
+ * Each source CRS inside this loop will be for dimensions at indices
[startAtDimension … endAtDimension-1].
+ * Note that those indices are not necessarily the same than the
indices in the fields of the same name in
+ * SourceComponent, because those indices are not relative to the same
CompoundCRS.
+ */
+ int endAtDimension = 0;
+ final int startOfIdentity = SourceComponent.startOfIdentity(infos);
+ for (int i=0; i<stepComponents.length; i++) {
+ final CoordinateReferenceSystem source = stepComponents[i];
+ final CoordinateReferenceSystem target = targets.get(i);
+ CoordinateOperation subOperation = infos[i].operation;
+ final MathTransform subTransform = subOperation.getMathTransform();
+ /*
+ * In order to compute 'stepTargetCRS', replace in-place a single
element in 'stepComponents'.
+ * For each step except the last one, 'stepTargetCRS' is a mix of
target and source CRS. Only
+ * after the loop finished, 'stepTargetCRS' will become the
complete targetCRS definition.
+ */
+ final CoordinateReferenceSystem stepTargetCRS;
+ stepComponents[i] = target;
+ if (i >= startOfIdentity) {
+ stepTargetCRS = targetCRS; // If all remaining
transforms are identity, we reached the final CRS.
+ } else if (subTransform.isIdentity()) {
+ stepTargetCRS = stepSourceCRS; // In any identity
transform, the source and target CRS are equal.
+ } else if (stepComponents.length == 1) {
+ stepTargetCRS = target; // Slight optimization
of the next block.
+ } else {
+ stepTargetCRS =
ReferencingServices.getInstance().createCompoundCRS(
+ factorySIS.getCRSFactory(), factorySIS.getCSFactory(),
derivedFrom(target), stepComponents);
+ }
+ int delta = source.getCoordinateSystem().getDimension();
+ final int startAtDimension = endAtDimension;
+ endAtDimension += delta;
+ /*
+ * Constructs the pass through transform only if there is at least
one ordinate to pass.
+ * Actually the code below would work inconditionally, but we
perform this check anyway
+ * for avoiding the creation of intermediate objects.
+ */
+ if (!(startAtDimension == 0 && endAtDimension ==
remainingSourceDimensions)) {
+ final Map<String,?> properties =
IdentifiedObjects.getProperties(subOperation);
+ /*
+ * The DefaultPassThroughOperation constuctor expect a
SingleOperation.
+ * In most case, the 'subOperation' is already of this kind.
However if
+ * it is not, try to copy it in such object.
+ */
+ final SingleOperation op;
+ if (subOperation instanceof SingleOperation) {
+ op = (SingleOperation) subOperation;
+ } else {
+ op = factorySIS.createSingleOperation(properties,
+ subOperation.getSourceCRS(),
subOperation.getTargetCRS(), null,
+ new DefaultOperationMethod(subTransform),
subTransform);
+ }
+ subOperation = new DefaultPassThroughOperation(properties,
stepSourceCRS, stepTargetCRS,
+ op, startAtDimension, remainingSourceDimensions -
endAtDimension);
+ }
+ /*
+ * Concatenate the operation with the ones we have found so far,
and use the current 'stepTargetCRS'
+ * as the source CRS for the next operation step. We also need to
adjust the dimension indices,
+ * since the previous operations may have removed some dimensions.
Note that the delta may also
+ * be negative in a few occasions.
+ */
+ operation = concatenate(operation, subOperation);
+ stepSourceCRS = stepTargetCRS;
+ delta -= target.getCoordinateSystem().getDimension();
+ endAtDimension -= delta;
+ remainingSourceDimensions -= delta;
+ }
+ return operation;
}
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SourceComponent.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SourceComponent.java?rev=1737980&r1=1737979&r2=1737980&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SourceComponent.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SourceComponent.java
[UTF-8] Wed Apr 6 13:15:00 2016
@@ -78,12 +78,12 @@ final class SourceComponent {
/**
* Returns the first dimension (inclusive) where the source component CRS
begins in the source compound CRS.
*/
- private final int startAtDimension;
+ final int startAtDimension;
/**
* Returns the last dimension (exclusive) where the source component CRS
ends in the source compound CRS.
*/
- private final int endAtDimension;
+ final int endAtDimension;
/**
* Creates a new instance containing the given information.
@@ -132,7 +132,7 @@ final class SourceComponent {
continue;
}
/*
- * Found an operation. Remove the source component
from the list because each source
+ * Found an operation. Exclude the source
component from the list because each source
* should be used at most once by SourceComponent.
Note that the same source may still
* be used again in another context if that source
is also an interpolation CRS.
*
@@ -164,17 +164,27 @@ final class SourceComponent {
}
/**
+ * Returns the dimension from which all remaining operations are identity.
+ */
+ static int startOfIdentity(final SourceComponent[] selected) {
+ int n = selected.length;
+ while (n != 0) {
+ if (!selected[--n].operation.getMathTransform().isIdentity()) {
+ break;
+ }
+ }
+ return n;
+ }
+
+ /**
* Returns a matrix for an affine transform from all source coordinates to
the coordinates of the
* source components selected for participating in the coordinate
operation.
*
- * @param sourceDimensions number of dimension of the source {@code
CompoundCRS}.
+ * @param sourceDimensions number of dimension of the source {@code
CompoundCRS}.
+ * @param selectedDimensions number of source dimensions needed by the
coordinate operations.
* @param selected all {@code SourceComponent} instances needed for the
target {@code CompoundCRS}.
*/
- static Matrix sourceToSelected(final int sourceDimensions, final
SourceComponent[] selected) {
- int selectedDimensions = 0;
- for (final SourceComponent component : selected) {
- selectedDimensions += component.endAtDimension -
component.startAtDimension;
- }
+ static Matrix sourceToSelected(final int sourceDimensions, final int
selectedDimensions, final SourceComponent[] selected) {
final Matrix select = Matrices.createZero(selectedDimensions + 1,
sourceDimensions + 1);
select.setElement(selectedDimensions, sourceDimensions, 1);
int j = 0;
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=1737980&r1=1737979&r2=1737980&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] Wed Apr 6 13:15:00 2016
@@ -34,6 +34,7 @@ import org.opengis.referencing.operation
import org.opengis.referencing.operation.Projection;
import org.opengis.referencing.operation.Transformation;
import org.opengis.referencing.operation.TransformException;
+import org.opengis.referencing.operation.ConcatenatedOperation;
import org.opengis.referencing.operation.OperationNotFoundException;
import org.apache.sis.referencing.operation.transform.LinearTransform;
import org.apache.sis.referencing.operation.matrix.Matrices;
@@ -585,6 +586,7 @@ public final strictfp class CoordinateOp
* @throws TransformException if an error occurred while converting the
test points.
*/
@Test
+ @DependsOnMethod("testIdentityTransform")
public void testGeographic3D_to_EllipsoidalHeight() throws
FactoryException, TransformException {
final CoordinateReferenceSystem sourceCRS =
CommonCRS.WGS84.geographic3D();
final CoordinateReferenceSystem targetCRS =
HardCodedCRS.ELLIPSOIDAL_HEIGHT_cm;
@@ -630,15 +632,16 @@ public final strictfp class CoordinateOp
* @throws FactoryException if the operation can not be created.
* @throws TransformException if an error occurred while converting the
test points.
*/
-// @Test
+ @Test
+ @DependsOnMethod("testTemporalConversion")
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);
- assertSame ("sourceCRS", sourceCRS,
operation.getSourceCRS());
- assertSame ("targetCRS", targetCRS,
operation.getTargetCRS());
- assertEquals ("name", "Axis changes",
operation.getName().getCode());
- assertInstanceOf("operation", Conversion.class, operation);
+ assertSame ("sourceCRS", sourceCRS, operation.getSourceCRS());
+ assertSame ("targetCRS", targetCRS, operation.getTargetCRS());
+ assertInstanceOf("operation", ConcatenatedOperation.class, operation);
+ assertEquals ("name", "CompoundCRS[“Test3D”] →
CompoundCRS[“Test4D”]", operation.getName().getCode());
transform = operation.getMathTransform();
assertInstanceOf("transform", LinearTransform.class, transform);
@@ -651,6 +654,13 @@ public final strictfp class CoordinateOp
0, 0, 1./(24*60*60), 40587,
0, 0, 0, 1
}), ((LinearTransform) transform).getMatrix(), 1E-12);
+
+ tolerance = 1E-12;
+ verifyTransform(new double[] {
+ -5, -8,
CommonCRS.Temporal.DUBLIN_JULIAN.datum().getOrigin().getTime() / 1000
+ }, new double[] {
+ -5, -8, 0, 15019.5 // Same value than in
testTemporalConversion().
+ });
validate();
}
}