sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1600340 [1/2] - in /sis/branches/JDK8/core: sis-metadata/src/main/java/org/apache/sis/io/wkt/ sis-referencing/src/main/java/org/apache/sis/internal/referencing/ sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/ sis...
Date Wed, 04 Jun 2014 17:00:14 GMT
Author: desruisseaux
Date: Wed Jun  4 17:00:13 2014
New Revision: 1600340

URL: http://svn.apache.org/r1600340
Log:
Ported ConcatenatedTransform implementations and some of their dependencies.

Added:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Semaphores.java   (with props)
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform1D.java   (with props)
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform2D.java   (with props)
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform.java   (with props)
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform1D.java   (with props)
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform2D.java   (with props)
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransformDirect.java   (with props)
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransformDirect1D.java   (with props)
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransformDirect2D.java   (with props)
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java   (with props)
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PassThroughTransform.java   (with props)
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ProjectiveTransform.java   (with props)
Modified:
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Formulas.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LinearTransform.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java?rev=1600340&r1=1600339&r2=1600340&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java [UTF-8] Wed Jun  4 17:00:13 2014
@@ -84,7 +84,7 @@ import org.apache.sis.metadata.iso.exten
  * </ul>
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @since   0.4 (derived from geotk-2.0)
+ * @since   0.5 (derived from geotk-2.0)
  * @version 0.4
  * @module
  */
@@ -1174,6 +1174,32 @@ public class Formatter implements Locali
     }
 
     /**
+     * Delegates the formatting to another {@link FormattableObject} implementation.
+     * Invoking this method is equivalent to first verifying the {@code other} class,
+     * then delegating as below:
+     *
+     * {@preformat
+     *     return other.formatTo(this);
+     * }
+     *
+     * This method is useful for {@code FormattableObject} which are wrapper around another object.
+     * It allows to delegate the WKT formatting to the wrapped object.
+     *
+     * @param  other The object to format with this formatter.
+     * @return The value returned by {@link FormattableObject#formatTo(Formatter)}.
+     *
+     * @since 0.5
+     */
+    public String delegateTo(final Object other) throws UnformattableObjectException {
+        ArgumentChecks.ensureNonNull("other", other);
+        if (other instanceof FormattableObject) {
+            return ((FormattableObject) other).formatTo(this);
+        }
+        throw new UnformattableObjectException(Errors.format(
+                Errors.Keys.IllegalClass_2, FormattableObject.class, other.getClass()));
+    }
+
+    /**
      * Returns the enclosing WKT element, or {@code null} if element being formatted is the root.
      * This method can be invoked by child elements having some aspects that depend on the enclosing element.
      *

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Formulas.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Formulas.java?rev=1600340&r1=1600339&r2=1600340&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Formulas.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Formulas.java [UTF-8] Wed Jun  4 17:00:13 2014
@@ -95,8 +95,12 @@ public final class Formulas extends Stat
      * @see org.apache.sis.referencing.datum.DefaultEllipsoid#getAuthalicRadius()
      */
     public static double getAuthalicRadius(final double a, final double b) {
-        final double f = 1 - b/a;
-        final double e = sqrt(2*f - f*f);
-        return sqrt(0.5 * (a*a + b*b*atanh(e)/e));
+        if (a != b) {
+            final double f = 1 - b/a;
+            final double e = sqrt(2*f - f*f);
+            return sqrt(0.5 * (a*a + b*b*atanh(e)/e));
+        } else {
+            return a;
+        }
     }
 }

Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Semaphores.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Semaphores.java?rev=1600340&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Semaphores.java (added)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Semaphores.java [UTF-8] Wed Jun  4 17:00:13 2014
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.referencing;
+
+
+/**
+ * Semaphores that need to be shared across different referencing packages. Each thread has its own set of semaphores.
+ * The {@link #clear(int)} method <strong>must</strong> be invoked after the {@link #queryAndSet(int)} method in a
+ * {@code try ... finally} block.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.5 (derived from geotk-3.00)
+ * @version 0.5
+ * @module
+ */
+public final class Semaphores {
+    /**
+     * A lock for avoiding never-ending recursivity in the {@code equals} method of
+     * {@link org.apache.sis.referencing.crs.AbstractDerivedCRS} and
+     * {@link org.apache.sis.referencing.operation.AbstractCoordinateOperation}.
+     * It is set to {@code true} when a comparison is in progress. This lock is necessary because
+     * {@code AbstractDerivedCRS} objects contain a {@code conversionFromBase} field, which contains a
+     * {@code DefaultConversion.targetCRS} field referencing back the {@code AbstractDerivedCRS} object.
+     */
+    public static final int COMPARING = 1;
+
+    /**
+     * A flag to indicate that {@link org.apache.sis.referencing.operation.DefaultSingleOperation}
+     * is querying {@link org.apache.sis.referencing.operation.transform.ConcatenatedTransform} in
+     * the intend to format WKT (normally a {@code "PROJCS"} element).
+     */
+    public static final int PROJCS = 2;
+
+    /**
+     * The flags per running thread.
+     */
+    private static final ThreadLocal<Semaphores> FLAGS = new ThreadLocal<>();
+
+    /**
+     * The bit flags.
+     */
+    private int flags;
+
+    /**
+     * For internal use only.
+     */
+    private Semaphores() {
+    }
+
+    /**
+     * Returns {@code true} if the given flag is set.
+     *
+     * @param  flag One of {@link #COMPARING} or {@link #PROJCS} constants.
+     * @return {@code true} if the given flag is set.
+     */
+    public static boolean query(final int flag) {
+        final Semaphores s = FLAGS.get();
+        return (s != null) && (s.flags & flag) != 0;
+    }
+
+    /**
+     * Sets the given flag.
+     *
+     * @param  flag One of {@link #COMPARING} or {@link #PROJCS} constants.
+     * @return {@code true} if the given flag was already set.
+     */
+    public static boolean queryAndSet(final int flag) {
+        Semaphores s = FLAGS.get();
+        if (s == null) {
+            s = new Semaphores();
+            FLAGS.set(s);
+        }
+        final boolean isSet = ((s.flags & flag) != 0);
+        s.flags |= flag;
+        return isSet;
+    }
+
+    /**
+     * Clears the given flag.
+     *
+     * @param flag One of {@link #COMPARING} or {@link #PROJCS} constants.
+     */
+    public static void clear(final int flag) {
+        final Semaphores s = FLAGS.get();
+        if (s != null) {
+            s.flags &= ~flag;
+        }
+    }
+}

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Semaphores.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Semaphores.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java?rev=1600340&r1=1600339&r2=1600340&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java [UTF-8] Wed Jun  4 17:00:13 2014
@@ -533,7 +533,7 @@ public final class Matrices extends Stat
      * @throws IllegalArgumentException if a value of {@code selectedDimensions} is lower than 0
      *         or not smaller than {@code sourceDimensions}.
      *
-     * @see org.apache.sis.referencing.operation.MathTransforms#dimensionFilter(int, int[])
+     * @see org.apache.sis.referencing.operation.transform.MathTransforms#dimensionFilter(int, int[])
      */
     public static MatrixSIS createDimensionSelect(final int sourceDimensions, final int[] selectedDimensions) {
         final int numTargetDim = selectedDimensions.length;

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java?rev=1600340&r1=1600339&r2=1600340&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java [UTF-8] Wed Jun  4 17:00:13 2014
@@ -303,7 +303,7 @@ public abstract class AbstractMathTransf
      *
      * @see #derivative(DirectPosition)
      * @see #transform(DirectPosition, DirectPosition)
-     * @see org.apache.sis.referencing.operation.MathTransforms#derivativeAndTransform(MathTransform, double[], int, double[], int)
+     * @see MathTransforms#derivativeAndTransform(MathTransform, double[], int, double[], int)
      */
     public abstract Matrix transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, boolean derivate)
             throws TransformException;
@@ -923,7 +923,7 @@ public abstract class AbstractMathTransf
      * The parameter group name is used as the math transform name.
      *
      * @param  formatter The formatter to use.
-     * @return The WKT element name, which is {@code "PARAM_MT"} in the default implementation.
+     * @return The WKT element name, which is {@code "Param_MT"} in the default implementation.
      */
     @Override
     public String formatTo(final Formatter formatter) {
@@ -932,7 +932,7 @@ public abstract class AbstractMathTransf
             WKTUtilities.appendName(parameters.getDescriptor(), formatter, null);
             WKTUtilities.append(parameters, formatter);
         }
-        return "PARAM_MT";
+        return "Param_MT";
     }
 
     /**
@@ -950,14 +950,19 @@ public abstract class AbstractMathTransf
      * @see AbstractMathTransform2D#beforeFormat(List, int, boolean)
      * @see ConcatenatedTransform#getPseudoSteps()
      */
-    int beforeFormat(List<Object> transforms, int index, boolean inverse) {
+    int beforeFormat(List<MathTransform> transforms, int index, boolean inverse) {
         return index;
     }
 
     /**
-     * Default implementation for inverse math transform. This inner class is the inverse of
-     * the enclosing {@link AbstractMathTransform}. It is serializable only if the enclosing
-     * math transform is also serializable.
+     * Base class for implementations of inverse math transforms.
+     * This inner class is the inverse of the enclosing {@link AbstractMathTransform}.
+     *
+     * {@section Serialization}
+     * Instances of this class are serializable only if the enclosing math transform is also serializable.
+     * Serialized math transforms are not guaranteed to be compatible with future SIS versions.
+     * Serialization, if allowed, should be used only for short term storage or RMI between applications
+     * running the same SIS version.
      *
      * @author  Martin Desruisseaux (IRD, Geomatys)
      * @since   0.5 (derived from geotk-2.0)
@@ -1024,13 +1029,10 @@ public abstract class AbstractMathTransf
         /**
          * Returns the inverse of this math transform, which is the enclosing math transform.
          *
-         * <div class="note"><b>API note:</b> this method is final because some implementations assume
-         * that the inverse of {@code this} is always {@code AbstractMathTransform.this}.</div>
-         *
          * @return The enclosing math transform.
          */
         @Override
-        public final MathTransform inverse() {
+        public MathTransform inverse() {
             return AbstractMathTransform.this;
         }
 
@@ -1069,8 +1071,7 @@ public abstract class AbstractMathTransf
                 return true;
             }
             if (object != null && object.getClass() == getClass()) {
-                final Inverse that = (Inverse) object;
-                return AbstractMathTransform.this.equals(that.inverse(), mode);
+                return AbstractMathTransform.this.equals(((Inverse) object).inverse(), mode);
             } else {
                 return false;
             }
@@ -1080,11 +1081,11 @@ public abstract class AbstractMathTransf
          * Formats the inner part of a <cite>Well Known Text</cite> version 1 (WKT 1) element.
          * If this inverse math transform has any parameter values, then this method format the
          * WKT as in the {@linkplain AbstractMathTransform#formatWKT super-class method}.
-         * Otherwise this method formats the math transform as an {@code "INVERSE_MT"} entity.
+         * Otherwise this method formats the math transform as an {@code "Inverse_MT"} entity.
          *
          * @param  formatter The formatter to use.
-         * @return The WKT element name, which is {@code "PARAM_MT"} or
-         *         {@code "INVERSE_MT"} in the default implementation.
+         * @return The WKT element name, which is {@code "Param_MT"} or
+         *         {@code "Inverse_MT"} in the default implementation.
          */
         @Override
         public String formatTo(final Formatter formatter) {
@@ -1092,10 +1093,10 @@ public abstract class AbstractMathTransf
             if (parameters != null) {
                 WKTUtilities.appendName(parameters.getDescriptor(), formatter, null);
                 WKTUtilities.append(parameters, formatter);
-                return "PARAM_MT";
+                return "Param_MT";
             } else {
                 formatter.append((FormattableObject) AbstractMathTransform.this);
-                return "INVERSE_MT";
+                return "Inverse_MT";
             }
         }
     }

Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform1D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform1D.java?rev=1600340&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform1D.java (added)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform1D.java [UTF-8] Wed Jun  4 17:00:13 2014
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.referencing.operation.transform;
+
+import org.opengis.geometry.DirectPosition;
+import org.opengis.geometry.MismatchedDimensionException;
+import org.opengis.referencing.operation.Matrix;
+import org.opengis.referencing.operation.MathTransform1D;
+import org.opengis.referencing.operation.NoninvertibleTransformException;
+import org.opengis.referencing.operation.TransformException;
+import org.apache.sis.referencing.operation.matrix.Matrix1;
+
+import static org.apache.sis.util.ArgumentChecks.ensureDimensionMatches;
+
+
+/**
+ * Base class for math transforms that are known to be one-dimensional in all cases.
+ * One-dimensional math transforms are not required to extend this class,
+ * however doing so may simplify their implementation.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.5 (derived from geotk-3.17)
+ * @version 0.5
+ * @module
+ */
+public abstract class AbstractMathTransform1D extends AbstractMathTransform implements MathTransform1D {
+    /**
+     * Constructs a default math transform.
+     */
+    protected AbstractMathTransform1D() {
+    }
+
+    /**
+     * Returns the dimension of input points, which is always 1.
+     */
+    @Override
+    public final int getSourceDimensions() {
+        return 1;
+    }
+
+    /**
+     * Returns the dimension of output points, which is always 1.
+     */
+    @Override
+    public final int getTargetDimensions() {
+        return 1;
+    }
+
+    /**
+     * Transforms a single point in the given array and opportunistically computes its derivative if requested.
+     * The default implementation delegates to {@link #transform(double)} and potentially to {@link #derivative(double)}.
+     * Subclasses may override this method for performance reason.
+     *
+     * @return {@inheritDoc}
+     * @throws TransformException {@inheritDoc}
+     */
+    @Override
+    public Matrix transform(final double[] srcPts, final int srcOff,
+                            final double[] dstPts, final int dstOff,
+                            final boolean derivate) throws TransformException
+    {
+        final double ordinate = srcPts[srcOff];
+        if (dstPts != null) {
+            dstPts[dstOff] = transform(ordinate);
+        }
+        return derivate ? new Matrix1(derivative(ordinate)) : null;
+    }
+
+    /**
+     * Gets the derivative of this transform at a point. The default implementation ensures that
+     * {@code point} is one-dimensional, then delegates to {@link #derivative(double)}.
+     *
+     * @param  point The coordinate point where to evaluate the derivative, or {@code null}.
+     * @return The derivative at the specified point (never {@code null}).
+     * @throws MismatchedDimensionException if {@code point} does not have the expected dimension.
+     * @throws TransformException if the derivative can not be evaluated at the specified point.
+     */
+    @Override
+    public Matrix derivative(final DirectPosition point) throws TransformException {
+        final double ordinate;
+        if (point == null) {
+            ordinate = Double.NaN;
+        } else {
+            ensureDimensionMatches("point", 1, point);
+            ordinate = point.getOrdinate(0);
+        }
+        return new Matrix1(derivative(ordinate));
+    }
+
+    /**
+     * Returns the inverse transform of this object.
+     * The default implementation returns {@code this} if this transform is an identity transform,
+     * or throws an exception otherwise. Subclasses should override this method.
+     */
+    @Override
+    public MathTransform1D inverse() throws NoninvertibleTransformException {
+        return (MathTransform1D) super.inverse();
+    }
+}

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform1D.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform1D.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform2D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform2D.java?rev=1600340&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform2D.java (added)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform2D.java [UTF-8] Wed Jun  4 17:00:13 2014
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.referencing.operation.transform;
+
+import java.util.List;
+import java.awt.Shape;
+import java.awt.geom.Point2D;
+import java.awt.geom.AffineTransform;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.MathTransform2D;
+import org.opengis.referencing.operation.TransformException;
+import org.opengis.referencing.operation.NoninvertibleTransformException;
+
+
+/**
+ * Base class for math transforms that are known to be two-dimensional in all cases.
+ * Two-dimensional math transforms are not required to extend this class,
+ * however doing so may simplify their implementation.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.5 (derived from geotk-2.0)
+ * @version 0.5
+ * @module
+ */
+public abstract class AbstractMathTransform2D extends AbstractMathTransform implements MathTransform2D {
+    /**
+     * Constructs a default math transform.
+     */
+    protected AbstractMathTransform2D() {
+    }
+
+    /**
+     * Returns the dimension of input points, which is always 2.
+     */
+    @Override
+    public final int getSourceDimensions() {
+        return 2;
+    }
+
+    /**
+     * Returns the dimension of output points, which is always 2.
+     */
+    @Override
+    public final int getTargetDimensions() {
+        return 2;
+    }
+
+    /**
+     * Transforms the specified {@code ptSrc} and stores the result in {@code ptDst}.
+     * The default implementation invokes {@link #transform(double[], int, double[], int, boolean)}
+     * using a temporary array of doubles.
+     *
+     * @param  ptSrc The coordinate point to be transformed.
+     * @param  ptDst The coordinate point that stores the result of transforming {@code ptSrc},
+     *               or {@code null} if a new point shall be created.
+     * @return The coordinate point after transforming {@code ptSrc} and storing the result in {@code ptDst},
+     *         or in a new point if {@code ptDst} was null.
+     * @throws TransformException If the point can not be transformed.
+     *
+     * @see MathTransform2D#transform(Point2D, Point2D)
+     */
+    @Override
+    public Point2D transform(final Point2D ptSrc, final Point2D ptDst) throws TransformException {
+        final double[] ord = new double[] {ptSrc.getX(), ptSrc.getY()};
+        transform(ord, 0, ord, 0, false);
+        if (ptDst != null) {
+            ptDst.setLocation(ord[0], ord[1]);
+            return ptDst;
+        } else {
+            return new Point2D.Double(ord[0], ord[1]);
+        }
+    }
+
+    /**
+     * Transform the specified shape. The default implementation computes quadratic curves
+     * using three points for each line segment in the shape. The returned object is often
+     * a {@link Path2D}, but may also be a {@link Line2D} or a {@link QuadCurve2D} if such
+     * simplification is possible.
+     *
+     * @param  shape Shape to transform.
+     * @return Transformed shape, or {@code shape} if this transform is the identity transform.
+     * @throws TransformException if a transform failed.
+     */
+    @Override
+    public Shape createTransformedShape(final Shape shape) throws TransformException {
+        return isIdentity() ? shape : createTransformedShape(this, shape, null, null, false);
+    }
+
+    /**
+     * Transforms a geometric shape. This method always copy transformed coordinates in a new object.
+     * The new object is often a {@link Path2D}, but may also be a {@link Line2D} or a
+     * {@link QuadCurve2D} if such simplification is possible.
+     *
+     * @param  transform     The transform to use.
+     * @param  shape         The geometric shape to transform.
+     * @param  preTransform  An optional affine transform to apply <em>before</em> the
+     *                       transformation using {@code this}, or {@code null} if none.
+     * @param  postTransform An optional affine transform to apply <em>after</em> the transformation
+     *                       using {@code this}, or {@code null} if none.
+     * @param  horizontal    {@code true} for forcing parabolic equation.
+     *
+     * @return The transformed geometric shape.
+     * @throws MismatchedDimensionException if this transform doesn't is not two-dimensional.
+     * @throws TransformException If a transformation failed.
+     */
+    static Shape createTransformedShape(final MathTransform2D transform,
+                                        final Shape           shape,
+                                        final AffineTransform preTransform,
+                                        final AffineTransform postTransform,
+                                        final boolean         horizontal)
+            throws TransformException
+    {
+        // TODO
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns the inverse transform of this object.
+     * The default implementation returns {@code this} if this transform is an identity transform,
+     * or throws an exception otherwise. Subclasses should override this method.
+     */
+    @Override
+    public MathTransform2D inverse() throws NoninvertibleTransformException {
+        return (MathTransform2D) super.inverse();
+    }
+
+    /**
+     * Base class for implementation of inverse math transforms.
+     * This inner class is the inverse of the enclosing {@link AbstractMathTransform2D}.
+     *
+     * {@section Serialization}
+     * Instances of this class are serializable only if the enclosing math transform is also serializable.
+     * Serialized math transforms are not guaranteed to be compatible with future SIS versions.
+     * Serialization, if allowed, should be used only for short term storage or RMI between applications
+     * running the same SIS version.
+     *
+     * @author  Martin Desruisseaux (Geomatys)
+     * @since   0.5 (derived from geotk-3.00)
+     * @version 0.5
+     * @module
+     */
+    protected abstract class Inverse extends AbstractMathTransform.Inverse implements MathTransform2D {
+        /**
+         * Serial number for inter-operability with different versions.
+         */
+        private static final long serialVersionUID = 5751908928042026412L;
+
+        /**
+         * Constructs an inverse math transform.
+         */
+        protected Inverse() {
+            AbstractMathTransform2D.this.super();
+        }
+
+        /**
+         * Returns the enclosing math transform.
+         */
+        @Override
+        public MathTransform2D inverse() {
+            return (MathTransform2D) super.inverse();
+        }
+
+        /**
+         * Same work than {@link AbstractMathTransform2D#beforeFormat(List, int, boolean)}
+         * but with the knowledge that this transform is an inverse transform.
+         */
+        @Override
+        final int beforeFormat(final List<MathTransform> transforms, final int index, final boolean inverse) {
+            return AbstractMathTransform2D.this.beforeFormat(transforms, index, !inverse);
+        }
+    }
+}

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform2D.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform2D.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform.java?rev=1600340&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform.java (added)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform.java [UTF-8] Wed Jun  4 17:00:13 2014
@@ -0,0 +1,903 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.referencing.operation.transform;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.io.Serializable;
+import org.opengis.geometry.DirectPosition;
+import org.opengis.geometry.MismatchedDimensionException;
+import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.referencing.operation.Matrix;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.MathTransform1D;
+import org.opengis.referencing.operation.MathTransform2D;
+import org.opengis.referencing.operation.TransformException;
+import org.opengis.referencing.operation.NoninvertibleTransformException;
+import org.apache.sis.parameter.Parameterized;
+import org.apache.sis.referencing.operation.matrix.MatrixSIS;
+import org.apache.sis.internal.referencing.Semaphores;
+import org.apache.sis.util.Classes;
+import org.apache.sis.util.LenientComparable;
+import org.apache.sis.util.ComparisonMode;
+import org.apache.sis.util.Utilities;
+import org.apache.sis.io.wkt.Convention;
+import org.apache.sis.io.wkt.Formatter;
+import org.apache.sis.util.resources.Errors;
+
+
+/**
+ * Base class for concatenated transforms. Instances can be created by calls to the
+ * {@link #create(MathTransform, MathTransform)} method. When possible, the above-cited
+ * method concatenates {@linkplain ProjectiveTransform projective transforms} before to
+ * fallback on the creation of new {@code ConcatenatedTransform} instances.
+ *
+ * <p>Concatenated transforms are serializable if all their step transforms are serializable.</p>
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @since   0.5 (derived from geotk-1.2)
+ * @version 0.5
+ * @module
+ *
+ * @see org.opengis.referencing.operation.MathTransformFactory#createConcatenatedTransform(MathTransform, MathTransform)
+ */
+class ConcatenatedTransform extends AbstractMathTransform implements Serializable {
+    /**
+     * Serial number for inter-operability with different versions.
+     */
+    private static final long serialVersionUID = 5772066656987558634L;
+
+    /**
+     * The first math transform.
+     */
+    protected final MathTransform transform1;
+
+    /**
+     * The second math transform.
+     */
+    protected final MathTransform transform2;
+
+    /**
+     * The inverse transform. This field will be computed only when needed.
+     * But it is serialized in order to avoid rounding errors if the inverse
+     * transform is serialized instead of the original one.
+     */
+    private ConcatenatedTransform inverse;
+
+    /**
+     * Constructs a concatenated transform. This constructor is for subclasses only.
+     * To create a concatenated transform, use the {@link #create(MathTransform, MathTransform)}
+     * factory method instead.
+     *
+     * @param transform1 The first math transform.
+     * @param transform2 The second math transform.
+     */
+    protected ConcatenatedTransform(final MathTransform transform1,
+                                    final MathTransform transform2)
+    {
+        this.transform1 = transform1;
+        this.transform2 = transform2;
+        if (!isValid()) {
+            throw new IllegalArgumentException(Errors.format(Errors.Keys.CanNotConcatenateTransforms_2,
+                    getName(transform1), getName(transform2)));
+        }
+    }
+
+    /**
+     * Tests if one math transform is the inverse of the other, or approximatively the inverse.
+     * Used for {@link #createOptimized(MathTransform, MathTransform)} implementation.
+     */
+    private static boolean areInverse(final MathTransform tr1, MathTransform tr2) {
+        try {
+            tr2 = tr2.inverse();
+        } catch (NoninvertibleTransformException e) {
+            return false;
+        }
+        if (tr1 == tr2) {
+            return true;
+        }
+        if (tr1 instanceof LenientComparable) {
+            return ((LenientComparable) tr1).equals(tr2, ComparisonMode.APPROXIMATIVE);
+        }
+        if (tr2 instanceof LenientComparable) {
+            return ((LenientComparable) tr2).equals(tr1, ComparisonMode.APPROXIMATIVE);
+        }
+        return tr1.equals(tr2);
+    }
+
+    /**
+     * Concatenates the two given transforms.
+     * If the concatenation result works with two-dimensional input and output points,
+     * then the returned transform will implement {@link MathTransform2D}.
+     * Likewise if the concatenation result works with one-dimensional input and output points,
+     * then the returned transform will implement {@link MathTransform1D}.
+     *
+     * <div class="note"><b>Implementation note:</b>
+     * {@code ConcatenatedTransform} implementations are available in two versions: direct and non-direct.
+     * The "non-direct" versions use an intermediate buffer when performing transformations; they are slower
+     * and consume more memory. They are used only as a fallback when a "direct" version can not be created.</div>
+     *
+     * @param tr1 The first math transform.
+     * @param tr2 The second math transform.
+     * @return    The concatenated transform.
+     *
+     * @see MathTransforms#concatenate(MathTransform, MathTransform)
+     */
+    public static MathTransform create(MathTransform tr1, MathTransform tr2) throws MismatchedDimensionException {
+        final int dim1 = tr1.getTargetDimensions();
+        final int dim2 = tr2.getSourceDimensions();
+        if (dim1 != dim2) {
+            throw new MismatchedDimensionException(Errors.format(Errors.Keys.CanNotConcatenateTransforms_2, getName(tr1),
+                    getName(tr2)) + ' ' + Errors.format(Errors.Keys.MismatchedDimension_2, dim1, dim2));
+        }
+        MathTransform mt = createOptimized(tr1, tr2);
+        if (mt != null) {
+            return mt;
+        }
+        /*
+         * If at least one math transform is an instance of ConcatenatedTransform and assuming
+         * that MathTransforms are associatives, tries the following arrangements and select
+         * the one with the fewest amount of steps:
+         *
+         *   Assuming :  tr1 = (A * B)
+         *               tr2 = (C * D)
+         *
+         *   Current  :  (A * B) * (C * D)     Will be the selected one if nothing better.
+         *   Try k=0  :  A * (B * (C * D))     Implies A * ((B * C) * D) through recursivity.
+         *   Try k=1  :  ((A * B) * C) * D     Implies (A * (B * C)) * D through recursivity.
+         *   Try k=2  :                        Tried only if try k=1 changed something.
+         *
+         * TODO: The same combination may be computed more than once (e.g. (B * C) above).
+         *       Should not be a big deal if there is not two many steps. In the even where
+         *       it would appears a performance issue, we could maintain a Map of combinations
+         *       already computed. The map would be local to a "create" method execution.
+         */
+        int stepCount = getStepCount(tr1) + getStepCount(tr2);
+        boolean tryAgain = true; // Really 'true' because we want at least 2 iterations.
+        for (int k=0; ; k++) {
+            MathTransform c1 = tr1;
+            MathTransform c2 = tr2;
+            final boolean first = (k & 1) == 0;
+            MathTransform candidate = first ? c1 : c2;
+            while (candidate instanceof ConcatenatedTransform) {
+                final ConcatenatedTransform ctr = (ConcatenatedTransform) candidate;
+                if (first) {
+                    c1 = candidate = ctr.transform1;
+                    c2 = create(ctr.transform2, c2);
+                } else {
+                    c1 = create(c1, ctr.transform1);
+                    c2 = candidate = ctr.transform2;
+                }
+                final int c = getStepCount(c1) + getStepCount(c2);
+                if (c < stepCount) {
+                    tr1 = c1;
+                    tr2 = c2;
+                    stepCount = c;
+                    tryAgain = true;
+                }
+            }
+            if (!tryAgain) break;
+            tryAgain = false;
+        }
+        /*
+         * Tries again the check for optimized cases (identity, etc.), because a
+         * transform may have been simplified to identity as a result of the above.
+         */
+        mt = createOptimized(tr1, tr2);
+        if (mt != null) {
+            return mt;
+        }
+        /*
+         * Can not avoid the creation of a ConcatenatedTransform object.
+         * Check for the type to create (1D, 2D, general case...)
+         */
+        return createConcatenatedTransform(tr1, tr2);
+    }
+
+    /**
+     * Tries to returns an optimized concatenation, for example by merging two affine transforms
+     * into a single one. If no optimized cases has been found, returns {@code null}. In the later
+     * case, the caller will need to create a more heavy {@link ConcatenatedTransform} instance.
+     */
+    private static MathTransform createOptimized(final MathTransform tr1, final MathTransform tr2) {
+        /*
+         * Trivial - but actually essential!! - check for the identity cases.
+         */
+        if (tr1.isIdentity()) return tr2;
+        if (tr2.isIdentity()) return tr1;
+        /*
+         * If both transforms use matrix, then we can create
+         * a single transform using the concatenated matrix.
+         */
+        final Matrix matrix1 = MathTransforms.getMatrix(tr1);
+        if (matrix1 != null) {
+            final Matrix matrix2 = MathTransforms.getMatrix(tr2);
+            if (matrix2 != null) {
+                final Matrix matrix = MatrixSIS.castOrCopy(matrix2).multiply(matrix1);
+                /*
+                 * NOTE: It is quite tempting to "fix rounding errors" in the matrix before to create the transform.
+                 * But this is often wrong for datum shift transformations (Molodensky and the like) since the datum
+                 * shifts are very small. The shift may be the order of magnitude of the tolerance threshold. Intead,
+                 * Apache SIS performs matrix operations using double-double arithmetic in the hope to get exact
+                 * results at the 'double' accuracy, which avoid the need for a tolerance threshold.
+                 */
+                return ProjectiveTransform.create(matrix);
+            }
+            /*
+             * If the second transform is a passthrough transform and all passthrough ordinates
+             * are unchanged by the matrix, we can move the matrix inside the passthrough transform.
+             */
+            if (tr2 instanceof PassThroughTransform) {
+                final PassThroughTransform candidate = (PassThroughTransform) tr2;
+                final Matrix sub = candidate.toSubMatrix(matrix1);
+                if (sub != null) {
+                    return PassThroughTransform.create(candidate.firstAffectedOrdinate,
+                            create(ProjectiveTransform.create(sub), candidate.subTransform),
+                            candidate.numTrailingOrdinates);
+                }
+            }
+        }
+        /*
+         * If one transform is the inverse of the
+         * other, returns the identity transform.
+         */
+        if (areInverse(tr1, tr2) || areInverse(tr2, tr1)) {
+            assert tr1.getSourceDimensions() == tr2.getTargetDimensions();
+            assert tr1.getTargetDimensions() == tr2.getSourceDimensions();
+            return ProjectiveTransform.identity(tr1.getSourceDimensions());
+        }
+        /*
+         * Gives a chance to AbstractMathTransform to returns an optimized object.
+         * The main use case is Logarithmic vs Exponential transforms.
+         */
+        if (tr1 instanceof AbstractMathTransform) {
+            final MathTransform optimized = ((AbstractMathTransform) tr1).concatenate(tr2, false);
+            if (optimized != null) {
+                return optimized;
+            }
+        }
+        if (tr2 instanceof AbstractMathTransform) {
+            final MathTransform optimized = ((AbstractMathTransform) tr2).concatenate(tr1, true);
+            if (optimized != null) {
+                return optimized;
+            }
+        }
+        // No optimized case found.
+        return null;
+    }
+
+    /**
+     * Continue the construction started by the {@link #create(MathTransform, MathTransform)} method.
+     * The construction step is available separately for testing purpose (in a JUnit test), and for
+     * {@link #inverse()} implementation.
+     */
+    static ConcatenatedTransform createConcatenatedTransform(
+            final MathTransform tr1, final MathTransform tr2)
+    {
+        final int dimSource = tr1.getSourceDimensions();
+        final int dimTarget = tr2.getTargetDimensions();
+        /*
+         * Checks if the result need to be a MathTransform1D.
+         */
+        if (dimSource == 1 && dimTarget == 1) {
+            if (tr1 instanceof MathTransform1D && tr2 instanceof MathTransform1D) {
+                return new ConcatenatedTransformDirect1D((MathTransform1D) tr1,
+                                                         (MathTransform1D) tr2);
+            } else {
+                return new ConcatenatedTransform1D(tr1, tr2);
+            }
+        } else
+        /*
+         * Checks if the result need to be a MathTransform2D.
+         */
+        if (dimSource == 2 && dimTarget == 2) {
+            if (tr1 instanceof MathTransform2D && tr2 instanceof MathTransform2D) {
+                return new ConcatenatedTransformDirect2D((MathTransform2D) tr1,
+                                                         (MathTransform2D) tr2);
+            } else {
+                return new ConcatenatedTransform2D(tr1, tr2);
+            }
+        } else if (dimSource == tr1.getTargetDimensions() && tr2.getSourceDimensions() == dimTarget) {
+            return new ConcatenatedTransformDirect(tr1, tr2);
+        } else {
+            return new ConcatenatedTransform(tr1, tr2);
+        }
+    }
+
+    /**
+     * Returns a name for the specified math transform.
+     */
+    private static String getName(final MathTransform transform) {
+        if (transform instanceof AbstractMathTransform) {
+            ParameterValueGroup params = ((AbstractMathTransform) transform).getParameterValues();
+            if (params != null) {
+                String name = params.getDescriptor().getName().getCode();
+                if (name != null && !(name = name.trim()).isEmpty()) {
+                    return name;
+                }
+            }
+        }
+        return Classes.getShortClassName(transform);
+    }
+
+    /**
+     * Checks if transforms are compatibles. The default
+     * implementation check if transfer dimension match.
+     */
+    boolean isValid() {
+        return transform1.getTargetDimensions() == transform2.getSourceDimensions();
+    }
+
+    /**
+     * Gets the dimension of input points.
+     *
+     * @return {@inheritDoc}
+     */
+    @Override
+    public final int getSourceDimensions() {
+        return transform1.getSourceDimensions();
+    }
+
+    /**
+     * Gets the dimension of output points.
+     *
+     * @return {@inheritDoc}
+     */
+    @Override
+    public final int getTargetDimensions() {
+        return transform2.getTargetDimensions();
+    }
+
+    /**
+     * Returns the number of single {@link MathTransform} steps.
+     * Nested concatenated transforms (if any) are explored recursively in order to
+     * get the count of single (non-nested) transforms.
+     *
+     * @return The number of single transform steps.
+     */
+    private int getStepCount() {
+        return getStepCount(transform1) + getStepCount(transform2);
+    }
+
+    /**
+     * Returns the number of single {@linkplain MathTransform math transform} steps performed
+     * by the given transform. As a special case, we returns 0 for the identity transform since
+     * it should be omitted from the final chain.
+     */
+    private static int getStepCount(final MathTransform transform) {
+        if (transform.isIdentity()) {
+            return 0;
+        }
+        if (!(transform instanceof ConcatenatedTransform)) {
+            return 1;
+        }
+        return ((ConcatenatedTransform) transform).getStepCount();
+    }
+
+    /**
+     * Returns all concatenated transforms. The returned list contains only <cite>single</cite>
+     * transforms, i.e. all nested concatenated transforms (if any) have been expanded.
+     *
+     * @return All single math transforms performed by this concatenated transform.
+     */
+    public final List<MathTransform> getSteps() {
+        final List<MathTransform> transforms = new ArrayList<>(5);
+        getSteps(transforms);
+        return transforms;
+    }
+
+    /**
+     * Returns all concatenated transforms, modified with the pre- and post-processing required for WKT formating.
+     * More specifically, if there is any Apache SIS implementation of Map Projection in the chain, then the
+     * (<var>normalize</var>, <var>unitary projection</var>, <var>denormalize</var>) tuples are replaced by single
+     * (<var>projection</var>) elements, which does not need to be instances of {@link MathTransform}.
+     */
+    private List<MathTransform> getPseudoSteps() {
+        final List<MathTransform> transforms = new ArrayList<>();
+        getSteps(transforms);
+        /*
+         * Pre-process the transforms before to format. Some steps may be* merged, or new
+         * steps may be created. Do not move size() out of the loop, because it may change.
+         */
+        for (int i=0; i<transforms.size(); i++) {
+            final Object step = transforms.get(i);
+            if (step instanceof AbstractMathTransform) {
+                i = ((AbstractMathTransform) step).beforeFormat(transforms, i, false);
+            }
+        }
+        return transforms;
+    }
+
+    /**
+     * Adds all concatenated transforms in the given list.
+     *
+     * @param transforms The list where to add concatenated transforms.
+     */
+    private void getSteps(final List<MathTransform> transforms) {
+        if (transform1 instanceof ConcatenatedTransform) {
+            ((ConcatenatedTransform) transform1).getSteps(transforms);
+        } else {
+            transforms.add(transform1);
+        }
+        if (transform2 instanceof ConcatenatedTransform) {
+            ((ConcatenatedTransform) transform2).getSteps(transforms);
+        } else {
+            transforms.add(transform2);
+        }
+    }
+
+    /**
+     * If there is exactly one transform step which is {@linkplain Parameterized parameterized},
+     * returns that transform step. Otherwise returns {@code null}.
+     *
+     * <p>This method normally requires that there is exactly one transform step remaining after we
+     * processed map projections in the special way described in {@link #getParameterValues()},
+     * because if they were more than one remaining steps, the returned parameters would not be
+     * sufficient for rebuilding the full concatenated transform. Returning parameters when there
+     * is more than one remaining step, even if all other transform steps are not parameterizable,
+     * would be a contract violation.</p>
+     *
+     * <p>However in the special case where we are formatting {@code PROJCS} element, the above rule
+     * is slightly relaxed. More specifically we ignore affine transforms in order to accept axis
+     * swapping or unit conversions. This special case is internal to SIS implementation of WKT
+     * formatter and should be unknown to users.</p>
+     *
+     * <p>See {@link org.apache.sis.referencing.operation.DefaultSingleOperation#getParameterValues()}
+     * for the code where the above-cited special case is applied.</p>
+     *
+     * @return The parameterizable transform step, or {@code null} if none.
+     *
+     * @see org.apache.sis.referencing.operation.DefaultSingleOperation#simplify(MathTransform)
+     */
+    private Parameterized getParameterised() {
+        Parameterized param = null;
+        final List<MathTransform> transforms = getPseudoSteps();
+        if (transforms.size() == 1 || Semaphores.query(Semaphores.PROJCS)) {
+            for (final Object candidate : transforms) {
+                if (!(candidate instanceof Parameterized)) {
+                    /*
+                     * If a step does not implement the Parameterized interface, we conservatively
+                     * handle it as if it was a non-linear step: we should return its parameters
+                     * (which are null), or return null if there is more non-linear steps.
+                     */
+                    return null;
+                }
+                if (param != null) {
+                    /*
+                     * We found more than one Parameterized step. If both steps are non-linear,
+                     * we fail (return null) because we don't know which one to choose. If both
+                     * steps are linear, we fail for the same reason   (actually the later case
+                     * should never occur, since consecutive linear transforms should have been
+                     * concatenated in a single affine transform. But we check as a safety). If
+                     * the previous step was linear and the current candidate is non-linear, we
+                     * retain the current candidate. Otherwise we discart it.
+                     */
+                    final boolean isLinear = (candidate instanceof LinearTransform);
+                    if ((param instanceof LinearTransform) == isLinear) {
+                        return null;
+                    }
+                    if (isLinear) {
+                        continue;
+                    }
+                }
+                param = (Parameterized) candidate;
+            }
+        }
+        return param;
+    }
+
+    /**
+     * Returns the parameter descriptor, or {@code null} if none.
+     * This method performs the same special check than {@link #getParameterValues()}.
+     */
+    @Override
+    public ParameterDescriptorGroup getParameterDescriptors() {
+        final Parameterized param = getParameterised();
+        return (param != null) ? param.getParameterDescriptors() : null;
+    }
+
+    /**
+     * Returns the parameter values, or {@code null} if none. Concatenated transforms usually have
+     * no parameters; instead the parameters of the individual components ({@link #transform1} and
+     * {@link #transform2}) need to be inspected. However map projections in SIS are implemented as
+     * (<cite>normalize</cite> – <cite>non-linear kernel</cite> – <cite>denormalize</cite>) tuples.
+     * This method detects such concatenation chains in order to return the parameter values that
+     * describe the projection as a whole.
+     */
+    @Override
+    public ParameterValueGroup getParameterValues() {
+        final Parameterized param = getParameterised();
+        return (param != null) ? param.getParameterValues() : null;
+    }
+
+    /**
+     * Transforms the specified {@code ptSrc} and stores the result in {@code ptDst}.
+     *
+     * @throws TransformException If {@link #transform1} or {@link #transform2} failed.
+     */
+    @Override
+    public DirectPosition transform(final DirectPosition ptSrc, final DirectPosition ptDst)
+            throws TransformException
+    {
+        assert isValid();
+        //  Note: If we know that the transfer dimension is the same than source
+        //        and target dimension, then we don't need to use an intermediate
+        //        point. This optimization is done in ConcatenatedTransformDirect.
+        return transform2.transform(transform1.transform(ptSrc, null), ptDst);
+    }
+
+    /**
+     * Transforms a single coordinate in a list of ordinal values,
+     * and optionally returns the derivative at that location.
+     *
+     * @throws TransformException If {@link #transform1} or {@link #transform2} failed.
+     */
+    @Override
+    public Matrix transform(final double[] srcPts, final int srcOff,
+                            final double[] dstPts, final int dstOff,
+                            final boolean derivate) throws TransformException
+    {
+        assert isValid();
+        final int bufferDim = transform2.getSourceDimensions();
+        final int targetDim = transform2.getTargetDimensions();
+        final double[] buffer;
+        final int offset;
+        if (bufferDim > targetDim) {
+            buffer = new double[bufferDim];
+            offset = 0;
+        } else {
+            buffer = dstPts;
+            offset = dstOff;
+        }
+        if (derivate) {
+            final Matrix matrix1 = MathTransforms.derivativeAndTransform(transform1, srcPts, srcOff, buffer, offset);
+            final Matrix matrix2 = MathTransforms.derivativeAndTransform(transform2, buffer, offset, dstPts, dstOff);
+            return MatrixSIS.castOrCopy(matrix2).multiply(matrix1);
+        } else {
+            transform1.transform(srcPts, srcOff, buffer, offset, 1);
+            transform2.transform(buffer, offset, dstPts, dstOff, 1);
+            return null;
+        }
+    }
+
+    /**
+     * Transforms many coordinates in a list of ordinal values. The source points are first
+     * transformed by {@link #transform1}, then the intermediate points are transformed by
+     * {@link #transform2}. The transformations are performed without intermediate buffer
+     * if it can be avoided.
+     *
+     * @throws TransformException If {@link #transform1} or {@link #transform2} failed.
+     */
+    @Override
+    public void transform(final double[] srcPts, int srcOff,
+                          final double[] dstPts, int dstOff, int numPts)
+            throws TransformException
+    {
+        assert isValid();
+        int bufferDim = transform2.getSourceDimensions();
+        int targetDim = transform2.getTargetDimensions();
+        /*
+         * If the transfer dimension is not greater than the target dimension, then we
+         * don't need to use an intermediate buffer. Note that this optimization is done
+         * unconditionally in ConcatenatedTransformDirect.
+         */
+        if (bufferDim <= targetDim) {
+            transform1.transform(srcPts, srcOff, dstPts, dstOff, numPts);
+            transform2.transform(dstPts, dstOff, dstPts, dstOff, numPts);
+            return;
+        }
+        if (numPts <= 0) {
+            return;
+        }
+        /*
+         * Creates a temporary array for the intermediate result. The array may be smaller than
+         * the length necessary for containing every coordinates. In such case the concatenated
+         * transform will need to be applied piecewise with special care in case of overlapping
+         * arrays.
+         */
+        boolean descending = false;
+        int sourceDim = transform1.getSourceDimensions();
+        int numBuf = numPts;
+        int length = numBuf * bufferDim;
+        if (length > MAXIMUM_BUFFER_SIZE) {
+            numBuf = Math.max(1, MAXIMUM_BUFFER_SIZE / bufferDim);
+            if (srcPts == dstPts) {
+                // Since we are using a buffer, the whole buffer is like a single coordinate point.
+                switch (IterationStrategy.suggest(srcOff, numBuf*sourceDim, dstOff, numBuf*targetDim, numPts)) {
+                    default: {
+                        // Needs to copy the whole data.
+                        numBuf = numPts;
+                        break;
+                    }
+                    case ASCENDING: {
+                        // No special care needed.
+                        break;
+                    }
+                    case DESCENDING: {
+                        // Traversing in reverse order is sufficient.
+                        final int shift = numPts - numBuf;
+                        srcOff += shift*sourceDim; sourceDim = -sourceDim;
+                        dstOff += shift*targetDim; targetDim = -targetDim;
+                        descending = true;
+                        break;
+                    }
+                }
+            }
+            length = numBuf * bufferDim;
+        }
+        final double[] buf = new double[length];
+        do {
+            if (!descending && numBuf > numPts) {
+                // Must be done before transforms if we are iterating in ascending order.
+                numBuf = numPts;
+            }
+            transform1.transform(srcPts, srcOff, buf, 0, numBuf);
+            transform2.transform(buf, 0, dstPts, dstOff, numBuf);
+            numPts -= numBuf;
+            if (descending && numBuf > numPts) {
+                // Must be done after transforms if we are iterating in descending order.
+                numBuf = numPts;
+            }
+            srcOff += numBuf * sourceDim;
+            dstOff += numBuf * targetDim;
+        } while (numPts != 0);
+    }
+
+    /**
+     * Transforms many coordinates in a list of ordinal values. The source points are first
+     * transformed by {@link #transform1}, then the intermediate points are transformed by
+     * {@link #transform2}. An intermediate buffer of type {@code double[]} for intermediate
+     * results is used for reducing rounding errors.
+     *
+     * @throws TransformException If {@link #transform1} or {@link #transform2} failed.
+     */
+    @Override
+    public void transform(final float[] srcPts, int srcOff,
+                          final float[] dstPts, int dstOff, int numPts)
+            throws TransformException
+    {
+        assert isValid();
+        if (numPts <= 0) {
+            return;
+        }
+        boolean descending = false;
+        int sourceDim = transform1.getSourceDimensions();
+        int bufferDim = transform1.getTargetDimensions();
+        int targetDim = transform2.getTargetDimensions();
+        int dimension = Math.max(targetDim, bufferDim);
+        int numBuf = numPts;
+        int length = numBuf * dimension;
+        if (length > MAXIMUM_BUFFER_SIZE) {
+            numBuf = Math.max(1, MAXIMUM_BUFFER_SIZE / dimension);
+            if (srcPts == dstPts) {
+                switch (IterationStrategy.suggest(srcOff, numBuf*sourceDim, dstOff, numBuf*targetDim, numPts)) {
+                    default: {
+                        numBuf = numPts;
+                        break;
+                    }
+                    case ASCENDING: {
+                        break;
+                    }
+                    case DESCENDING: {
+                        final int shift = numPts - numBuf;
+                        srcOff += shift*sourceDim; sourceDim = -sourceDim;
+                        dstOff += shift*targetDim; targetDim = -targetDim;
+                        descending = true;
+                        break;
+                    }
+                }
+            }
+            length = numBuf * dimension;
+        }
+        final double[] buf = new double[length];
+        do {
+            if (!descending && numBuf > numPts) {
+                numBuf = numPts;
+            }
+            transform1.transform(srcPts, srcOff, buf, 0, numBuf);
+            transform2.transform(buf, 0, dstPts, dstOff, numBuf);
+            numPts -= numBuf;
+            if (descending && numBuf > numPts) {
+                numBuf = numPts;
+            }
+            srcOff += numBuf * sourceDim;
+            dstOff += numBuf * targetDim;
+        } while (numPts != 0);
+    }
+
+    /**
+     * Transforms many coordinates in a list of ordinal values. The source points are first
+     * transformed by {@link #transform1}, then the intermediate points are transformed by
+     * {@link #transform2}. An intermediate buffer of type {@code double[]} for intermediate
+     * results is used for reducing rounding errors.
+     *
+     * @throws TransformException If {@link #transform1} or {@link #transform2} failed.
+     */
+    @Override
+    public void transform(final double[] srcPts, int srcOff,
+                          final float [] dstPts, int dstOff, int numPts)
+            throws TransformException
+    {
+        // Same code than transform(float[], ..., float[], ...) but the method calls
+        // are actually different because of overloading of the "transform" methods.
+        assert isValid();
+        if (numPts <= 0) {
+            return;
+        }
+        final int sourceDim = transform1.getSourceDimensions();
+        final int bufferDim = transform1.getTargetDimensions();
+        final int targetDim = transform2.getTargetDimensions();
+        final int dimension = Math.max(targetDim, bufferDim);
+        int numBuf = numPts;
+        int length = numBuf * dimension;
+        if (length > MAXIMUM_BUFFER_SIZE) {
+            numBuf = Math.max(1, MAXIMUM_BUFFER_SIZE / dimension);
+            length = numBuf * dimension;
+        }
+        final double[] buf = new double[length];
+        do {
+            if (numBuf > numPts) {
+                numBuf = numPts;
+            }
+            transform1.transform(srcPts, srcOff, buf, 0, numBuf);
+            transform2.transform(buf, 0, dstPts, dstOff, numBuf);
+            srcOff += numBuf * sourceDim;
+            dstOff += numBuf * targetDim;
+            numPts -= numBuf;
+        } while (numPts != 0);
+    }
+
+    /**
+     * Transforms many coordinates in a list of ordinal values. The source points are first
+     * transformed by {@link #transform1}, then the intermediate points are transformed by
+     * {@link #transform2}. The transformations are performed without intermediate buffer
+     * if it can be avoided.
+     *
+     * @throws TransformException If {@link #transform1} or {@link #transform2} failed.
+     */
+    @Override
+    public void transform(final float [] srcPts, int srcOff,
+                          final double[] dstPts, int dstOff, int numPts)
+            throws TransformException
+    {
+        // Same code than transform(double[], ..., double[], ...) but the method calls
+        // are actually different because of overloading of the "transform" methods.
+        assert isValid();
+        final int bufferDim = transform2.getSourceDimensions();
+        final int targetDim = transform2.getTargetDimensions();
+        if (bufferDim <= targetDim) {
+            transform1.transform(srcPts, srcOff, dstPts, dstOff, numPts);
+            transform2.transform(dstPts, dstOff, dstPts, dstOff, numPts);
+            return;
+        }
+        if (numPts <= 0) {
+            return;
+        }
+        int numBuf = numPts;
+        int length = numBuf * bufferDim;
+        if (length > MAXIMUM_BUFFER_SIZE) {
+            numBuf = Math.max(1, MAXIMUM_BUFFER_SIZE / bufferDim);
+            length = numBuf * bufferDim;
+        }
+        final double[] buf = new double[length];
+        final int sourceDim = getSourceDimensions();
+        do {
+            if (numBuf > numPts) {
+                numBuf = numPts;
+            }
+            transform1.transform(srcPts, srcOff, buf, 0, numBuf);
+            transform2.transform(buf, 0, dstPts, dstOff, numBuf);
+            srcOff += numBuf * sourceDim;
+            dstOff += numBuf * targetDim;
+            numPts -= numBuf;
+        } while (numPts != 0);
+    }
+
+    /**
+     * Creates the inverse transform of this object.
+     */
+    @Override
+    public synchronized MathTransform inverse() throws NoninvertibleTransformException {
+        assert isValid();
+        if (inverse == null) {
+            inverse = createConcatenatedTransform(transform2.inverse(), transform1.inverse());
+            inverse.inverse = this;
+        }
+        return inverse;
+    }
+
+    /**
+     * Gets the derivative of this transform at a point.
+     *
+     * @param  point The coordinate point where to evaluate the derivative.
+     * @return The derivative at the specified point (never {@code null}).
+     * @throws TransformException if the derivative can't be evaluated at the specified point.
+     */
+    @Override
+    public Matrix derivative(final DirectPosition point) throws TransformException {
+        final Matrix matrix1 = transform1.derivative(point);
+        final Matrix matrix2 = transform2.derivative(transform1.transform(point, null));
+        return MatrixSIS.castOrCopy(matrix2).multiply(matrix1);
+    }
+
+    /**
+     * Tests whether this transform does not move any points.
+     * Default implementation check if the two transforms are identity.
+     */
+    @Override
+    public final boolean isIdentity() {
+        return transform1.isIdentity() && transform2.isIdentity();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected int computeHashCode() {
+        return super.computeHashCode() ^ getSteps().hashCode();
+    }
+
+    /**
+     * Compares the specified object with this math transform for equality.
+     */
+    @Override
+    public final boolean equals(final Object object, final ComparisonMode mode) {
+        if (object == this) { // Slight optimization
+            return true;
+        }
+        /*
+         * Do not invoke super.equals(...) because we don't want to compare descriptors.
+         * Their computation may be expensive and this information is derived from the
+         * transform steps anyway.
+         */
+        if (object instanceof ConcatenatedTransform) {
+            final ConcatenatedTransform that = (ConcatenatedTransform) object;
+            return Utilities.deepEquals(this.getSteps(), that.getSteps(), mode);
+        }
+        return false;
+    }
+
+    /**
+     * Formats the inner part of a <cite>Well Known Text</cite> version 1 (WKT 1) element.
+     *
+     * @param  formatter The formatter to use.
+     * @return The WKT element name, which is {@code "Concat_MT"}.
+     */
+    @Override
+    public String formatTo(final Formatter formatter) {
+        final List<MathTransform> transforms;
+        if (formatter.getConvention() == Convention.INTERNAL) {
+            transforms = getSteps();
+        } else {
+            transforms = getPseudoSteps();
+        }
+        /*
+         * Now formats the list that we got. Note that as a result of the above
+         * pre-processing the list may have been reduced to a singleton, in which
+         * case this is no longer a CONCAT_MT.
+         */
+        if (transforms.size() == 1) {
+            return formatter.delegateTo(transforms.get(0));
+        }
+        for (final MathTransform step : transforms) {
+            formatter.newLine();
+            formatter.append(step);
+        }
+        return "Concat_MT";
+    }
+}

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform1D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform1D.java?rev=1600340&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform1D.java (added)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform1D.java [UTF-8] Wed Jun  4 17:00:13 2014
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.referencing.operation.transform;
+
+import org.opengis.referencing.operation.Matrix;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.MathTransform1D;
+import org.opengis.referencing.operation.TransformException;
+import org.opengis.referencing.operation.NoninvertibleTransformException;
+import org.apache.sis.geometry.DirectPosition1D;
+
+
+/**
+ * Concatenated transform in which the resulting transform is one-dimensional.
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @since   0.5 (derived from geotk-2.0)
+ * @version 0.5
+ * @module
+ */
+final class ConcatenatedTransform1D extends ConcatenatedTransform implements MathTransform1D {
+    /**
+     * Serial number for inter-operability with different versions.
+     */
+    private static final long serialVersionUID = 8150427971141078395L;
+
+    /**
+     * Constructs a concatenated transform.
+     */
+    ConcatenatedTransform1D(final MathTransform transform1,
+                            final MathTransform transform2)
+    {
+        super(transform1, transform2);
+    }
+
+    /**
+     * Checks if transforms are compatibles with this implementation.
+     */
+    @Override
+    boolean isValid() {
+        return super.isValid() && getSourceDimensions() == 1 && getTargetDimensions() == 1;
+    }
+
+    /**
+     * Transforms the specified value.
+     */
+    @Override
+    public double transform(final double value) throws TransformException {
+        final double[] values = new double[] {value};
+        final double[] buffer = new double[] {transform1.getTargetDimensions()};
+        transform1.transform(values, 0, buffer, 0, 1);
+        transform2.transform(buffer, 0, values, 0, 1);
+        return values[0];
+    }
+
+    /**
+     * Gets the derivative of this function at a value.
+     */
+    @Override
+    public double derivative(final double value) throws TransformException {
+        final DirectPosition1D p = new DirectPosition1D(value);
+        final Matrix m = derivative(p);
+        assert (m.getNumRow() == 1) && (m.getNumCol() == 1);
+        return m.getElement(0,0);
+    }
+
+    /**
+     * Creates the inverse transform of this object.
+     */
+    @Override
+    public MathTransform1D inverse() throws NoninvertibleTransformException {
+        return (MathTransform1D) super.inverse();
+    }
+}

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform1D.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform1D.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform2D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform2D.java?rev=1600340&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform2D.java (added)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform2D.java [UTF-8] Wed Jun  4 17:00:13 2014
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.referencing.operation.transform;
+
+import java.awt.Shape;
+import java.awt.geom.Point2D;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.MathTransform2D;
+import org.opengis.referencing.operation.Matrix;
+import org.opengis.referencing.operation.NoninvertibleTransformException;
+import org.opengis.referencing.operation.TransformException;
+import org.apache.sis.geometry.GeneralDirectPosition;
+
+
+/**
+ * Concatenated transform in which the resulting transform is two-dimensional.
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @since   0.5 (derived from geotk-1.2)
+ * @version 0.5
+ * @module
+ */
+final class ConcatenatedTransform2D extends ConcatenatedTransform implements MathTransform2D {
+    /**
+     * Serial number for inter-operability with different versions.
+     */
+    private static final long serialVersionUID = -7307709788564866500L;
+
+    /**
+     * Constructs a concatenated transform.
+     */
+    ConcatenatedTransform2D(final MathTransform transform1,
+                            final MathTransform transform2)
+    {
+        super(transform1, transform2);
+    }
+
+    /**
+     * Checks if transforms are compatibles with this implementation.
+     */
+    @Override
+    boolean isValid() {
+        return super.isValid() && (getSourceDimensions() == 2) && (getTargetDimensions() == 2);
+    }
+
+    /**
+     * Transforms the specified {@code ptSrc} and stores the result in {@code ptDst}.
+     * This method is a copy of {@link AbstractMathTransform2D#transform(Point2D, Point2D)}
+     */
+    @Override
+    public Point2D transform(final Point2D ptSrc, final Point2D ptDst) throws TransformException {
+        final double[] ord = new double[] {ptSrc.getX(), ptSrc.getY()};
+        transform(ord, 0, ord, 0, false);
+        if (ptDst != null) {
+            ptDst.setLocation(ord[0], ord[1]);
+            return ptDst;
+        } else {
+            return new Point2D.Double(ord[0], ord[1]);
+        }
+    }
+
+    /**
+     * Transform the specified shape.
+     *
+     * @param  shape Shape to transform.
+     * @return Transformed shape.
+     * @throws TransformException if a transform failed.
+     */
+    @Override
+    public Shape createTransformedShape(final Shape shape) throws TransformException {
+        return AbstractMathTransform2D.createTransformedShape(this, shape, null, null, false);
+    }
+
+    /**
+     * Gets the derivative of this transform at a point. This method delegates to the
+     * {@link #derivative(DirectPosition)} method because the transformation steps
+     * {@link #transform1} and {@link #transform2} may not be instances of {@link MathTransform2D}.
+     *
+     * @param  point The coordinate point where to evaluate the derivative.
+     * @return The derivative at the specified point as a 2&times;2 matrix.
+     * @throws TransformException if the derivative can't be evaluated at the specified point.
+     */
+    @Override
+    public Matrix derivative(final Point2D point) throws TransformException {
+        return derivative(new GeneralDirectPosition(point.getX(), point.getY()));
+    }
+
+    /**
+     * Creates the inverse transform of this object.
+     */
+    @Override
+    public MathTransform2D inverse() throws NoninvertibleTransformException {
+        return (MathTransform2D) super.inverse();
+    }
+}

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform2D.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform2D.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransformDirect.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransformDirect.java?rev=1600340&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransformDirect.java (added)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransformDirect.java [UTF-8] Wed Jun  4 17:00:13 2014
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.referencing.operation.transform;
+
+import org.opengis.geometry.DirectPosition;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.TransformException;
+
+
+/**
+ * Concatenated transform where the transfer dimension is the same than source and target dimension.
+ * This fact allows some optimizations, the most important one being the possibility to avoid the use
+ * of an intermediate buffer in some case.
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @since   0.5 (derived from geotk-1.2)
+ * @version 0.5
+ * @module
+ */
+class ConcatenatedTransformDirect extends ConcatenatedTransform {
+    /**
+     * Serial number for inter-operability with different versions.
+     */
+    private static final long serialVersionUID = -3568975979013908920L;
+
+    /**
+     * Constructs a concatenated transform.
+     */
+    public ConcatenatedTransformDirect(final MathTransform transform1,
+                                       final MathTransform transform2)
+    {
+        super(transform1, transform2);
+    }
+
+    /**
+     * Checks if transforms are compatibles with this implementation.
+     */
+    @Override
+    boolean isValid() {
+        return super.isValid() &&
+               transform1.getSourceDimensions() == transform1.getTargetDimensions() &&
+               transform2.getSourceDimensions() == transform2.getTargetDimensions();
+    }
+
+    /**
+     * Transforms the specified {@code ptSrc} and stores the result in {@code ptDst}.
+     */
+    @Override
+    public DirectPosition transform(final DirectPosition ptSrc, DirectPosition ptDst)
+            throws TransformException
+    {
+        assert isValid();
+        ptDst = transform1.transform(ptSrc, ptDst);
+        return  transform2.transform(ptDst, ptDst);
+    }
+
+    /**
+     * Transforms many coordinates in a list of ordinal values.
+     */
+    @Override
+    public void transform(final double[] srcPts, final int srcOff,
+                          final double[] dstPts, final int dstOff,
+                          final int numPts) throws TransformException
+    {
+        assert isValid();
+        transform1.transform(srcPts, srcOff, dstPts, dstOff, numPts);
+        transform2.transform(dstPts, dstOff, dstPts, dstOff, numPts);
+    }
+
+    /**
+     * Transforms many coordinates in a list of ordinal values.
+     */
+    @Override
+    public void transform(final float[]  srcPts, final int srcOff,
+                          final double[] dstPts, final int dstOff,
+                          final int numPts) throws TransformException
+    {
+        assert isValid();
+        transform1.transform(srcPts, srcOff, dstPts, dstOff, numPts);
+        transform2.transform(dstPts, dstOff, dstPts, dstOff, numPts);
+    }
+
+    // Do NOT override the transform(..., float[]...) version because we really need to use
+    // an intermediate buffer of type double[] for reducing rounding error.  Otherwise some
+    // map projection degrades image quality in an unacceptable way.
+}

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransformDirect.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransformDirect.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8



Mime
View raw message