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


Reply via email to