Author: desruisseaux
Date: Mon Jul  6 11:13:05 2015
New Revision: 1689367

URL: http://svn.apache.org/r1689367
Log:
Merge CoordinateOperation parsing from JDK7 branch.

Added:
    
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/OperationPathFinder.java
      - copied unchanged from r1689365, 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/OperationPathFinder.java
Modified:
    sis/branches/JDK6/   (props changed)
    
sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
    
sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java
    
sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
    
sis/branches/JDK6/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/ElementTest.java
    
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java
    
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Affine.java
    
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConicProjection.java
    
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
    
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCylindricalProjection.java
    
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPlanarProjection.java
    
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultProjection.java
    
sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/AffineTest.java
    
sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java

Propchange: sis/branches/JDK6/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Jul  6 11:13:05 2015
@@ -1,4 +1,4 @@
 /sis/branches/Android:1430670-1480699
-/sis/branches/JDK7:1394913-1689050
-/sis/branches/JDK8:1584960-1689049
+/sis/branches/JDK7:1394913-1689365
+/sis/branches/JDK8:1584960-1689363
 /sis/trunk:1394364-1508466,1519089-1519674

Modified: 
sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java?rev=1689367&r1=1689366&r2=1689367&view=diff
==============================================================================
--- 
sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
 [UTF-8] (original)
+++ 
sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
 [UTF-8] Mon Jul  6 11:13:05 2015
@@ -24,6 +24,7 @@ import org.opengis.geometry.Envelope;
 import org.opengis.metadata.Identifier;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.crs.SingleCRS;
 import org.opengis.referencing.crs.DerivedCRS;
 import org.opengis.referencing.crs.VerticalCRS;
@@ -36,7 +37,9 @@ import org.opengis.referencing.operation
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.operation.CoordinateOperationFactory;
 import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.referencing.operation.SingleOperation;
 import org.opengis.referencing.operation.TransformException;
+import org.opengis.util.FactoryException;
 import org.apache.sis.metadata.iso.extent.DefaultExtent;
 import org.apache.sis.metadata.iso.extent.DefaultVerticalExtent;
 import org.apache.sis.metadata.iso.extent.DefaultTemporalExtent;
@@ -92,6 +95,15 @@ public class ReferencingServices extends
     public static final String PARAMETERS_KEY = "parameters";
 
     /**
+     * The key for specifying the base type of the coordinate operation to 
create. This optional entry
+     * is used by {@code 
DefaultCoordinateOperationFactory.createSingleOperation(…)}. Apache SIS tries
+     * to infer this value automatically, but this entry may help SIS to 
perform a better choice in
+     * some cases. For example an "Affine" operation can be both a conversion 
or a transformation
+     * (the later is used in datum shift in geocentric coordinates).
+     */
+    public static final String OPERATION_TYPE_KEY = "operationType";
+
+    /**
      * The key for specifying a {@linkplain 
org.opengis.referencing.operation.MathTransformFactory}
      * instance to use for the construction of a geodetic object. This is 
usually not needed for CRS
      * construction, except in the special case of a derived CRS created from 
a defining conversion.
@@ -422,6 +434,32 @@ public class ReferencingServices extends
     }
 
     /**
+     * Creates a single operation from the given properties.
+     * This method is provided here because not yet available in GeoAPI 
interfaces.
+     *
+     * @param  properties The properties to be given to the identified object.
+     * @param  sourceCRS  The source CRS.
+     * @param  targetCRS  The target CRS.
+     * @param  interpolationCRS The CRS of additional coordinates needed for 
the operation, or {@code null} if none.
+     * @param  method     The coordinate operation method (mandatory in all 
cases).
+     * @param  factory    The factory to use.
+     * @return The coordinate operation created from the given arguments.
+     * @throws FactoryException if the object creation failed.
+     *
+     * @since 0.6
+     */
+    public SingleOperation createSingleOperation(
+            final Map<String,?>              properties,
+            final CoordinateReferenceSystem  sourceCRS,
+            final CoordinateReferenceSystem  targetCRS,
+            final CoordinateReferenceSystem  interpolationCRS,
+            final OperationMethod            method,
+            final CoordinateOperationFactory factory) throws FactoryException
+    {
+        throw moduleNotFound();
+    }
+
+    /**
      * Returns the coordinate operation factory to use for the given 
properties and math transform factory.
      * If the given properties are empty and the {@code mtFactory} is the 
system default, then this method
      * returns the system default {@code CoordinateOperationFactory} instead 
of creating a new one.

Modified: 
sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java?rev=1689367&r1=1689366&r2=1689367&view=diff
==============================================================================
--- 
sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java
 [UTF-8] (original)
+++ 
sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java
 [UTF-8] Mon Jul  6 11:13:05 2015
@@ -211,7 +211,12 @@ final class Element {
                     }
                     lower = upper + n;  // After the closing quote.
                 } while (lower < text.length() && text.codePointAt(lower) == 
closingQuote);
-                list.add(content.toString());
+                /*
+                 * Leading and trailing spaces should be ignored according ISO 
19162 §B.4.
+                 * Note that the specification suggests also to replace 
consecutive white
+                 * spaces by a single space, but we don't do that yet.
+                 */
+                list.add(CharSequences.trimWhitespaces(content).toString());
             } else if (!Character.isUnicodeIdentifierStart(firstChar)) {
                 /*
                  * Try to parse the next element as a date or a number. We 
will attempt such parsing

Modified: 
sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java?rev=1689367&r1=1689366&r2=1689367&view=diff
==============================================================================
--- 
sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
 [UTF-8] (original)
+++ 
sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
 [UTF-8] Mon Jul  6 11:13:05 2015
@@ -669,7 +669,7 @@ final class GeodeticObjectParser extends
             final Element element = parent.pullElement(OPTIONAL, 
WKTKeywords.CS);
             if (element != null) {
                 final String expected = type;
-                type         = 
CharSequences.trimWhitespaces(element.pullVoidElement("type").keyword);
+                type         = element.pullVoidElement("type").keyword;
                 dimension    = element.pullInteger("dimension");
                 csProperties = new 
HashMap<String,Object>(parseMetadataAndClose(element, "CS", null));
                 if (expected != null) {
@@ -952,7 +952,7 @@ final class GeodeticObjectParser extends
          * expressed by a syntax like AXIS[“South along 90°W”, SOUTH, 
MERIDIAN[-90, UNIT["deg"]]]. Note that
          * the meridian is relative to the prime meridian of the enclosing 
geodetic CRS.
          */
-        String name = 
CharSequences.trimWhitespaces(element.pullString("name"));
+        String name = element.pullString("name");
         final Element orientation = element.pullVoidElement("orientation");
         Unit<?> unit = parseUnit(element);
         if (unit == null) {
@@ -1251,7 +1251,7 @@ final class GeodeticObjectParser extends
             }
             name = parent.pullString("name");
         }
-        OperationMethod method = parseMethod(parent, WKTKeywords.Method, 
WKTKeywords.Projection);
+        final OperationMethod method = parseMethod(parent, WKTKeywords.Method, 
WKTKeywords.Projection);
         Map<String,?> properties = this.properties;  // Same properties then 
OperationMethod, with ID removed.
         /*
          * Set the list of parameters.
@@ -2078,15 +2078,20 @@ final class GeodeticObjectParser extends
         final CoordinateReferenceSystem sourceCRS        = 
parseCoordinateReferenceSystem(element, MANDATORY, WKTKeywords.SourceCRS);
         final CoordinateReferenceSystem targetCRS        = 
parseCoordinateReferenceSystem(element, MANDATORY, WKTKeywords.TargetCRS);
         final CoordinateReferenceSystem interpolationCRS = 
parseCoordinateReferenceSystem(element, OPTIONAL,  
WKTKeywords.InterpolationCRS);
-        final OperationMethod           method           = parseMethod(parent, 
WKTKeywords.Method);
-        final Element                   accuracy         = 
parent.pullElement(OPTIONAL, WKTKeywords.OperationAccuracy);
-        final Map<String,Object>        properties       = 
parseMetadataAndClose(parent, name, method);
+        final OperationMethod           method           = 
parseMethod(element, WKTKeywords.Method);
+        final Element                   accuracy         = 
element.pullElement(OPTIONAL, WKTKeywords.OperationAccuracy);
+        final Map<String,Object>        properties       = 
parseMetadataAndClose(element, name, method);
         final ParameterValueGroup       parameters       = 
method.getParameters().createValue();
-        parseParameters(parent, parameters, null, null);
+        parseParameters(element, parameters, null, null);
+        properties.put(ReferencingServices.PARAMETERS_KEY, parameters);
         if (accuracy != null) {
             accuracy.pullDouble("accuracy");    // TODO: share the code from 
EPSG factory.
             accuracy.close(ignoredElements);
         }
-        return null;    // Not yet implemented.
+        try {
+            return referencing.createSingleOperation(properties, sourceCRS, 
targetCRS, interpolationCRS, method, opFactory);
+        } catch (FactoryException e) {
+            throw element.parseFailed(e);
+        }
     }
 }

Modified: 
sis/branches/JDK6/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/ElementTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/ElementTest.java?rev=1689367&r1=1689366&r2=1689367&view=diff
==============================================================================
--- 
sis/branches/JDK6/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/ElementTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK6/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/ElementTest.java
 [UTF-8] Mon Jul  6 11:13:05 2015
@@ -83,10 +83,10 @@ public final strictfp class ElementTest
         assertEquals("value", "World Geodetic System 1984", 
element.pullString("value"));
         element.close(null);
 
-        // Spaces inside quotes should be preserved.
+        // Leading and trailing spaces inside quotes should be ignored (ISO 
19162 §B.4).
         element = parse("  Datum [  \" World Geodetic System 1984  \"  ]  ");
         assertEquals("keyword", "Datum", element.keyword);
-        assertEquals("value", " World Geodetic System 1984  ", 
element.pullString("value"));
+        assertEquals("value", "World Geodetic System 1984", 
element.pullString("value"));
         element.close(null);
 
         // Consecutive values.

Modified: 
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java?rev=1689367&r1=1689366&r2=1689367&view=diff
==============================================================================
--- 
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java
 [UTF-8] (original)
+++ 
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java
 [UTF-8] Mon Jul  6 11:13:05 2015
@@ -41,6 +41,7 @@ import org.opengis.referencing.operation
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.operation.TransformException;
 import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.referencing.operation.SingleOperation;
 import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.operation.CoordinateOperationFactory;
 import org.opengis.metadata.extent.GeographicBoundingBox;
@@ -570,6 +571,39 @@ public final class ServicesForMetadata e
     }
 
     /**
+     * Creates a single operation from the given properties.
+     * This method is provided here because not yet available in GeoAPI 
interfaces.
+     *
+     * @param  properties The properties to be given to the identified object.
+     * @param  sourceCRS  The source CRS.
+     * @param  targetCRS  The target CRS.
+     * @param  interpolationCRS The CRS of additional coordinates needed for 
the operation, or {@code null} if none.
+     * @param  method     The coordinate operation method (mandatory in all 
cases).
+     * @param  factory    The factory to use.
+     * @return The coordinate operation created from the given arguments.
+     * @throws FactoryException if the object creation failed.
+     *
+     * @since 0.6
+     */
+    @Override
+    public SingleOperation createSingleOperation(
+            final Map<String,?>              properties,
+            final CoordinateReferenceSystem  sourceCRS,
+            final CoordinateReferenceSystem  targetCRS,
+            final CoordinateReferenceSystem  interpolationCRS,
+            final OperationMethod            method,
+            final CoordinateOperationFactory factory) throws FactoryException
+    {
+        final DefaultCoordinateOperationFactory df;
+        if (factory instanceof DefaultCoordinateOperationFactory) {
+            df = (DefaultCoordinateOperationFactory) factory;
+        } else {
+            df = DefaultFactories.forBuildin(CoordinateOperationFactory.class, 
DefaultCoordinateOperationFactory.class);
+        }
+        return df.createSingleOperation(properties, sourceCRS, targetCRS, 
interpolationCRS, method, null);
+    }
+
+    /**
      * Returns the coordinate operation factory to use for the given 
properties and math transform factory.
      * If the given properties are empty and the {@code mtFactory} is the 
system default, then this method
      * returns the system default {@code CoordinateOperationFactory} instead 
of creating a new one.

Modified: 
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Affine.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Affine.java?rev=1689367&r1=1689366&r2=1689367&view=diff
==============================================================================
--- 
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Affine.java
 [UTF-8] (original)
+++ 
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Affine.java
 [UTF-8] Mon Jul  6 11:13:05 2015
@@ -23,7 +23,6 @@ import org.opengis.parameter.ParameterVa
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterNotFoundException;
 import org.opengis.referencing.operation.Matrix;
-import org.opengis.referencing.operation.Conversion;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.operation.OperationMethod;
@@ -168,15 +167,13 @@ public final class Affine extends Abstra
         }
     }
 
-    /**
-     * Returns the type of operations created by this provider.
-     *
-     * @return Always {@code Conversion.class} for this provider.
+    /*
+     * Do not override the 'getOperationType()' method. We want to inherit the 
super-type value, which is
+     * SingleOperation.class, because we do not know if this operation method 
will be used for a Conversion
+     * or a Transformation. When applied on geocentric coordinates, this 
method applies a transformation
+     * (indeeded, the EPSG method name is "Affine parametric transformation"). 
But this method can also
+     * be applied for unit conversions or axis swapping for examples, which 
are conversions.
      */
-    @Override
-    public Class<Conversion> getOperationType() {
-        return Conversion.class;
-    }
 
     /**
      * Creates a projective transform from the specified group of parameter 
values.

Modified: 
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConicProjection.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConicProjection.java?rev=1689367&r1=1689366&r2=1689367&view=diff
==============================================================================
--- 
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConicProjection.java
 [UTF-8] (original)
+++ 
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConicProjection.java
 [UTF-8] Mon Jul  6 11:13:05 2015
@@ -16,12 +16,17 @@
  */
 package org.apache.sis.referencing.operation;
 
+import java.util.Map;
 import javax.xml.bind.annotation.XmlTransient;
 import org.opengis.util.FactoryException;
 import org.opengis.referencing.operation.Conversion;
 import org.opengis.referencing.operation.ConicProjection;
+import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.crs.GeographicCRS;
+import org.opengis.referencing.crs.ProjectedCRS;
 
 
 /**
@@ -43,6 +48,24 @@ final class DefaultConicProjection exten
     private static final long serialVersionUID = -8717453834398763963L;
 
     /**
+     * Creates a projection from the given properties.
+     *
+     * @param properties The properties to be given to the identified object.
+     * @param sourceCRS  The source CRS.
+     * @param targetCRS  The target CRS.
+     * @param method     The coordinate operation method.
+     * @param transform  Transform from positions in the source CRS to 
positions in the target CRS.
+     */
+    public DefaultConicProjection(final Map<String,?>   properties,
+                                  final GeographicCRS   sourceCRS,
+                                  final ProjectedCRS    targetCRS,
+                                  final OperationMethod method,
+                                  final MathTransform   transform)
+    {
+        super(properties, sourceCRS, targetCRS, method, transform);
+    }
+
+    /**
      * Creates a new projection with the same values than the specified one, 
together with the
      * specified source and target CRS. While the source conversion can be an 
arbitrary one, it
      * is typically a defining conversion.

Modified: 
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java?rev=1689367&r1=1689366&r2=1689367&view=diff
==============================================================================
--- 
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
 [UTF-8] (original)
+++ 
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
 [UTF-8] Mon Jul  6 11:13:05 2015
@@ -26,16 +26,20 @@ import org.opengis.parameter.ParameterDe
 import org.opengis.referencing.operation.*;
 import org.opengis.referencing.IdentifiedObject;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.crs.GeographicCRS;
+import org.opengis.referencing.crs.ProjectedCRS;
 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.referencing.operation.transform.DefaultMathTransformFactory;
 import org.apache.sis.util.collection.WeakHashSet;
+import org.apache.sis.util.collection.Containers;
 import org.apache.sis.util.iso.AbstractFactory;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.NullArgumentException;
 
 
 /**
@@ -203,7 +207,7 @@ public class DefaultCoordinateOperationF
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
      *     <td>{@link DefaultOperationMethod#getName()}</td>
      *   </tr>
      *   <tr>
@@ -213,7 +217,7 @@ public class DefaultCoordinateOperationF
      *   </tr>
      *   <tr>
      *     <td>{@value 
org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.metadata.Identifier} (optionally as 
array)</td>
      *     <td>{@link DefaultOperationMethod#getIdentifiers()}</td>
      *   </tr>
      *   <tr>
@@ -247,7 +251,7 @@ public class DefaultCoordinateOperationF
     }
 
     /**
-     * Constructs a defining conversion from the given operation parameters.
+     * Creates a defining conversion from the given operation parameters.
      * This conversion has no source and target CRS since those elements are 
usually unknown at this stage.
      * The source and target CRS will become known later, at the
      * {@linkplain org.apache.sis.referencing.crs.DefaultDerivedCRS Derived 
CRS} or
@@ -308,6 +312,171 @@ public class DefaultCoordinateOperationF
     }
 
     /**
+     * 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
+     * ({@link CylindricalProjection}, {@link ConicProjection} or {@link 
PlanarProjection})
+     * using the {@linkplain DefaultOperationMethod#getOperationType() 
information provided by the given method}.
+     *
+     * <p>The properties given in argument follow the same rules than for the
+     * {@linkplain 
AbstractCoordinateOperation#AbstractCoordinateOperation(Map, 
CoordinateReferenceSystem,
+     * CoordinateReferenceSystem, CoordinateReferenceSystem, MathTransform) 
coordinate operation} constructor.
+     * The following table is a reminder of main (not all) properties:</p>
+     *
+     * <table class="sis">
+     *   <caption>Recognized properties (non exhaustive list)</caption>
+     *   <tr>
+     *     <th>Property name</th>
+     *     <th>Value type</th>
+     *     <th>Returned by</th>
+     *   </tr>
+     *   <tr>
+     *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
+     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link DefaultConversion#getName()}</td>
+     *   </tr>
+     *   <tr>
+     *     <td>{@value 
org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
+     *     <td>{@link org.opengis.metadata.Identifier} (optionally as 
array)</td>
+     *     <td>{@link DefaultConversion#getIdentifiers()}</td>
+     *   </tr>
+     *   <tr>
+     *     <td>{@value 
org.opengis.referencing.operation.CoordinateOperation#DOMAIN_OF_VALIDITY_KEY}</td>
+     *     <td>{@link org.opengis.metadata.extent.Extent}</td>
+     *     <td>{@link DefaultConversion#getDomainOfValidity()}</td>
+     *   </tr>
+     * </table>
+     *
+     * @param  properties The properties to be given to the identified object.
+     * @param  sourceCRS  The source CRS.
+     * @param  targetCRS  The target CRS.
+     * @param  interpolationCRS The CRS of additional coordinates needed for 
the operation, or {@code null} if none.
+     * @param  method     The coordinate operation method (mandatory in all 
cases).
+     * @param  transform  Transform from positions in the source CRS to 
positions in the target CRS.
+     * @return The coordinate operation created from the given arguments.
+     * @throws FactoryException if the object creation failed.
+     *
+     * @see DefaultOperationMethod#getOperationType()
+     * @see DefaultTransformation
+     * @see DefaultConversion
+     */
+    public SingleOperation createSingleOperation(
+            final Map<String,?>             properties,
+            final CoordinateReferenceSystem sourceCRS,
+            final CoordinateReferenceSystem targetCRS,
+            final CoordinateReferenceSystem interpolationCRS,
+            final OperationMethod           method,
+                  MathTransform             transform) throws FactoryException
+    {
+        ArgumentChecks.ensureNonNull("sourceCRS", sourceCRS);
+        ArgumentChecks.ensureNonNull("targetCRS", targetCRS);
+        ArgumentChecks.ensureNonNull("method",    method);
+        /*
+         * Undocumented (for now) feature: if the 'transform' argument is null 
but parameters are
+         * found in the given properties, create the MathTransform instance 
from those parameters.
+         * This is needed for WKT parsing of CoordinateOperation[…] among 
others.
+         */
+        if (transform == null) {
+            final ParameterValueGroup parameters = 
Containers.property(properties,
+                    ReferencingServices.PARAMETERS_KEY, 
ParameterValueGroup.class);
+            if (parameters == null) {
+                throw new 
NullArgumentException(Errors.format(Errors.Keys.NullArgument_1, "transform"));
+            }
+            transform = mtFactory.createBaseToDerived(sourceCRS, parameters, 
targetCRS.getCoordinateSystem());
+        }
+        /*
+         * The "operationType" property is currently undocumented. The intend 
is to help this factory method in
+         * situations where the given operation method is not an Apache SIS 
implementation or does not override
+         * getOperationType(), or the method is ambiguous (e.g. "Affine" can 
be used for both a transformation
+         * or a conversion).
+         *
+         * If we have both a 'baseType' and a Method.getOperationType(), take 
the most specific type.
+         * An exception will be thrown if the two types are incompatible.
+         */
+        Class<?> baseType = Containers.property(properties, 
ReferencingServices.OPERATION_TYPE_KEY, Class.class);
+        if (baseType == null) {
+            baseType = SingleOperation.class;
+        }
+        if (method instanceof DefaultOperationMethod) {
+            final Class<? extends SingleOperation> c = 
((DefaultOperationMethod) method).getOperationType();
+            if (c != null) {  // Paranoiac check (above method should not 
return null).
+                if (baseType.isAssignableFrom(c)) {
+                    baseType = c;
+                } else if (!c.isAssignableFrom(baseType)) {
+                    throw new 
IllegalArgumentException(Errors.format(Errors.Keys.IncompatiblePropertyValue_1,
+                            ReferencingServices.OPERATION_TYPE_KEY));
+                }
+            }
+        }
+        /*
+         * If the base type is still abstract (probably because it was not 
specified neither in the given OperationMethod
+         * or in the properties), then try to find a concrete type using the 
following rules derived from the definitions
+         * given in ISO 19111:
+         *
+         *   - If the two CRS uses the same datum (ignoring metadata), assume 
that we have a Conversion.
+         *   - Otherwise we have a datum change, which implies that we have a 
Transformation.
+         *
+         * In the case of Conversion, we can specialize one step more if the 
conversion is going from a geographic CRS
+         * to a projected CRS. It may seems that we should check if 
ProjectedCRS.getBaseCRS() is equals (ignoring meta
+         * data) to source CRS. But we already checked the datum, which is the 
important part. The axis order and unit
+         * could be different, which we want to allow.
+         */
+        if (baseType == SingleOperation.class) {
+            if (OperationPathFinder.isConversion(sourceCRS, targetCRS)) {
+                if (interpolationCRS == null && sourceCRS instanceof 
GeographicCRS
+                                             && targetCRS instanceof 
ProjectedCRS)
+                {
+                    baseType = Projection.class;
+                } else {
+                    baseType = Conversion.class;
+                }
+            } else {
+                baseType = Transformation.class;
+            }
+        }
+        /*
+         * Now create the coordinate operation of the requested type. If we 
can not find a concrete class for the
+         * requested type, we will instantiate an SingleOperation in last 
resort. The later action is a departure
+         * from ISO 19111 since 'SingleOperation' is conceptually abstract.  
But we do that as a way to said that
+         * we are missing this important piece of information but still go 
ahead.
+         *
+         * It is unconvenient to guarantee that the created operation is an 
instance of 'baseType' since the user
+         * could have specified an implementation class or a custom 
sub-interface. We will perform the type check
+         * only after object creation.
+         */
+        final AbstractSingleOperation op;
+        if (Transformation.class.isAssignableFrom(baseType)) {
+            op = new DefaultTransformation(properties, sourceCRS, targetCRS, 
interpolationCRS, method, transform);
+        } else if (Projection.class.isAssignableFrom(baseType)) {
+            ArgumentChecks.ensureCanCast("sourceCRS", GeographicCRS.class, 
sourceCRS);
+            ArgumentChecks.ensureCanCast("targetCRS", ProjectedCRS .class, 
targetCRS);
+            if (interpolationCRS != null) {
+                throw new IllegalArgumentException(Errors.format(
+                        Errors.Keys.ForbiddenAttribute_2, "interpolationCRS", 
baseType));
+            }
+            final GeographicCRS baseCRS = (GeographicCRS) sourceCRS;
+            final ProjectedCRS  crs     =  (ProjectedCRS) targetCRS;
+            if (CylindricalProjection.class.isAssignableFrom(baseType)) {
+                op = new DefaultCylindricalProjection(properties, baseCRS, 
crs, method, transform);
+            } else if (ConicProjection.class.isAssignableFrom(baseType)) {
+                op = new DefaultConicProjection(properties, baseCRS, crs, 
method, transform);
+            } else if (PlanarProjection.class.isAssignableFrom(baseType)) {
+                op = new DefaultPlanarProjection(properties, baseCRS, crs, 
method, transform);
+            } else {
+                op = new DefaultProjection(properties, baseCRS, crs, method, 
transform);
+            }
+        } else if (Conversion.class.isAssignableFrom(baseType)) {
+            op = new DefaultConversion(properties, sourceCRS, targetCRS, 
interpolationCRS, method, transform);
+        } else {  // See above comment about this last-resort fallback.
+            op = new AbstractSingleOperation(properties, sourceCRS, targetCRS, 
interpolationCRS, method, transform);
+        }
+        if (!baseType.isInstance(op)) {
+            throw new 
FactoryException(Errors.format(Errors.Keys.CanNotInstantiate_1, baseType));
+        }
+        return pool.unique(op);
+    }
+
+    /**
      * Creates an ordered sequence of two or more single coordinate operations.
      * The sequence of operations is constrained by the requirement that the 
source coordinate reference system
      * of step (<var>n</var>+1) must be the same as the target coordinate 
reference system of step (<var>n</var>).

Modified: 
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCylindricalProjection.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCylindricalProjection.java?rev=1689367&r1=1689366&r2=1689367&view=diff
==============================================================================
--- 
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCylindricalProjection.java
 [UTF-8] (original)
+++ 
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCylindricalProjection.java
 [UTF-8] Mon Jul  6 11:13:05 2015
@@ -16,12 +16,17 @@
  */
 package org.apache.sis.referencing.operation;
 
+import java.util.Map;
 import javax.xml.bind.annotation.XmlTransient;
 import org.opengis.util.FactoryException;
 import org.opengis.referencing.operation.Conversion;
 import org.opengis.referencing.operation.CylindricalProjection;
+import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.crs.GeographicCRS;
+import org.opengis.referencing.crs.ProjectedCRS;
 
 
 /**
@@ -43,6 +48,24 @@ final class DefaultCylindricalProjection
     private static final long serialVersionUID = -969486613826553580L;
 
     /**
+     * Creates a projection from the given properties.
+     *
+     * @param properties The properties to be given to the identified object.
+     * @param sourceCRS  The source CRS.
+     * @param targetCRS  The target CRS.
+     * @param method     The coordinate operation method.
+     * @param transform  Transform from positions in the source CRS to 
positions in the target CRS.
+     */
+    public DefaultCylindricalProjection(final Map<String,?>   properties,
+                                        final GeographicCRS   sourceCRS,
+                                        final ProjectedCRS    targetCRS,
+                                        final OperationMethod method,
+                                        final MathTransform   transform)
+    {
+        super(properties, sourceCRS, targetCRS, method, transform);
+    }
+
+    /**
      * Creates a new projection with the same values than the specified one, 
together with the
      * specified source and target CRS. While the source conversion can be an 
arbitrary one, it
      * is typically a defining conversion.

Modified: 
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPlanarProjection.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPlanarProjection.java?rev=1689367&r1=1689366&r2=1689367&view=diff
==============================================================================
--- 
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPlanarProjection.java
 [UTF-8] (original)
+++ 
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPlanarProjection.java
 [UTF-8] Mon Jul  6 11:13:05 2015
@@ -16,12 +16,17 @@
  */
 package org.apache.sis.referencing.operation;
 
+import java.util.Map;
 import javax.xml.bind.annotation.XmlTransient;
 import org.opengis.util.FactoryException;
 import org.opengis.referencing.operation.Conversion;
 import org.opengis.referencing.operation.PlanarProjection;
+import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.crs.GeographicCRS;
+import org.opengis.referencing.crs.ProjectedCRS;
 
 
 /**
@@ -43,6 +48,24 @@ final class DefaultPlanarProjection exte
     private static final long serialVersionUID = 8171256287775067736L;
 
     /**
+     * Creates a projection from the given properties.
+     *
+     * @param properties The properties to be given to the identified object.
+     * @param sourceCRS  The source CRS.
+     * @param targetCRS  The target CRS.
+     * @param method     The coordinate operation method.
+     * @param transform  Transform from positions in the source CRS to 
positions in the target CRS.
+     */
+    public DefaultPlanarProjection(final Map<String,?>   properties,
+                                   final GeographicCRS   sourceCRS,
+                                   final ProjectedCRS    targetCRS,
+                                   final OperationMethod method,
+                                   final MathTransform   transform)
+    {
+        super(properties, sourceCRS, targetCRS, method, transform);
+    }
+
+    /**
      * Creates a new projection with the same values than the specified one, 
together with the
      * specified source and target CRS. While the source conversion can be an 
arbitrary one, it
      * is typically a defining conversion.

Modified: 
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultProjection.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultProjection.java?rev=1689367&r1=1689366&r2=1689367&view=diff
==============================================================================
--- 
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultProjection.java
 [UTF-8] (original)
+++ 
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultProjection.java
 [UTF-8] Mon Jul  6 11:13:05 2015
@@ -16,10 +16,13 @@
  */
 package org.apache.sis.referencing.operation;
 
+import java.util.Map;
 import javax.xml.bind.annotation.XmlTransient;
 import org.opengis.util.FactoryException;
 import org.opengis.referencing.operation.Conversion;
 import org.opengis.referencing.operation.Projection;
+import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.crs.ProjectedCRS;
 import org.opengis.referencing.crs.GeographicCRS;
@@ -58,6 +61,24 @@ class DefaultProjection extends DefaultC
     private static final long serialVersionUID = -7176751851369816864L;
 
     /**
+     * Creates a projection from the given properties.
+     *
+     * @param properties The properties to be given to the identified object.
+     * @param sourceCRS  The source CRS.
+     * @param targetCRS  The target CRS.
+     * @param method     The coordinate operation method.
+     * @param transform  Transform from positions in the source CRS to 
positions in the target CRS.
+     */
+    public DefaultProjection(final Map<String,?>   properties,
+                             final GeographicCRS   sourceCRS,
+                             final ProjectedCRS    targetCRS,
+                             final OperationMethod method,
+                             final MathTransform   transform)
+    {
+        super(properties, sourceCRS, targetCRS, null, method, transform);
+    }
+
+    /**
      * Creates a new projection with the same values than the specified one, 
together with the
      * specified source and target CRS. While the source conversion can be an 
arbitrary one, it
      * is typically a defining conversion.

Modified: 
sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/AffineTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/AffineTest.java?rev=1689367&r1=1689366&r2=1689367&view=diff
==============================================================================
--- 
sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/AffineTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/AffineTest.java
 [UTF-8] Mon Jul  6 11:13:05 2015
@@ -17,6 +17,7 @@
 package org.apache.sis.internal.referencing.provider;
 
 import org.opengis.parameter.GeneralParameterDescriptor;
+import org.opengis.referencing.operation.SingleOperation;
 import org.opengis.referencing.operation.Matrix;
 import org.apache.sis.referencing.operation.matrix.Matrices;
 import org.apache.sis.test.DependsOnMethod;
@@ -38,6 +39,17 @@ import static org.apache.sis.test.Metada
 @DependsOn(org.apache.sis.parameter.TensorValuesTest.class)
 public final strictfp class AffineTest extends TestCase {
     /**
+     * Verifies that {@link Affine#getOperationType()} is {@link 
SingleOperation}.
+     * The {@code Affine} class can not return one of the above, because we do 
not
+     * know if this operation method will be used for a transformation ora 
conversion
+     * (it can be used for both).
+     */
+    @Test
+    public void testOperationType() {
+        assertEquals(SingleOperation.class, new Affine().getOperationType());
+    }
+
+    /**
      * Tests {@link Affine#getParameters()} on a standard EPSG:9624 instance.
      */
     @Test

Modified: 
sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java?rev=1689367&r1=1689366&r2=1689367&view=diff
==============================================================================
--- 
sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java
 [UTF-8] Mon Jul  6 11:13:05 2015
@@ -120,7 +120,7 @@ public final strictfp class DefaultMathT
         assertFalse(transforms .isEmpty());
         assertFalse(conversions.isEmpty());
         assertFalse(projections.isEmpty());
-        assertTrue 
(conversions.contains(factory.getOperationMethod(Constants.AFFINE)));
+        assertTrue 
(transforms.contains(factory.getOperationMethod(Constants.AFFINE)));
         /*
          * Following tests will force instantiation of all remaining 
OperationMethod.
          */


Reply via email to