sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1737072 [3/5] - in /sis/branches/JDK7: ./ application/sis-console/src/main/artifact/conf/ core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ core/sis-metadata/src/main/java/org/apache/sis/io/wkt/ core/sis-referencing/src/mai...
Date Tue, 29 Mar 2016 22:51:41 GMT
Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java?rev=1737072&r1=1737071&r2=1737072&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java [UTF-8] Tue Mar 29 22:51:40 2016
@@ -374,28 +374,30 @@ public class EPSGFactory extends Concurr
             if (ac) {
                 connection.setAutoCommit(false);
             }
-            boolean success = false;
             try {
-                if (!"".equals(schema)) {                                               // Schema may be null.
-                    installer.setSchema(schema != null ? schema : Constants.EPSG);
-                    if (catalog != null && !catalog.isEmpty()) {
-                        installer.prependNamespace(catalog);
+                boolean success = false;
+                try {
+                    if (!"".equals(schema)) {                                           // Schema may be null.
+                        installer.setSchema(schema != null ? schema : Constants.EPSG);
+                        if (catalog != null && !catalog.isEmpty()) {
+                            installer.prependNamespace(catalog);
+                        }
                     }
-                }
-                installer.run(scriptProvider, locale);
-                success = true;
-            } finally {
-                if (ac) {
-                    if (success) {
-                        connection.commit();
-                    } else {
-                        connection.rollback();
+                    installer.run(scriptProvider, locale);
+                    success = true;
+                } finally {
+                    if (ac) {
+                        if (success) {
+                            connection.commit();
+                        } else {
+                            connection.rollback();
+                        }
+                        connection.setAutoCommit(true);
                     }
-                    connection.setAutoCommit(true);
-                }
-                if (!success) {
-                    installer.logFailure(locale);
                 }
+            } catch (IOException | SQLException e) {
+                installer.logFailure(locale, e);
+                throw e;
             }
         }
     }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGInstaller.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGInstaller.java?rev=1737072&r1=1737071&r2=1737072&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGInstaller.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGInstaller.java [UTF-8] Tue Mar 29 22:51:40 2016
@@ -34,6 +34,7 @@ import org.apache.sis.internal.metadata.
 import org.apache.sis.internal.metadata.sql.SQLUtilities;
 import org.apache.sis.internal.util.Fallback;
 import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.Exceptions;
 import org.apache.sis.util.resources.Messages;
 import org.apache.sis.util.logging.PerformanceLevel;
 import org.apache.sis.setup.InstallationResources;
@@ -291,12 +292,13 @@ final class EPSGInstaller extends Script
      * lets the exception propagate. Another code (for example {@link org.apache.sis.referencing.CRS#forCode(String)})
      * may catch that exception and log another record with the exception message.
      */
-    final void logFailure(final Locale locale) {
+    final void logFailure(final Locale locale, final Exception cause) {
         String message = Messages.getResources(locale).getString(Messages.Keys.CanNotCreateSchema_1, EPSG);
         String status = status(locale);
         if (status != null) {
             message = message + ' ' + status;
         }
+        message = Exceptions.formatChainedMessages(locale, message, cause);
         InstallationScriptProvider.log(new LogRecord(Level.WARNING, message));
     }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/InstallationScriptProvider.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/InstallationScriptProvider.java?rev=1737072&r1=1737071&r2=1737072&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/InstallationScriptProvider.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/InstallationScriptProvider.java [UTF-8] Tue Mar 29 22:51:40 2016
@@ -383,7 +383,7 @@ public abstract class InstallationScript
          */
         @Override
         protected InputStream openStream(final String name) throws IOException {
-            return Files.newInputStream(directory.resolve(name));
+            return (directory != null) ? Files.newInputStream(directory.resolve(name)) : null;
         }
     }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java?rev=1737072&r1=1737071&r2=1737072&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java [UTF-8] Tue Mar 29 22:51:40 2016
@@ -32,6 +32,7 @@ import org.opengis.metadata.quality.Posi
 import org.opengis.referencing.IdentifiedObject;
 import org.opengis.referencing.crs.GeneralDerivedCRS;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.ConcatenatedOperation;
 import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.referencing.operation.MathTransform;
@@ -651,16 +652,29 @@ check:      for (int isTarget=0; ; isTar
      * {@linkplain #transform}, if possible. If no descriptor can be inferred from the math transform,
      * then this method fallback on the {@link OperationMethod} parameters.
      */
-    ParameterDescriptorGroup getParameterDescriptors() throws UnsupportedOperationException {
-        MathTransform mt = transform;
-        while (mt != null) {
-            if (mt instanceof Parameterized) {
+    ParameterDescriptorGroup getParameterDescriptors() {
+        ParameterDescriptorGroup descriptor = getParameterDescriptors(transform);
+        if (descriptor == null) {
+            final OperationMethod method = getMethod();
+            if (method != null) {
+                descriptor = method.getParameters();
+            }
+        }
+        return descriptor;
+    }
+
+    /**
+     * Returns the parameter descriptors for the given transform, or {@code null} if unknown.
+     */
+    static ParameterDescriptorGroup getParameterDescriptors(MathTransform transform) {
+        while (transform != null) {
+            if (transform instanceof Parameterized) {
                 final ParameterDescriptorGroup param;
                 if (Semaphores.queryAndSet(Semaphores.ENCLOSED_IN_OPERATION)) {
-                    throw new AssertionError(); // Should never happen.
+                    throw new AssertionError();                                     // Should never happen.
                 }
                 try {
-                    param = ((Parameterized) mt).getParameterDescriptors();
+                    param = ((Parameterized) transform).getParameterDescriptors();
                 } finally {
                     Semaphores.clear(Semaphores.ENCLOSED_IN_OPERATION);
                 }
@@ -668,14 +682,13 @@ check:      for (int isTarget=0; ; isTar
                     return param;
                 }
             }
-            if (mt instanceof PassThroughTransform) {
-                mt = ((PassThroughTransform) mt).getSubTransform();
+            if (transform instanceof PassThroughTransform) {
+                transform = ((PassThroughTransform) transform).getSubTransform();
             } else {
                 break;
             }
         }
-        final OperationMethod method = getMethod();
-        return (method != null) ? method.getParameters() : null;
+        return null;
     }
 
     /**
@@ -686,13 +699,13 @@ check:      for (int isTarget=0; ; isTar
      * @throws UnsupportedOperationException if the parameter values can not
      *         be determined for the current math transform implementation.
      */
-    ParameterValueGroup getParameterValues() {
+    ParameterValueGroup getParameterValues() throws UnsupportedOperationException {
         MathTransform mt = transform;
         while (mt != null) {
             if (mt instanceof Parameterized) {
                 final ParameterValueGroup param;
                 if (Semaphores.queryAndSet(Semaphores.ENCLOSED_IN_OPERATION)) {
-                    throw new AssertionError(); // Should never happen.
+                    throw new AssertionError();                                     // Should never happen.
                 }
                 try {
                     param = ((Parameterized) mt).getParameterValues();
@@ -845,32 +858,45 @@ check:      for (int isTarget=0; ; isTar
     protected String formatTo(final Formatter formatter) {
         super.formatTo(formatter);
         formatter.newLine();
-        append(formatter, getSourceCRS(), WKTKeywords.SourceCRS);
-        append(formatter, getTargetCRS(), WKTKeywords.TargetCRS);
-        formatter.append(DefaultOperationMethod.castOrCopy(getMethod()));
-        ParameterValueGroup parameters;
-        try {
-            parameters = getParameterValues();
-        } catch (UnsupportedOperationException e) {
-            final IdentifiedObject c = getParameterDescriptors();
-            formatter.setInvalidWKT(c != null ? c : this, e);
-            parameters = null;
+        /*
+         * If the WKT is a component of a ConcatenatedOperation, do not format the source and target CRS.
+         * This decision SIS-specific since the WKT 2 specification does not define concatenated operations.
+         * The choice of content to omit may change in any future version.
+         */
+        final boolean isComponent = (formatter.getEnclosingElement(1) instanceof ConcatenatedOperation);
+        if (!isComponent) {
+            append(formatter, getSourceCRS(), WKTKeywords.SourceCRS);
+            append(formatter, getTargetCRS(), WKTKeywords.TargetCRS);
         }
-        if (parameters != null) {
-            formatter.newLine();
-            for (final GeneralParameterValue param : parameters.values()) {
-                WKTUtilities.append(param, formatter);
+        final OperationMethod method = getMethod();
+        if (method != null) {
+            formatter.append(DefaultOperationMethod.castOrCopy(method));
+            ParameterValueGroup parameters;
+            try {
+                parameters = getParameterValues();
+            } catch (UnsupportedOperationException e) {
+                final IdentifiedObject c = getParameterDescriptors();
+                formatter.setInvalidWKT(c != null ? c : this, e);
+                parameters = null;
             }
-        }
-        append(formatter, getInterpolationCRS(), WKTKeywords.InterpolationCRS);
-        final double accuracy = getLinearAccuracy();
-        if (accuracy > 0) {
-            formatter.append(new FormattableObject() {
-                @Override protected String formatTo(final Formatter formatter) {
-                    formatter.append(accuracy);
-                    return WKTKeywords.OperationAccuracy;
+            if (parameters != null) {
+                formatter.newLine();
+                for (final GeneralParameterValue param : parameters.values()) {
+                    WKTUtilities.append(param, formatter);
                 }
-            });
+            }
+        }
+        if (!isComponent) {
+            append(formatter, getInterpolationCRS(), WKTKeywords.InterpolationCRS);
+            final double accuracy = getLinearAccuracy();
+            if (accuracy > 0) {
+                formatter.append(new FormattableObject() {
+                    @Override protected String formatTo(final Formatter formatter) {
+                        formatter.append(accuracy);
+                        return WKTKeywords.OperationAccuracy;
+                    }
+                });
+            }
         }
         if (formatter.getConvention().majorVersion() == 1) {
             formatter.setInvalidWKT(this, null);

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractSingleOperation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractSingleOperation.java?rev=1737072&r1=1737071&r2=1737072&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractSingleOperation.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractSingleOperation.java [UTF-8] Tue Mar 29 22:51:40 2016
@@ -225,14 +225,14 @@ class AbstractSingleOperation extends Ab
          * ignoring null java.lang.Integer instances.  We do not specify whether the method
          * dimensions should include the interpolation dimensions or not, so we accept both.
          */
-        int isTarget = 0;   // 0 == false: the wrong dimension is the source one.
+        int isTarget = 0;               // 0 == false: the wrong dimension is the source one.
         if (expected == null || (actual == expected) || (actual == expected + interpDim)) {
             actual = transform.getTargetDimensions();
             expected = method.getTargetDimensions();
             if (expected == null || (actual == expected) || (actual == expected + interpDim)) {
                 return;
             }
-            isTarget = 1;   // 1 == true: the wrong dimension is the target one.
+            isTarget = 1;               // 1 == true: the wrong dimension is the target one.
         }
         /*
          * At least one dimension does not match.  In principle this is an error, but we make an exception for the

Copied: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java (from r1737071, sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java?p2=sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java&p1=sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java&r1=1737071&r2=1737072&rev=1737072&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationInference.java [UTF-8] Tue Mar 29 22:51:40 2016
@@ -65,6 +65,7 @@ import static org.apache.sis.util.Utilit
 
 // Branch-dependent imports
 import java.util.Objects;
+import org.apache.sis.internal.jdk8.JDK8;
 
 
 /**
@@ -728,7 +729,7 @@ public class CoordinateOperationInferenc
         }
         properties.put(ReferencingServices.OPERATION_TYPE_KEY, type);
         if (Conversion.class.isAssignableFrom(type)) {
-            properties.replace(IdentifiedObject.NAME_KEY, AXIS_CHANGES, IDENTITY);
+            JDK8.replace(properties, IdentifiedObject.NAME_KEY, AXIS_CHANGES, IDENTITY);
         }
         return factorySIS.createSingleOperation(properties, sourceCRS, targetCRS, null, method, transform);
     }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java?rev=1737072&r1=1737071&r2=1737072&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java [UTF-8] Tue Mar 29 22:51:40 2016
@@ -46,6 +46,7 @@ import static org.apache.sis.util.Utilit
 
 // Branch-dependent imports
 import java.util.Objects;
+import org.apache.sis.io.wkt.Formatter;
 
 
 /**
@@ -325,6 +326,23 @@ final class DefaultConcatenatedOperation
         return super.computeHashCode() + 37 * Objects.hashCode(operations);
     }
 
+    /**
+     * Formats this coordinate operation in pseudo-WKT. This is specific to Apache SIS since
+     * there is no concatenated operation in the Well Known Text (WKT) version 2 format.
+     *
+     * @param  formatter The formatter to use.
+     * @return {@code "ConcatenatedOperation"}.
+     */
+    @Override
+    protected String formatTo(final Formatter formatter) {
+        super.formatTo(formatter);
+        for (final CoordinateOperation component : operations) {
+            formatter.append(castOrCopy(component));
+        }
+        formatter.setInvalidWKT(this, null);
+        return "ConcatenatedOperation";
+    }
+
 
 
 

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java?rev=1737072&r1=1737071&r2=1737072&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java [UTF-8] Tue Mar 29 22:51:40 2016
@@ -254,12 +254,12 @@ public class DefaultConversion extends A
                  * CoordinateReferenceSystem because the targetCRS is typically under construction when this
                  * method in invoked, and attempts to use it can cause NullPointerException.
                  */
-                final DefaultMathTransformFactory.Context context = new DefaultMathTransformFactory.Context();
-                context.setSource(source);
+                final DefaultMathTransformFactory.Context context;
                 if (target instanceof GeneralDerivedCRS) {
+                    context = ReferencingUtilities.createTransformContext(source, null, null);
                     context.setTarget(target.getCoordinateSystem());    // Using 'target' would be unsafe here.
                 } else {
-                    context.setTarget(target);
+                    context = ReferencingUtilities.createTransformContext(source, target, null);
                 }
                 transform = ((DefaultMathTransformFactory) factory).createParameterizedTransform(parameters, context);
                 parameters = Parameters.unmodifiable(context.getCompletedParameters());

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java?rev=1737072&r1=1737071&r2=1737072&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java [UTF-8] Tue Mar 29 22:51:40 2016
@@ -19,6 +19,7 @@ package org.apache.sis.referencing.opera
 import java.util.Map;
 import java.util.HashMap;
 import java.util.Collections;
+import java.util.List;
 import org.opengis.util.FactoryException;
 import org.opengis.util.NoSuchIdentifierException;
 import org.opengis.parameter.ParameterValueGroup;
@@ -28,11 +29,13 @@ import org.opengis.referencing.Identifie
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.crs.GeographicCRS;
 import org.opengis.referencing.crs.ProjectedCRS;
+import org.opengis.referencing.crs.SingleCRS;
+import org.opengis.referencing.datum.Datum;
 import org.apache.sis.internal.referencing.MergedProperties;
 import org.apache.sis.internal.metadata.ReferencingServices;
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.internal.util.CollectionsExt;
-import org.apache.sis.internal.util.Utilities;
+import org.apache.sis.referencing.CRS;
 import org.apache.sis.referencing.factory.InvalidGeodeticParameterException;
 import org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory;
 import org.apache.sis.util.collection.WeakHashSet;
@@ -42,6 +45,7 @@ import org.apache.sis.util.resources.Err
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.NullArgumentException;
+import org.apache.sis.util.Utilities;
 
 
 /**
@@ -68,7 +72,7 @@ import org.apache.sis.util.NullArgumentE
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.6
- * @version 0.6
+ * @version 0.7
  * @module
  */
 public class DefaultCoordinateOperationFactory extends AbstractFactory implements CoordinateOperationFactory {
@@ -149,7 +153,7 @@ public class DefaultCoordinateOperationF
      *
      * @return The underlying math transform factory.
      */
-    private MathTransformFactory getMathTransformFactory() {
+    final MathTransformFactory getMathTransformFactory() {
         MathTransformFactory factory = mtFactory;
         if (factory == null) {
             mtFactory = factory = DefaultFactories.forBuildin(MathTransformFactory.class);
@@ -158,6 +162,18 @@ public class DefaultCoordinateOperationF
     }
 
     /**
+     * Returns the Apache SIS implementation of math transform factory.
+     * This method is used only when we need SIS-specific methods.
+     */
+    final DefaultMathTransformFactory getDefaultMathTransformFactory() {
+        MathTransformFactory factory = getMathTransformFactory();
+        if (factory instanceof DefaultMathTransformFactory) {
+            return (DefaultMathTransformFactory) factory;
+        }
+        return DefaultFactories.forBuildin(MathTransformFactory.class, DefaultMathTransformFactory.class);
+    }
+
+    /**
      * Returns the operation method of the given name. The given argument shall be either a method
      * {@linkplain DefaultOperationMethod#getName() name} (e.g. <cite>"Transverse Mercator"</cite>)
      * or one of its {@linkplain DefaultOperationMethod#getIdentifiers() identifiers} (e.g. {@code "EPSG:9807"}).
@@ -314,6 +330,39 @@ public class DefaultCoordinateOperationF
     }
 
     /**
+     * Returns {@code true} if the given CRS are using equivalent (ignoring metadata) datum.
+     * If the CRS are {@link CompoundCRS}, then this method verifies that all datum in the
+     * target CRS exists in the source CRS, but not necessarily in the same order.
+     * The target CRS may have less datum than the source CRS.
+     *
+     * @param sourceCRS The target CRS.
+     * @param targetCRS The source CRS.
+     * @return {@code true} if all datum in the {@code targetCRS} exists in the {@code sourceCRS}.
+     */
+    private static boolean isConversion(final CoordinateReferenceSystem sourceCRS,
+                                        final CoordinateReferenceSystem targetCRS)
+    {
+        List<SingleCRS> components = CRS.getSingleComponents(sourceCRS);
+        int n = components.size();                      // Number of remaining datum from sourceCRS to verify.
+        final Datum[] datum = new Datum[n];
+        for (int i=0; i<n; i++) {
+            datum[i] = components.get(i).getDatum();
+        }
+        components = CRS.getSingleComponents(targetCRS);
+next:   for (int i=components.size(); --i >= 0;) {
+            final Datum d = components.get(i).getDatum();
+            for (int j=n; --j >= 0;) {
+                if (Utilities.equalsIgnoreMetadata(d, datum[j])) {
+                    System.arraycopy(datum, j+1, datum, j, --n - j);  // Remove the datum from the list.
+                    continue next;
+                }
+            }
+            return false;                               // Datum from 'targetCRS' not found in 'sourceCRS'.
+        }
+        return true;
+    }
+
+    /**
      * Creates a transformation or conversion from the given properties.
      * This method infers by itself if the operation to create is a
      * {@link Transformation}, a {@link Conversion} or a {@link Projection} sub-type
@@ -401,7 +450,7 @@ public class DefaultCoordinateOperationF
         }
         if (method instanceof DefaultOperationMethod) {
             final Class<? extends SingleOperation> c = ((DefaultOperationMethod) method).getOperationType();
-            if (c != null) {  // Paranoiac check (above method should not return null).
+            if (c != null) {                        // Paranoiac check (above method should not return null).
                 if (baseType.isAssignableFrom(c)) {
                     baseType = c;
                 } else if (!c.isAssignableFrom(baseType)) {
@@ -424,7 +473,7 @@ public class DefaultCoordinateOperationF
          * could be different, which we want to allow.
          */
         if (baseType == SingleOperation.class) {
-            if (OperationPathFinder.isConversion(sourceCRS, targetCRS)) {
+            if (isConversion(sourceCRS, targetCRS)) {
                 if (interpolationCRS == null && sourceCRS instanceof GeographicCRS
                                              && targetCRS instanceof ProjectedCRS)
                 {
@@ -473,7 +522,7 @@ public class DefaultCoordinateOperationF
             op = new AbstractSingleOperation(properties, sourceCRS, targetCRS, interpolationCRS, method, transform);
         }
         if (!baseType.isInstance(op)) {
-            throw new FactoryException(Errors.format(Errors.Keys.CanNotInstantiate_1, baseType));
+            throw new FactoryException(Errors.format(Errors.Keys.CanNotCreateObjectAsInstanceOf_2, baseType, op.getName()));
         }
         return pool.unique(op);
     }
@@ -528,57 +577,87 @@ public class DefaultCoordinateOperationF
     }
 
     /**
-     * Not yet implemented.
-     *
-     * @param  sourceCRS Input coordinate reference system.
-     * @param  targetCRS Output coordinate reference system.
-     * @param  method the algorithmic method for conversion or transformation.
-     * @return A coordinate operation from {@code sourceCRS} to {@code targetCRS}.
-     * @throws FactoryException if the operation creation failed.
+     * Finds or creates an operation for conversion or transformation between two coordinate reference systems.
+     * If an operation exists, it is returned. If more than one operation exists, the operation having the widest
+     * domain of validity is returned. If no operation exists, then an exception is thrown.
+     *
+     * <p>The default implementation delegates to <code>{@linkplain #createOperation(CoordinateReferenceSystem,
+     * CoordinateReferenceSystem, CoordinateOperationContext) createOperation}(sourceCRS, targetCRS, null)}</code>.</p>
+     *
+     * @param  sourceCRS  input coordinate reference system.
+     * @param  targetCRS  output coordinate reference system.
+     * @return a coordinate operation from {@code sourceCRS} to {@code targetCRS}.
+     * @throws OperationNotFoundException if no operation path was found from {@code sourceCRS} to {@code targetCRS}.
+     * @throws FactoryException if the operation creation failed for some other reason.
      */
     @Override
     public CoordinateOperation createOperation(final CoordinateReferenceSystem sourceCRS,
-                                               final CoordinateReferenceSystem targetCRS,
-                                               final OperationMethod method)
-            throws FactoryException
+                                               final CoordinateReferenceSystem targetCRS)
+            throws OperationNotFoundException, FactoryException
     {
-        return delegate().createOperation(sourceCRS, targetCRS, method);
+        return createOperation(sourceCRS, targetCRS, (CoordinateOperationContext) null);
     }
 
     /**
-     * Not yet implemented.
+     * Finds or creates an operation for conversion or transformation between two coordinate reference systems.
+     * If an operation exists, it is returned. If more than one operation exists, then the operation having the
+     * widest intersection between its {@linkplain AbstractCoordinateOperation#getDomainOfValidity() domain of
+     * validity} and the {@linkplain CoordinateOperationContext#getAreaOfInterest() area of interest} is returned.
+     *
+     * <p>The default implementation is as below:</p>
      *
-     * @param  sourceCRS Input coordinate reference system.
-     * @param  targetCRS Output coordinate reference system.
-     * @return A coordinate operation from {@code sourceCRS} to {@code targetCRS}.
+     * {@preformat java
+     *   return new CoordinateOperationInference(this, context).createOperation(sourceCRS, targetCRS);
+     * }
+     *
+     * Subclasses can override this method if they need, for example, to use a custom
+     * {@link CoordinateOperationInference} implementation.
+     *
+     * @param  sourceCRS  input coordinate reference system.
+     * @param  targetCRS  output coordinate reference system.
+     * @param  context    area of interest and desired accuracy, or {@code null}.
+     * @return a coordinate operation from {@code sourceCRS} to {@code targetCRS}.
      * @throws OperationNotFoundException if no operation path was found from {@code sourceCRS} to {@code targetCRS}.
      * @throws FactoryException if the operation creation failed for some other reason.
+     *
+     * @see CoordinateOperationInference
+     *
+     * @since 0.7
      */
-    @Override
     public CoordinateOperation createOperation(final CoordinateReferenceSystem sourceCRS,
-                                               final CoordinateReferenceSystem targetCRS)
+                                               final CoordinateReferenceSystem targetCRS,
+                                               final CoordinateOperationContext context)
             throws OperationNotFoundException, FactoryException
     {
-        return delegate().createOperation(sourceCRS, targetCRS);
+        return new CoordinateOperationInference(this, context).createOperation(sourceCRS, targetCRS);
     }
 
     /**
-     * Temporarily returns a third-party factory for operation not yet implemented by this class.
-     * This method will be removed when the missing implementation will have been ported to SIS.
+     * Returns an operation using a particular method for conversion or transformation between
+     * two coordinate reference systems. If an operation exists using the given method, then it
+     * is returned. If no operation using the given method is found, then the implementation has
+     * the option of inferring the operation from the argument objects.
+     *
+     * <p>Current implementation ignores the {@code method} argument.
+     * This behavior may change in a future Apache SIS version.</p>
+     *
+     * @param  sourceCRS  input coordinate reference system.
+     * @param  targetCRS  output coordinate reference system.
+     * @param  method     the algorithmic method for conversion or transformation.
+     * @return a coordinate operation from {@code sourceCRS} to {@code targetCRS}.
+     * @throws OperationNotFoundException if no operation path was found from {@code sourceCRS} to {@code targetCRS}.
+     * @throws FactoryException if the operation creation failed for some other reason.
+     *
+     * @deprecated Replaced by {@link #createOperation(CoordinateReferenceSystem, CoordinateReferenceSystem, CoordinateOperationContext)}.
      */
-    private synchronized CoordinateOperationFactory delegate() throws FactoryException {
-        if (delegate != null) {
-            return delegate;
-        }
-        for (final CoordinateOperationFactory factory : java.util.ServiceLoader.load(CoordinateOperationFactory.class)) {
-            if (!Utilities.isSIS(factory.getClass())) {
-                delegate = factory;
-                return factory;
-            }
-        }
-        throw new FactoryException(Errors.format(Errors.Keys.MissingRequiredModule_1, "geotk-referencing")); // This is temporary.
+    @Override
+    @Deprecated
+    public CoordinateOperation createOperation(final CoordinateReferenceSystem sourceCRS,
+                                               final CoordinateReferenceSystem targetCRS,
+                                               final OperationMethod method)
+            throws FactoryException
+    {
+        ArgumentChecks.ensureNonNull("method", method);     // As a matter of principle.
+        return createOperation(sourceCRS, targetCRS, (CoordinateOperationContext) null);
     }
-
-    /** Temporary, to be deleted in a future SIS version. */
-    private transient CoordinateOperationFactory delegate;
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java?rev=1737072&r1=1737071&r2=1737072&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java [UTF-8] Tue Mar 29 22:51:40 2016
@@ -191,7 +191,7 @@ class GeneralMatrix extends MatrixSIS im
      */
     static int indexOfErrors(final int numRow, final int numCol, final double[] elements) {
         assert elements.length % (numRow * numCol) == 0;
-        return (numRow * numCol) % elements.length; // A % B is for getting 0 without branching if A == B.
+        return (numRow * numCol) % elements.length;         // A % B is for getting 0 without branching if A == B.
     }
 
     /**
@@ -337,7 +337,7 @@ class GeneralMatrix extends MatrixSIS im
                 if (copy) {
                     elements = elements.clone();
                 }
-                return elements; // Internal array already uses extended precision.
+                return elements;                                // Internal array already uses extended precision.
             } else {
                 elements = Arrays.copyOf(elements, length);
             }
@@ -415,7 +415,7 @@ class GeneralMatrix extends MatrixSIS im
      * @see Matrices#create(int, int, Number[])
      */
     final boolean setElements(final Number[] newValues) {
-        final int numRow = this.numRow; // Protection against accidental changes.
+        final int numRow = this.numRow;                         // Protection against accidental changes.
         final int numCol = this.numCol;
         final int length = numRow * numCol;
         if (newValues.length != length) {
@@ -494,9 +494,18 @@ class GeneralMatrix extends MatrixSIS im
      */
     @Override
     public final boolean isAffine() {
-        final int numRow = this.numRow; // Protection against accidental changes.
+        return isAffine(true);
+    }
+
+    /**
+     * Implementation of {@link #isAffine()} with control on whether we require the matrix to be square.
+     *
+     * @param square {@code true} if the matrix must be square, or {@code false} for allowing non-square matrices.
+     */
+    final boolean isAffine(final boolean square) {
+        final int numRow = this.numRow;                     // Protection against accidental changes.
         final int numCol = this.numCol;
-        if (numRow == numCol) {
+        if (numRow == numCol || !square) {
             int i = numRow * numCol;
             if (elements[--i] == 1) {
                 final int base = (numRow - 1) * numCol;
@@ -526,7 +535,7 @@ class GeneralMatrix extends MatrixSIS im
      */
     @Override
     public final boolean isIdentity() {
-        final int numRow = this.numRow; // Protection against accidental changes.
+        final int numRow = this.numRow;                     // Protection against accidental changes.
         final int numCol = this.numCol;
         if (numRow != numCol) {
             return false;
@@ -553,9 +562,9 @@ class GeneralMatrix extends MatrixSIS im
      */
     @Override
     public void transpose() {
-        final int numRow = this.numRow; // Protection against accidental changes.
+        final int numRow = this.numRow;                                 // Protection against accidental changes.
         final int numCol = this.numCol;
-        final int errors = indexOfErrors(numRow, numCol, elements); // Where error values start, or 0 if none.
+        final int errors = indexOfErrors(numRow, numCol, elements);     // Where error values start, or 0 if none.
         for (int j=0; j<numRow; j++) {
             for (int i=0; i<j; i++) {
                 final int lo = j*numCol + i;
@@ -574,7 +583,7 @@ class GeneralMatrix extends MatrixSIS im
      * The matrix sizes much match - this is not verified unless assertions are enabled.
      */
     final void setToProduct(final Matrix A, final Matrix B) {
-        final int numRow = this.numRow; // Protection against accidental changes.
+        final int numRow = this.numRow;         // Protection against accidental changes.
         final int numCol = this.numCol;
         final int nc = A.getNumCol();
         assert B.getNumRow() == nc;
@@ -585,7 +594,7 @@ class GeneralMatrix extends MatrixSIS im
          */
         final double[] eltA   = getExtendedElements(A, numRow, nc, false);
         final double[] eltB   = getExtendedElements(B, nc, numCol, false);
-        final int errorOffset = numRow * numCol; // Where error terms start.
+        final int errorOffset = numRow * numCol;            // Where error terms start.
         final int errA        = numRow * nc;
         final int errB        = nc * numCol;
         /*
@@ -597,20 +606,20 @@ class GeneralMatrix extends MatrixSIS im
             for (int i=0; i<numCol; i++) {
                 sum.clear();
                 double max = 0;
-                int iB = i;       // Index of values in a single column of B.
-                int iA = j * nc;  // Index of values in a single row of A.
+                int iB = i;                                 // Index of values in a single column of B.
+                int iA = j * nc;                            // Index of values in a single row of A.
                 final int nextRow = iA + nc;
                 while (iA < nextRow) {
                     dot.setFrom (eltA, iA, errA);
                     dot.multiply(eltB, iB, errB);
                     sum.add(dot);
-                    iB += numCol; // Move to next row of B.
-                    iA++;         // Move to next column of A.
+                    iB += numCol;                           // Move to next row of B.
+                    iA++;                                   // Move to next column of A.
                     final double value = Math.abs(dot.value);
                     if (value > max) max = value;
                 }
                 if (Math.abs(sum.value) < Math.ulp(max) * ZERO_THRESHOLD) {
-                    sum.clear(); // Sum is not significant according double arithmetic.
+                    sum.clear();                            // Sum is not significant according double arithmetic.
                 }
                 sum.storeTo(elements, k++, errorOffset);
             }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java?rev=1737072&r1=1737071&r2=1737072&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java [UTF-8] Tue Mar 29 22:51:40 2016
@@ -68,7 +68,7 @@ import java.util.Objects;
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.4
- * @version 0.6
+ * @version 0.7
  * @module
  *
  * @see org.apache.sis.parameter.TensorParameters
@@ -735,7 +735,7 @@ public final class Matrices extends Stat
      */
     public static MatrixSIS multiply(final Matrix m1, final Matrix m2) throws MismatchedMatrixSizeException {
         if (m1 instanceof MatrixSIS) {
-            return ((MatrixSIS) m1).multiply(m2);  // Maybe the subclass override that method.
+            return ((MatrixSIS) m1).multiply(m2);           // Maybe the subclass overrides that method.
         }
         final int nc = m2.getNumCol();
         MatrixSIS.ensureNumRowMatch(m1.getNumCol(), m2.getNumRow(), nc);
@@ -776,7 +776,6 @@ public final class Matrices extends Stat
      * @return {@code true} if the matrix represents an affine transform.
      *
      * @see MatrixSIS#isAffine()
-     * @see AffineTransforms2D#castOrCopy(Matrix)
      */
     public static boolean isAffine(final Matrix matrix) {
         if (matrix instanceof MatrixSIS) {
@@ -787,6 +786,32 @@ public final class Matrices extends Stat
     }
 
     /**
+     * Returns {@code true} if the given matrix represents a translation.
+     * This method returns {@code true} if the given matrix {@linkplain #isAffine(Matrix) is affine}
+     * and differs from the identity matrix only in the last column.
+     *
+     * @param matrix The matrix to test.
+     * @return {@code true} if the matrix represents a translation.
+     *
+     * @since 0.7
+     */
+    public static boolean isTranslation(final Matrix matrix) {
+        if (!isAffine(matrix)) {
+            return false;
+        }
+        final int numRow = matrix.getNumRow() - 1;      // Excluding translation column.
+        final int numCol = matrix.getNumCol() - 1;      // Excluding last row in affine transform.
+        for (int j=0; j<numRow; j++) {
+            for (int i=0; i<numCol; i++) {
+                if (matrix.getElement(j,i) != ((i == j) ? 1 : 0)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
      * Returns {@code true} if the given matrix is close to an identity matrix, given a tolerance threshold.
      * This method is equivalent to computing the difference between the given matrix and an identity matrix
      * of identical size, and returning {@code true} if and only if all differences are smaller than or equal

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrix.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrix.java?rev=1737072&r1=1737071&r2=1737072&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrix.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrix.java [UTF-8] Tue Mar 29 22:51:40 2016
@@ -227,28 +227,39 @@ next:   do {
     }
 
     /**
-     * Inverse a matrix for a transform where target points has more ordinates than source points.
+     * Inverses a matrix for a transform where target points has more ordinates than source points.
      * In other words, the target matrices will be a transform that discard some ordinate values.
      * We will discard the ones for which the row contains only 0 or NaN elements.
+     *
+     * <p>In the special case where the last row is of the form [0 0 … 0 1] as in affine transforms,
+     * this method also omits rows that contain only a translation term. We allow that because if we
+     * do not omit those rows, then the matrix will be non-invertible anyway. This is true only when
+     * the last row contains only zero except in the last column ([0 0 … 0 n] where <var>n</var> can
+     * be any value). We restrict <var>n</var> to 1 for now because a different value may indicate a
+     * matrix created for another purpose than coordinate conversions.</p>
      */
     private MatrixSIS inverseDimensionIncrease() throws NoninvertibleMatrixException {
-        final int numRow = this.numRow; // Protection against accidental changes.
+        final int numRow = this.numRow;                     // Protection against accidental changes.
         final int numCol = this.numCol;
         int j  = numRow;
-        int oi = numRow - numCol; // Initialized to the maximal amount of rows that we may discard.
+        int oi = numRow - numCol;   // Initialized to the maximal amount of rows that we may discard.
         final int[] omitted = new int[oi];
+        final boolean ignoreTranslation = isAffine(false);
+        if (ignoreTranslation) j--;                         // Last row already verified by isAffine().
 next:   do {
             if (--j < 0) {
-                throw nonInvertible(); // Not enough rows that we can omit.
+                throw nonInvertible();                      // Not enough rows that we can omit.
             }
             final int offset = j * numCol;
-            for (int i=offset + numCol; --i >= offset;) {
+            int i = offset + numCol;
+            if (ignoreTranslation) i--;
+            while (--i >= offset) {
                 final double element = elements[i];
                 if (element != 0 && !Double.isNaN(element)) {
                     continue next;
                 }
             }
-            omitted[--oi] = j; // Found a row which contains only 0 or NaN elements.
+            omitted[--oi] = j;                  // Found a row which contains only 0 or NaN elements.
         } while (oi != 0);
         /*
          * Found enough rows containing only zero elements. Create a square matrix omitting those rows,
@@ -258,7 +269,7 @@ next:   do {
         int i = 0;
         for (j=0; j<numRow; j++) {
             if (oi != omitted.length && j == omitted[oi]) oi++;
-            else copyRow(this, j, squareMatrix, i++); // Copy only if not skipped.
+            else copyRow(this, j, squareMatrix, i++);                   // Copy only if not skipped.
         }
         if (indexOfErrors(numRow, numCol, elements) == 0) {
             inferErrors(squareMatrix.elements);
@@ -329,6 +340,7 @@ next:   do {
      * {@inheritDoc}
      */
     @Override
+    @SuppressWarnings("CloneDoesntCallSuperClone")
     public MatrixSIS clone() {
         return new NonSquareMatrix(this);
     }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Solver.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Solver.java?rev=1737072&r1=1737071&r2=1737072&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Solver.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Solver.java [UTF-8] Tue Mar 29 22:51:40 2016
@@ -38,7 +38,7 @@ import org.apache.sis.util.ArraysExt;
  * @module
  */
 @SuppressWarnings("CloneInNonCloneableClass")
-final class Solver implements Matrix { // Not Cloneable, despite the clone() method.
+final class Solver implements Matrix {                          // Not Cloneable, despite the clone() method.
     /**
      * The size of the (i, j, s) tuples used internally by {@link #solve(Matrix, Matrix, double[], int, int)}
      * for storing information about the NaN values.
@@ -143,7 +143,7 @@ final class Solver implements Matrix { /
         if (Y instanceof GeneralMatrix) {
             eltY = ((GeneralMatrix) Y).elements;
             if (eltY.length == size * innerSize) {
-                eltY = null; // Matrix does not contains error terms.
+                eltY = null;                            // Matrix does not contains error terms.
             }
         }
         return solve(X, Y, eltY, size, innerSize, true);
@@ -248,7 +248,7 @@ searchNaN:  for (int flatIndex = (size -
                     }
                     indexOfNaN[indexCount++] = i;
                     indexOfNaN[indexCount++] = j;
-                    indexOfNaN[indexCount++] = columnOfScale; // May be -1 (while uncommon)
+                    indexOfNaN[indexCount++] = columnOfScale;                   // May be -1 (while uncommon)
                     assert (indexCount % TUPLE_SIZE) == 0;
                 }
             }
@@ -262,7 +262,7 @@ searchNaN:  for (int flatIndex = (size -
                 final int j = indexOfNaN[k+1];
                 final int flatIndex = j*size + i;
                 LU[flatIndex] = (i == lastRowOrColumn) ? 0 : 1;
-                LU[flatIndex + size*size] = 0; // Error term (see 'errorLU') in next method.
+                LU[flatIndex + size*size] = 0;                      // Error term (see 'errorLU') in next method.
             }
         }
         /*
@@ -280,9 +280,9 @@ searchNaN:  for (int flatIndex = (size -
             final int s = indexOfNaN[k++];
             if (i != lastRowOrColumn) {
                 // Found a scale factor to set to NaN.
-                matrix.setElement(i, j, Double.NaN); // Note that i,j indices are interchanged.
+                matrix.setElement(i, j, Double.NaN);                      // Note that i,j indices are interchanged.
                 if (matrix.getElement(i, lastRowOrColumn) != 0) {
-                    matrix.setElement(i, lastRowOrColumn, Double.NaN); // = -offset/scale, so 0 stay 0.
+                    matrix.setElement(i, lastRowOrColumn, Double.NaN);    // = -offset/scale, so 0 stay 0.
                 }
             } else if (s >= 0) {
                 // Found a translation factory to set to NaN.
@@ -323,17 +323,17 @@ searchNaN:  for (int flatIndex = (size -
         for (int j=0; j<size; j++) {
            pivot[j] = j;
         }
-        final double[]  column = new double[size * 2]; // [0 … size-1] : column values; [size … 2*size-1] : error terms.
-        final DoubleDouble acc = new DoubleDouble();   // Temporary variable for sum ("accumulator") and subtraction.
-        final DoubleDouble rat = new DoubleDouble();   // Temporary variable for products and ratios.
+        final double[]  column = new double[size * 2];  // [0 … size-1] : column values; [size … 2*size-1] : error terms.
+        final DoubleDouble acc = new DoubleDouble();    // Temporary variable for sum ("accumulator") and subtraction.
+        final DoubleDouble rat = new DoubleDouble();    // Temporary variable for products and ratios.
         for (int i=0; i<size; i++) {
             /*
              * Make a copy of the i-th column.
              */
             for (int j=0; j<size; j++) {
                 final int k = j*size + i;
-                column[j]        = LU[k];            // Value
-                column[j + size] = LU[k + errorLU];  // Error
+                column[j]        = LU[k];               // Value
+                column[j + size] = LU[k + errorLU];     // Error
             }
             /*
              * Apply previous transformations. This part is equivalent to the following code,
@@ -372,7 +372,7 @@ searchNaN:  for (int flatIndex = (size -
             if (p != i) {
                 final int pRow = p*size;
                 final int iRow = i*size;
-                for (int k=0; k<size; k++) { // Swap two full rows.
+                for (int k=0; k<size; k++) {                                // Swap two full rows.
                     DoubleDouble.swap(LU, pRow + k, iRow + k, errorLU);
                 }
                 ArraysExt.swap(pivot, p, i);
@@ -435,10 +435,10 @@ searchNaN:  for (int flatIndex = (size -
          *     elements[loRowOffset + i] -= (elements[rowOffset + i] * LU[luRowOffset + k]);
          */
         for (int k=0; k<size; k++) {
-            final int rowOffset = k*innerSize;          // Offset of row computed by current iteration.
+            final int rowOffset = k*innerSize;              // Offset of row computed by current iteration.
             for (int j=k; ++j < size;) {
-                final int loRowOffset = j*innerSize;    // Offset of some row after the current row.
-                final int luRowOffset = j*size;         // Offset of the corresponding row in the LU matrix.
+                final int loRowOffset = j*innerSize;        // Offset of some row after the current row.
+                final int luRowOffset = j*size;             // Offset of the corresponding row in the LU matrix.
                 for (int i=0; i<innerSize; i++) {
                     acc.setFrom (elements, loRowOffset + i, errorOffset);
                     rat.setFrom (elements, rowOffset   + i, errorOffset);

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/UnmodifiableMatrix.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/UnmodifiableMatrix.java?rev=1737072&r1=1737071&r2=1737072&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/UnmodifiableMatrix.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/UnmodifiableMatrix.java [UTF-8] Tue Mar 29 22:51:40 2016
@@ -17,6 +17,7 @@
 package org.apache.sis.referencing.operation.matrix;
 
 import org.opengis.referencing.operation.Matrix;
+import org.apache.sis.internal.referencing.ExtendedPrecisionMatrix;
 import org.apache.sis.util.resources.Errors;
 
 
@@ -26,10 +27,10 @@ import org.apache.sis.util.resources.Err
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.6
- * @version 0.6
+ * @version 0.7
  * @module
  */
-final class UnmodifiableMatrix extends MatrixSIS {
+final class UnmodifiableMatrix extends MatrixSIS implements ExtendedPrecisionMatrix {
     /**
      * For cross-version compatibility.
      */
@@ -91,6 +92,18 @@ final class UnmodifiableMatrix extends M
         }
     }
 
+    /**
+     * Returns elements together with their error terms if available, or just the elements otherwise.
+     */
+    @Override
+    public double[] getExtendedElements() {
+        if (matrix instanceof ExtendedPrecisionMatrix) {
+            return ((ExtendedPrecisionMatrix) matrix).getExtendedElements();
+        } else {
+            return getElements();
+        }
+    }
+
     /**
      * Returns the exception to throw when a setter method is invoked.
      */

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/package-info.java?rev=1737072&r1=1737071&r2=1737072&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/package-info.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/package-info.java [UTF-8] Tue Mar 29 22:51:40 2016
@@ -53,6 +53,43 @@
  *     for converting the longitude axis of source and target CRS to degrees before this operation is applied.</li>
  * </ul>
  *
+ * <div class="section"><cite>Early binding</cite> versus <cite>late binding</cite> implementations</div>
+ * There is sometime multiple ways of transforming coordinates for a given pair of source and target CRS.
+ * For example the {@linkplain org.apache.sis.referencing.datum.BursaWolfParameters Bursa-Wolf parameters}
+ * may vary depending on the area of interest, like in the transformations from NAD27 to NAD83.
+ * Even for a fixed set of Bursa-Wolf parameter, there is various ways to use them (<cite>Molodensky</cite>,
+ * <cite>Abridged Molodensky</cite>, <cite>Geocentric translation</cite>, <cite>etc.</cite>).
+ *
+ * <p>EPSG identifies two approaches for addressing this multiplicity problem.
+ * Quoting the GIGS guideline:</p>
+ *
+ * <blockquote>
+ * <ul class="verbose">
+ *   <li><b>Early binding:</b>
+ *     A priori association of a coordinate transformation with a geodetic CRS.
+ *     The association is usually made at start-up of the session or project, as that is defined in the software,
+ *     but always before any data is associated with the ‘CRS’. In general the ‘coordinate transformation’ specified
+ *     uses the ‘CRS’ of the data as the source ‘CRS’ and WGS 84 as the target ‘CRS’.</li>
+ *
+ *   <li><b>Late binding:</b>
+ *     Association at run time of a coordinate transformation with a CRS.
+ *     Late binding allows the user to select the appropriate transformation upon import of ‘geospatial data’
+ *     or merge of two geospatial datasets. This means that, in cases where there are multiple existing transformations,
+ *     the user can choose the appropriate one, possibly aided by additional information.</li>
+ * </ul>
+ * <p style="text-align:right; font-size:small"><b>Source:</b>
+ * <u>Geospatial Integrity of Geoscience Software Part 1 – GIGS guidelines.</u>
+ * <i>OGP publication, Report No. 430-1, September 2011</i></p>
+ * </blockquote>
+ *
+ * Apache SIS is a <cite>late binding</cite> implementation, while a little trace for <cite>early binding</cite>
+ * exists in the form of the {@link org.apache.sis.referencing.datum.DefaultGeodeticDatum#getBursaWolfParameters()}
+ * method for those who really need it. This means that when searching for a coordinate operation between a given
+ * pair of CRS, Apache SIS will query {@link org.apache.sis.referencing.factory.sql.EPSGFactory} before to try to
+ * {@linkplain org.apache.sis.referencing.operation.CoordinateOperationInference infer the operation path by itelf}.
+ * The {@link org.apache.sis.referencing.operation.CoordinateOperationContext} can be used for further refinements,
+ * for example by specifying the area of interest.
+ *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @version 0.7
  * @since   0.6

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java?rev=1737072&r1=1737071&r2=1737072&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java [UTF-8] Tue Mar 29 22:51:40 2016
@@ -251,6 +251,8 @@ public abstract class AbstractMathTransf
      *   <li>Delegates to the {@link #transform(double[], int, double[], int, boolean)} method.</li>
      * </ul>
      *
+     * This method does not update the associated {@link org.opengis.referencing.crs.CoordinateReferenceSystem} value.
+     *
      * @param  ptSrc the coordinate point to be transformed.
      * @param  ptDst the coordinate point that stores the result of transforming {@code ptSrc}, or {@code null}.
      * @return the coordinate point after transforming {@code ptSrc} and storing the result in {@code ptDst},

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform.java?rev=1737072&r1=1737071&r2=1737072&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ConcatenatedTransform.java [UTF-8] Tue Mar 29 22:51:40 2016
@@ -316,8 +316,7 @@ class ConcatenatedTransform extends Abst
             }
         }
         /*
-         * If one transform is the inverse of the
-         * other, returns the identity transform.
+         * If one transform is the inverse of the other, return the identity transform.
          */
         if (areInverse(tr1, tr2) || areInverse(tr2, tr1)) {
             assert tr1.getSourceDimensions() == tr2.getTargetDimensions();
@@ -325,7 +324,7 @@ class ConcatenatedTransform extends Abst
             return MathTransforms.identity(tr1.getSourceDimensions());          // Returns a cached instance.
         }
         /*
-         * Gives a chance to AbstractMathTransform to returns an optimized object.
+         * Give a chance to AbstractMathTransform to returns an optimized object.
          * The main use case is Logarithmic vs Exponential transforms.
          */
         if (tr1 instanceof AbstractMathTransform) {
@@ -348,17 +347,17 @@ class ConcatenatedTransform extends Abst
      * Returns a name for the specified math transform.
      */
     private static String getName(final MathTransform transform) {
+        ParameterValueGroup params = null;
         if (transform instanceof AbstractMathTransform) {
-            ParameterValueGroup params;
             params = ((AbstractMathTransform) transform).getContextualParameters();
-            if (params == null) {
-                params = ((AbstractMathTransform) transform).getParameterValues();
-                if (params != null) {
-                    String name = params.getDescriptor().getName().getCode();
-                    if (name != null && !(name = name.trim()).isEmpty()) {
-                        return name;
-                    }
-                }
+        }
+        if (params == null && (transform instanceof Parameterized)) {
+            params = ((Parameterized) transform).getParameterValues();
+        }
+        if (params != null) {
+            String name = params.getDescriptor().getName().getCode();
+            if (name != null && !(name = name.trim()).isEmpty()) {
+                return name;
             }
         }
         return Classes.getShortClassName(transform);

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java?rev=1737072&r1=1737071&r2=1737072&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java [UTF-8] Tue Mar 29 22:51:40 2016
@@ -460,7 +460,7 @@ public class ContextualParameters extend
             offset = new DoubleDouble(-λ0);
             offset.multiply(toRadians);
         }
-        final MatrixSIS normalize = (MatrixSIS) this.normalize;  // Must be the same instance, not a copy.
+        final MatrixSIS normalize = (MatrixSIS) this.normalize;         // Must be the same instance, not a copy.
         normalize.convertBefore(0, toRadians, offset);
         normalize.convertBefore(1, toRadians, null);
         return normalize;
@@ -485,7 +485,7 @@ public class ContextualParameters extend
     public synchronized MatrixSIS denormalizeGeographicOutputs(final double λ0) {
         ensureModifiable();
         final DoubleDouble toDegrees = DoubleDouble.createRadiansToDegrees();
-        final MatrixSIS denormalize = (MatrixSIS) this.denormalize;  // Must be the same instance, not a copy.
+        final MatrixSIS denormalize = (MatrixSIS) this.denormalize;         // Must be the same instance, not a copy.
         denormalize.convertAfter(0, toDegrees, (λ0 != 0) ? λ0 : null);
         denormalize.convertAfter(1, toDegrees, null);
         return denormalize;
@@ -549,7 +549,7 @@ public class ContextualParameters extend
         final Map<ParameterDescriptor<?>, ParameterValue<?>> parameters = new IdentityHashMap<>(values.length);
         for (ParameterValue<?> p : values) {
             if (p == null) {
-                break;  // The first null value in the array indicates the end of sequence.
+                break;                      // The first null value in the array indicates the end of sequence.
             }
             p = DefaultParameterValue.unmodifiable(p);
             final ParameterDescriptor<?> desc = p.getDescriptor();

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java?rev=1737072&r1=1737071&r2=1737072&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java [UTF-8] Tue Mar 29 22:51:40 2016
@@ -453,13 +453,18 @@ public class DefaultMathTransformFactory
      * {@link DefaultMathTransformFactory} uses this information for:
      *
      * <ul>
-     *   <li>Complete some parameters if they were not provided. In particular, the {@linkplain #getSourceEllipsoid()
+     *   <li>Completing some parameters if they were not provided. In particular, the {@linkplain #getSourceEllipsoid()
      *       source ellipsoid} can be used for providing values for the {@code "semi_major"} and {@code "semi_minor"}
      *       parameters in map projections.</li>
-     *   <li>{@linkplain CoordinateSystems#swapAndScaleAxes Swap and scale axes} if the source or the target
+     *   <li>{@linkplain CoordinateSystems#swapAndScaleAxes Swapping and scaling axes} if the source or the target
      *       coordinate systems are not {@linkplain AxesConvention#NORMALIZED normalized}.</li>
      * </ul>
      *
+     * By default this class does <strong>not</strong> handle change of
+     * {@linkplain org.apache.sis.referencing.datum.DefaultGeodeticDatum#getPrimeMeridian() prime meridian}
+     * or anything else related to datum. Datum changes have dedicated {@link OperationMethod},
+     * for example <cite>"Longitude rotation"</cite> (EPSG:9601) for changing the prime meridian.
+     *
      * @author  Martin Desruisseaux (Geomatys)
      * @version 0.7
      * @since   0.7
@@ -505,17 +510,6 @@ public class DefaultMathTransformFactory
         }
 
         /**
-         * Sets the source ellipsoid to the given value.
-         * The source coordinate system is unconditionally set to {@code null}.
-         *
-         * @param ellipsoid The ellipsoid to set as the source (can be {@code null}).
-         */
-        public void setSource(final Ellipsoid ellipsoid) {
-            sourceEllipsoid = ellipsoid;
-            sourceCS = null;
-        }
-
-        /**
          * Sets the source coordinate system to the given value.
          * The source ellipsoid is unconditionally set to {@code null}.
          *
@@ -527,26 +521,23 @@ public class DefaultMathTransformFactory
         }
 
         /**
-         * Sets the source ellipsoid and coordinate system to values inferred from the given CRS.
-         * The source ellipsoid will be non-null only if the given CRS is geographic (not geocentric).
+         * Sets the source coordinate system and its associated ellipsoid to the given value.
          *
-         * @param crs The source coordinate reference system (can be {@code null}).
-         */
-        public void setSource(final CoordinateReferenceSystem crs) {
-            sourceCS = (crs != null) ? crs.getCoordinateSystem() : null;
-            sourceEllipsoid = ReferencingUtilities.getEllipsoidOfGeographicCRS(crs);
-            // Ellipsoid is intentionally null for GeocentricCRS.
-        }
-
-        /**
-         * Sets the target ellipsoid to the given value.
-         * The target coordinate system is unconditionally set to {@code null}.
+         * <div class="note"><b>Design note:</b>
+         * ellipsoidal coordinate systems and ellipsoids are associated indirectly, through a geodetic CRS.
+         * However this method expects those two components to be given explicitely instead than inferring
+         * them from a {@code CoordinateReferenceSystem} for making clear that {@code MathTransformFactory}
+         * does not perform any {@linkplain org.apache.sis.referencing.datum.DefaultGeodeticDatum geodetic
+         * datum} analysis. For coordinate operations that take datum changes in account (including change
+         * of prime meridian), see {@link org.apache.sis.referencing.operation.DefaultCoordinateOperationFactory}.
+         * This policy helps to enforce a separation of concerns.</div>
          *
-         * @param ellipsoid The ellipsoid to set as the target (can be {@code null}).
+         * @param cs The coordinate system to set as the source, or {@code null}.
+         * @param ellipsoid The ellipsoid associated to the given coordinate system, or {@code null}.
          */
-        public void setTarget(final Ellipsoid ellipsoid) {
-            targetEllipsoid = ellipsoid;
-            targetCS = null;
+        public void setSource(final EllipsoidalCS cs, final Ellipsoid ellipsoid) {
+            sourceCS = cs;
+            sourceEllipsoid = ellipsoid;
         }
 
         /**
@@ -561,15 +552,17 @@ public class DefaultMathTransformFactory
         }
 
         /**
-         * Sets the target ellipsoid and coordinate system to values inferred from the given CRS.
-         * The target ellipsoid will be non-null only if the given CRS is geographic (not geocentric).
+         * Sets the target coordinate system and its associated ellipsoid to the given value.
+         *
+         * <div class="note"><b>Design note:</b>
+         * see {@link #setSource(EllipsoidalCS, Ellipsoid)}.</div>
          *
-         * @param crs The target coordinate reference system (can be {@code null}).
+         * @param cs The coordinate system to set as the source, or {@code null}.
+         * @param ellipsoid The ellipsoid associated to the given coordinate system, or {@code null}.
          */
-        public void setTarget(final CoordinateReferenceSystem crs) {
-            targetCS = (crs != null) ? crs.getCoordinateSystem() : null;
-            targetEllipsoid = ReferencingUtilities.getEllipsoidOfGeographicCRS(crs);
-            // Ellipsoid is intentionally null for GeocentricCRS.
+        public void setTarget(final EllipsoidalCS cs, final Ellipsoid ellipsoid) {
+            targetCS = cs;
+            targetEllipsoid = ellipsoid;
         }
 
         /**
@@ -611,6 +604,66 @@ public class DefaultMathTransformFactory
         }
 
         /**
+         * Returns the matrix that represent the affine transform to concatenate before or after
+         * the parameterized transform. The {@code role} argument specifies which matrix is desired:
+         *
+         * <ul class="verbose">
+         *   <li>{@link org.apache.sis.referencing.operation.transform.ContextualParameters.MatrixRole#NORMALIZATION
+         *       NORMALIZATION} for the conversion from the {@linkplain #getSourceCS() source coordinate system} to
+         *       a {@linkplain AxesConvention#NORMALIZED normalized} coordinate system, usually with
+         *       (<var>longitude</var>, <var>latitude</var>) axis order in degrees or
+         *       (<var>easting</var>, <var>northing</var>) in metres.
+         *       This normalization needs to be applied <em>before</em> the parameterized transform.</li>
+         *
+         *   <li>{@link org.apache.sis.referencing.operation.transform.ContextualParameters.MatrixRole#DENORMALIZATION
+         *       DENORMALIZATION} for the conversion from a normalized coordinate system to the
+         *       {@linkplain #getTargetCS() target coordinate system}, for example with
+         *       (<var>latitude</var>, <var>longitude</var>) axis order.
+         *       This denormalization needs to be applied <em>after</em> the parameterized transform.</li>
+         *
+         *   <li>{@link org.apache.sis.referencing.operation.transform.ContextualParameters.MatrixRole#INVERSE_NORMALIZATION INVERSE_NORMALIZATION} and
+         *       {@link org.apache.sis.referencing.operation.transform.ContextualParameters.MatrixRole#INVERSE_DENORMALIZATION INVERSE_DENORMALIZATION}
+         *       are also supported but rarely used.</li>
+         * </ul>
+         *
+         * This method is invoked by {@link DefaultMathTransformFactory#swapAndScaleAxes(MathTransform, Context)}.
+         * Users an override this method if they need to customize the normalization process.
+         *
+         * @param  role Whether the normalization or denormalization matrix is desired.
+         * @return The requested matrix, or {@code null} if this {@code Context} has no information about the coordinate system.
+         * @throws FactoryException if an error occurred while computing the matrix.
+         *
+         * @see DefaultMathTransformFactory#createAffineTransform(Matrix)
+         * @see DefaultMathTransformFactory#createParameterizedTransform(ParameterValueGroup, Context)
+         */
+        @SuppressWarnings("fallthrough")
+        public Matrix getMatrix(final ContextualParameters.MatrixRole role) throws FactoryException {
+            final CoordinateSystem specified;
+            boolean inverse = false;
+            switch (role) {
+                default: throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2, "role", role));
+                case INVERSE_NORMALIZATION:   inverse   = true;          // Fall through
+                case NORMALIZATION:           specified = getSourceCS(); break;
+                case INVERSE_DENORMALIZATION: inverse   = true;          // Fall through
+                case DENORMALIZATION:         inverse   = !inverse;
+                                              specified = getTargetCS(); break;
+            }
+            if (specified == null) {
+                return null;
+            }
+            final CoordinateSystem normalized = CoordinateSystems.replaceAxes(specified, AxesConvention.NORMALIZED);
+            try {
+                if (inverse) {
+                    return CoordinateSystems.swapAndScaleAxes(normalized, specified);
+                } else {
+                    return CoordinateSystems.swapAndScaleAxes(specified, normalized);
+                }
+            } catch (IllegalArgumentException | ConversionException cause) {
+                throw new InvalidGeodeticParameterException(cause.getLocalizedMessage(), cause);
+            }
+        }
+
+        /**
          * Returns the parameter values used for the math transform creation, including the parameters completed
          * by the factory.
          *
@@ -968,7 +1021,7 @@ public class DefaultMathTransformFactory
 
     /**
      * Given a transform between normalized spaces,
-     * create a transform taking in account axis directions and units of measurement.
+     * creates a transform taking in account axis directions, units of measurement and longitude rotation.
      * This method {@linkplain #createConcatenatedTransform concatenates} the given parameterized transform
      * with any other transform required for performing units changes and ordinates swapping.
      *
@@ -984,6 +1037,10 @@ public class DefaultMathTransformFactory
      * both of them with ({@linkplain org.opengis.referencing.cs.AxisDirection#EAST East},
      * {@linkplain org.opengis.referencing.cs.AxisDirection#NORTH North}) axis orientations.</div>
      *
+     * <div class="section">Controlling the normalization process</div>
+     * Users who need a different normalized space than the default one way find more convenient to
+     * override the {@link Context#getMatrix Context.getMatrix(ContextualParameters.MatrixRole)} method.
+     *
      * @param  parameterized A transform for normalized input and output coordinates.
      * @param  context Source and target coordinate systems in which the transform is going to be used.
      * @return A transform taking in account unit conversions and axis swapping.
@@ -991,25 +1048,20 @@ public class DefaultMathTransformFactory
      *
      * @see org.apache.sis.referencing.cs.AxesConvention#NORMALIZED
      * @see org.apache.sis.referencing.operation.DefaultConversion#DefaultConversion(Map, OperationMethod, MathTransform, ParameterValueGroup)
+     *
+     * @since 0.7
      */
     public MathTransform swapAndScaleAxes(final MathTransform parameterized, final Context context) throws FactoryException {
         ArgumentChecks.ensureNonNull("parameterized", parameterized);
         ArgumentChecks.ensureNonNull("context", context);
-        final CoordinateSystem sourceCS = context.getSourceCS();
-        final CoordinateSystem targetCS = context.getTargetCS();
         /*
          * Computes matrix for swapping axis and performing units conversion.
          * There is one matrix to apply before projection on (longitude,latitude)
          * coordinates, and one matrix to apply after projection on (easting,northing)
          * coordinates.
          */
-        final Matrix swap1, swap3;
-        try {
-            swap1 = (sourceCS != null) ? CoordinateSystems.swapAndScaleAxes(sourceCS, CoordinateSystems.replaceAxes(sourceCS, AxesConvention.NORMALIZED)) : null;
-            swap3 = (targetCS != null) ? CoordinateSystems.swapAndScaleAxes(CoordinateSystems.replaceAxes(targetCS, AxesConvention.NORMALIZED), targetCS) : null;
-        } catch (IllegalArgumentException | ConversionException cause) {
-            throw new InvalidGeodeticParameterException(cause.getLocalizedMessage(), cause);
-        }
+        final Matrix swap1 = context.getMatrix(ContextualParameters.MatrixRole.NORMALIZATION);
+        final Matrix swap3 = context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION);
         /*
          * Prepares the concatenation of the matrices computed above and the projection.
          * Note that at this stage, the dimensions between each step may not be compatible.
@@ -1089,8 +1141,7 @@ public class DefaultMathTransformFactory
         ArgumentChecks.ensureNonNull("baseCRS",    baseCRS);
         ArgumentChecks.ensureNonNull("parameters", parameters);
         ArgumentChecks.ensureNonNull("derivedCS",  derivedCS);
-        final Context context = new Context();
-        context.setSource(baseCRS);
+        final Context context = ReferencingUtilities.createTransformContext(baseCRS, null, null);
         context.setTarget(derivedCS);
         return createParameterizedTransform(parameters, context);
     }
@@ -1125,6 +1176,25 @@ public class DefaultMathTransformFactory
     }
 
     /**
+     * Creates a math transform that represent a change of coordinate system.
+     *
+     * @param source the source coordinate system.
+     * @param target the target coordinate system.
+     * @return a conversion from the given source to the given target coordinate system.
+     * @throws FactoryException if the conversion can not be created.
+     *
+     * @since 0.7
+     */
+    public MathTransform createCoordinateSystemChange(final CoordinateSystem source, final CoordinateSystem target)
+            throws FactoryException
+    {
+        ArgumentChecks.ensureNonNull("source", source);
+        ArgumentChecks.ensureNonNull("target", target);
+        return CoordinateSystemTransform.create(this, source, target);
+        // No need to use unique(…) here.
+    }
+
+    /**
      * Creates an affine transform from a matrix. If the transform input dimension is {@code M},
      * and output dimension is {@code N}, then the matrix will have size {@code [N+1][M+1]}. The
      * +1 in the matrix dimensions allows the matrix to do a shift, as well as a rotation. The
@@ -1140,7 +1210,11 @@ public class DefaultMathTransformFactory
      */
     @Override
     public MathTransform createAffineTransform(final Matrix matrix) throws FactoryException {
-        lastMethod.remove(); // To be strict, we should set the ProjectiveTransform provider.
+        /*
+         * Performance note: we could set lastMethod to the "Affine" operation method provider, but we do not
+         * because setting this value is not free (e.g. it depends on matrix size) and it is rarely needed.
+         */
+        lastMethod.remove();
         return unique(MathTransforms.linear(matrix));
     }
 

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java?rev=1737072&r1=1737071&r2=1737072&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java [UTF-8] Tue Mar 29 22:51:40 2016
@@ -46,6 +46,7 @@ import org.apache.sis.internal.referenci
 import org.apache.sis.internal.referencing.provider.GeocentricToGeographic;
 import org.apache.sis.internal.referencing.provider.GeographicToGeocentric;
 import org.apache.sis.internal.referencing.provider.Geographic3Dto2D;
+import org.apache.sis.internal.metadata.ReferencingServices;
 import org.apache.sis.parameter.DefaultParameterDescriptorGroup;
 import org.apache.sis.metadata.iso.ImmutableIdentifier;
 import org.apache.sis.referencing.operation.matrix.Matrix3;
@@ -347,6 +348,19 @@ public class EllipsoidToCentricTransform
             final double semiMajor, final double semiMinor, final Unit<Length> unit,
             final boolean withHeight, final TargetType target) throws FactoryException
     {
+        if (Math.abs(semiMajor - semiMinor) <= semiMajor * (Formulas.LINEAR_TOLERANCE / ReferencingServices.AUTHALIC_RADIUS)) {
+            /*
+             * If semi-major axis length is almost equal to semi-minor axis length, uses spherical equations instead.
+             * We need to add the sphere radius to the elevation before to perform spherical to Cartesian conversion.
+             */
+            final MatrixSIS translate = Matrices.createDiagonal(4, withHeight ? 4 : 3);
+            translate.setElement(2, withHeight ? 3 : 2, semiMajor);
+            if (!withHeight) {
+                translate.setElement(3, 2, 1);
+            }
+            final MathTransform tr = SphericalToCartesian.INSTANCE.completeTransform(factory);
+            return factory.createConcatenatedTransform(factory.createAffineTransform(translate), tr);
+        }
         EllipsoidToCentricTransform tr = new EllipsoidToCentricTransform(semiMajor, semiMinor, unit, withHeight, target);
         return tr.context.completeTransform(factory, tr);
     }
@@ -615,7 +629,7 @@ public class EllipsoidToCentricTransform
     /*
      * NOTE: we do not bother to override the methods expecting a 'float' array because those methods should
      *       be rarely invoked. Since there is usually LinearTransforms before and after this transform, the
-     *       conversion between float and double will be handle by those LinearTransforms.   If nevertheless
+     *       conversion between float and double will be handled by those LinearTransforms.  If nevertheless
      *       this EllipsoidToCentricTransform is at the beginning or the end of a transformation chain,
      *       the methods inherited from the subclass will work (but may be slightly slower).
      */

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedMolodenskyTransform.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedMolodenskyTransform.java?rev=1737072&r1=1737071&r2=1737072&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedMolodenskyTransform.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedMolodenskyTransform.java [UTF-8] Tue Mar 29 22:51:40 2016
@@ -305,7 +305,7 @@ public class InterpolatedMolodenskyTrans
     /*
      * NOTE: we do not bother to override the methods expecting a 'float' array because those methods should
      *       be rarely invoked. Since there is usually LinearTransforms before and after this transform, the
-     *       conversion between float and double will be handle by those LinearTransforms.   If nevertheless
+     *       conversion between float and double will be handled by those LinearTransforms.  If nevertheless
      *       this MolodenskyTransform is at the beginning or the end of a transformation chain,  the methods
      *       inherited from the subclass will work (but may be slightly slower).
      */




Mime
View raw message