sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1661575 [2/4] - in /sis/branches/JDK6: ./ core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ core/sis-metadata/src/main/java/org/apache/sis/io/wkt/ core/sis-metadata/src/main/java/org/apache/sis/metadata/ core/sis-metadata/s...
Date Sun, 22 Feb 2015 23:02:54 GMT
Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorParameters.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorParameters.java?rev=1661575&r1=1661574&r2=1661575&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorParameters.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorParameters.java [UTF-8] Sun Feb 22 23:02:52 2015
@@ -20,6 +20,7 @@ import java.util.Map;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Arrays;
+import java.util.Collections;
 import java.io.IOException;
 import java.io.Serializable;
 import java.io.ObjectInputStream;
@@ -33,10 +34,13 @@ import org.opengis.parameter.GeneralPara
 import org.opengis.parameter.ParameterNotFoundException;
 import org.opengis.parameter.InvalidParameterNameException;
 import org.opengis.metadata.Identifier;
+import org.opengis.metadata.citation.Citation;
 import org.opengis.referencing.operation.Matrix;
+import org.apache.sis.referencing.NamedIdentifier;
 import org.apache.sis.referencing.IdentifiedObjects;
 import org.apache.sis.referencing.operation.matrix.Matrices;
-import org.apache.sis.internal.util.UnmodifiableArrayList;
+import org.apache.sis.internal.referencing.provider.Affine;
+import org.apache.sis.internal.util.Constants;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.measure.NumberRange;
 import org.apache.sis.util.Numbers;
@@ -53,9 +57,13 @@ import org.apache.sis.internal.jdk7.Obje
  *
  * <p>Each group of parameters contains the following elements:</p>
  * <ul>
- *   <li>A mandatory parameter for the number of rows ({@code "num_row"} in WKT 1).</li>
- *   <li>A mandatory parameter for the number of columns ({@code "num_col"} in WKT 1).</li>
- *   <li>(<i>etc.</i> for third-order or higher-order tensors).</li>
+ *   <li>Parameters (usually mandatory) for the tensor dimensions:
+ *     <ul>
+ *       <li>number of rows (named {@code "num_row"} in {@linkplain #WKT1} conventions),</li>
+ *       <li>number of columns (named {@code "num_col"} in WKT1 conventions),</li>
+ *       <li><i>etc.</i> for third-order or higher-order tensors.</li>
+ *     </ul>
+ *   </li>
  *   <li>A maximum of {@code num_row} × {@code num_col} × … optional parameters for the matrix or tensor element values.
  *       Parameter names depend on the formatting convention.</li>
  * </ul>
@@ -67,11 +75,35 @@ import org.apache.sis.internal.jdk7.Obje
  * <p><b>Parameters are not an efficient storage format for large tensors.</b>
  * Parameters are used only for small matrices/tensors to be specified in coordinate operations or processing libraries.
  * In particular, those parameters integrate well in <cite>Well Known Text</cite> (WKT) format.
- * For a more efficient matrix storage, see {@link org.apache.sis.referencing.operation.matrix.MatrixSIS}.</p>
+ * For a more efficient matrix storage,
+ * see the {@linkplain org.apache.sis.referencing.operation.matrix matrix package}.</p>
  *
  * {@section Formatting}
- * The parameters format for a matrix is typically like below:
+ * In the particular case of a tensor of {@linkplain #rank() rank} 2 (i.e. a matrix),
+ * the parameters are typically formatted as below. Note that in the EPSG convention,
+ * the matrix is implicitly {@linkplain Matrices#isAffine affine} and of dimension 3×3.
  *
+ * <table class="sis">
+ *   <caption>Well Known Text (WKT) formats for matrix parameters</caption>
+ * <tr>
+ *   <th>Using EPSG:9624 names and identifiers</th>
+ *   <th class="sep">Using OGC names</th>
+ * </tr>
+ * <tr><td>
+ * {@preformat wkt
+ *   Parameter["A0", <value>, Id["EPSG", 8623]],
+ *   Parameter["A1", <value>, Id["EPSG", 8624]],
+ *   Parameter["A2", <value>, Id["EPSG", 8625]],
+ *   Parameter["B0", <value>, Id["EPSG", 8639]],
+ *   Parameter["B1", <value>, Id["EPSG", 8640]],
+ *   Parameter["B2", <value>, Id["EPSG", 8641]]
+ * }
+ *
+ * <div class="note"><b>Note:</b>
+ * the EPSG database contains also A3, A4, A5, A6, A7, A8 and B3 parameters,
+ * but they are for polynomial transformations, not for affine transformations.</div>
+ *
+ * </td><td class="sep">
  * {@preformat wkt
  *   Parameter["num_row", 3],
  *   Parameter["num_col", 3],
@@ -84,28 +116,38 @@ import org.apache.sis.internal.jdk7.Obje
  *   ...
  *   Parameter["elt_<num_row-1>_<num_col-1>", <value>]
  * }
+ * </td></tr></table>
  *
  * Those groups are extensible, i.e. the number of <code>"elt_<var>row</var>_<var>col</var>"</code> parameters
  * depends on the {@code "num_row"} and {@code "num_col"} parameter values. For this reason, the descriptor of
  * matrix or tensor parameters is not immutable.
  *
- * {@section Usage}
+ * {@section Usage examples}
  * For creating a new group of parameters for a matrix using the {@link #WKT1} naming conventions,
- * on can use the following code:
+ * one can use the following code:
  *
  * {@preformat java
- *   Map<String,?> properties = Collections.singletonMap("name", "My operation");
+ *   Map<String,?> properties = Collections.singletonMap(ParameterValueGroup.NAME_KEY, "Affine");
  *   ParameterValueGroup p = TensorParameters.WKT1.createValueGroup(properties);
  * }
  *
+ * For setting the elements of a few values, then create a matrix from the parameter values:
+ *
+ * {@preformat java
+ *   p.parameter("elt_0_0").setValue(4);    // "A0" also accepted as a synonymous of "elt_0_0".
+ *   p.parameter("elt_1_1").setValue(6);    // "B1" also accepted as a synonymous of "elt_1_1".
+ *   Matrix m = TensorParameters.WKT1.toMatrix(p);
+ * }
+ *
  * @param <E> The type of tensor element values.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.4
- * @version 0.4
+ * @version 0.6
  * @module
+ *
+ * @see org.apache.sis.referencing.operation.matrix.Matrices
  */
-@SuppressWarnings("unchecked")
 public class TensorParameters<E> implements Serializable {
     /**
      * Serial number for inter-operability with different versions.
@@ -113,17 +155,70 @@ public class TensorParameters<E> impleme
     private static final long serialVersionUID = -7386537348359343836L;
 
     /**
-     * Parses and creates parameters names for matrices matching the
+     * Parses and creates matrix parameters with alphanumeric names.
+     * {@linkplain DefaultParameterDescriptor#getName() Names} are made of a letter indicating the row
+     * (first row is {@code "A"}), followed by a digit indicating the column index (first column is {@code "0"}).
+     * {@linkplain DefaultParameterDescriptor#getAlias() Aliases} are the names as they were defined in version 1
+     * of <cite>Well Known Text</cite> (WKT) format.
+     *
+     * <table class="sis">
+     *   <caption>Parameter names for a 3×3 matrix</caption>
+     *   <tr>
+     *     <th>Primary name</th>
+     *     <th class="sep">Alias</th>
+     *   </tr>
+     * <tr><td>
+     * {@preformat text
+     *   ┌            ┐
+     *   │ A0  A1  A2 │
+     *   │ B0  B1  B2 │
+     *   │ C0  C1  C2 │
+     *   └            ┘
+     * }</td><td class="sep">
+     * {@preformat text
+     *   ┌                             ┐
+     *   │ elt_0_0   elt_0_1   elt_0_2 │
+     *   │ elt_1_0   elt_1_1   elt_1_2 │
+     *   │ elt_2_0   elt_2_1   elt_2_2 │
+     *   └                             ┘
+     * }</td></tr>
+     * </table>
+     *
+     * {@section Relationship with EPSG}
+     * The above-cited group of parameters are close, but not identical, to the definitions provided
+     * by the <cite>"Affine general parametric transformation"</cite> (EPSG:9624) operation method.
+     * The differences are:
+     *
+     * <ul>
+     *   <li>EPSG:9624 is for matrices of size 3×3 and does not provide any way to specify the matrix size.
+     *       This {@code ALPHANUM} convention extends the definition to matrices of arbitrary size and accepts
+     *       {@code "num_row"} and {@code "num_col"} as optional parameters.</li>
+     *   <li>EPSG:9624 is restricted to affine matrices and consequently define parameters only for the two
+     *       first rows. This class accepts also parameters for the last row (namely {@code "C0"}, {@code "C1"}
+     *       and {@code "C2"} in a 3×3 matrices).</li>
+     * </ul>
+     *
+     * Because of the above-cited extensions, this {@code TensorParameters} constant can not be named {@code EPSG}.
+     *
+     * @since 0.6
+     */
+    public static final TensorParameters<Double> ALPHANUM;
+
+    /**
+     * Parses and creates matrix parameters with names matching the
      * <a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">Well Known Text</a>
      * version 1 (WKT 1) convention.
      *
      * <ul>
      *   <li>First parameter is {@code "num_row"}.</li>
      *   <li>Second parameter is {@code "num_col"}.</li>
-     *   <li>All other parameters are of the form <code>"elt_<var>row</var>_<var>col</var>"</code>.</li>
+     *   <li>All other parameters are of the form <code>"elt_</code><var>row</var><code>_</code><var>col</var><code>"</code>.
+     *       Those parameters have alias of the form {@code "A0"}, {@code "A1"}, <i>etc.</i> where the letter indicates
+     *       the row (first row is {@code "A"}) and the digit is the column index (first column is {@code "0"}).</li>
      * </ul>
      *
-     * <div class="note"><b>Example:</b> {@code "elt_2_1"} is the element name for the value at line 2 and row 1.</div>
+     * <div class="note"><b>Example:</b> {@code "elt_1_2"} is the element name for the value at row 1 and column 2.
+     * Its alias is {@code "B2"}, which is the EPSG name for the same parameter.</div>
      */
     public static final TensorParameters<Double> WKT1;
     static {
@@ -135,15 +230,29 @@ public class TensorParameters<E> impleme
          *       elements.
          */
         final NumberRange<Integer> valueDomain = NumberRange.create(1, true, 50, true);
-        final Integer defaultSize = 3;
-        final ParameterDescriptor<Integer> numRow, numCol;
+        final Integer defaultSize = Affine.EPSG_DIMENSION + 1;
+        /*
+         * For the WKT1 convention, the "num_row" and "num_col" parameters are mandatory.
+         */
         final Map<String,Object> properties = new HashMap<String,Object>(4);
         properties.put(Identifier.AUTHORITY_KEY, Citations.OGC);
-        properties.put(Identifier.CODE_KEY, "num_row");
-        numRow = new DefaultParameterDescriptor<Integer>(properties, 1, 1, Integer.class, valueDomain, null, defaultSize);
-        properties.put(Identifier.CODE_KEY, "num_col");
-        numCol = new DefaultParameterDescriptor<Integer>(properties, 1, 1, Integer.class, valueDomain, null, defaultSize);
-        WKT1 = new TensorParameters<Double>(Double.class, "elt_", "_", numRow, numCol);
+        properties.put(Identifier.CODE_KEY, Constants.NUM_ROW);
+        ParameterDescriptor<Integer> numRow = new DefaultParameterDescriptor<Integer>(
+                properties, 1, 1, Integer.class, valueDomain, null, defaultSize);
+        properties.put(Identifier.CODE_KEY, Constants.NUM_COL);
+        ParameterDescriptor<Integer> numCol = new DefaultParameterDescriptor<Integer>(
+                properties, 1, 1, Integer.class, valueDomain, null, defaultSize);
+        WKT1 = new MatrixParameters(numRow, numCol);
+        /*
+         * For the EPSG convention, there is no "num_row" or "num_col" parameters since the matrix
+         * size if fixed to 3×3. However since we still need them, we will declare them as optional
+         * and we will hide them from the descriptor unless the matrix size is different than 3×3.
+         */
+        numRow = new DefaultParameterDescriptor<Integer>(IdentifiedObjects.getProperties(numRow),
+                0, 1, Integer.class, valueDomain, null, defaultSize);
+        numCol = new DefaultParameterDescriptor<Integer>(IdentifiedObjects.getProperties(numCol),
+                0, 1, Integer.class, valueDomain, null, defaultSize);
+        ALPHANUM = new MatrixParametersAlphaNum(numRow, numCol);
     }
 
     /**
@@ -206,7 +315,7 @@ public class TensorParameters<E> impleme
      * @param dimensions  The parameter for the size of each dimension, usually in an array of length 2.
      *                    Length may be different if the caller wants to generalize usage of this class to tensors.
      */
-    @SuppressWarnings("rawtypes")
+    @SuppressWarnings({"unchecked", "rawtypes"})
     public TensorParameters(final Class<E> elementType, final String prefix, final String separator,
             final ParameterDescriptor<Integer>... dimensions)
     {
@@ -234,7 +343,7 @@ public class TensorParameters<E> impleme
      *
      * <p>This method is invoked by constructor and on deserialization.</p>
      */
-    @SuppressWarnings("rawtypes")
+    @SuppressWarnings({"unchecked", "rawtypes"})
     private <T> ParameterDescriptor<T>[] createCache() {
         if (Number.class.isAssignableFrom(elementType)) try {
             one  = (E) Numbers.wrap(1, (Class) elementType);
@@ -243,7 +352,7 @@ public class TensorParameters<E> impleme
             // Ignore - zero and one will be left to null.
         }
         int length = 1;
-        for (int i = Math.min(dimensions.length, CACHE_RANK); --i >= 0;) {
+        for (int i = Math.min(rank(), CACHE_RANK); --i >= 0;) {
             length *= CACHE_SIZE;
         }
         return new ParameterDescriptor[length];
@@ -264,10 +373,10 @@ public class TensorParameters<E> impleme
      *
      * <table class="sis">
      *   <caption>Tensor types implied by rank</caption>
-     *   <tr><th>Rank</th> <th>Type</th></tr>
-     *   <tr><td>0</td>    <td>scalar</td></tr>
-     *   <tr><td>1</td>    <td>vector</td></tr>
-     *   <tr><td>2</td>    <td>matrix</td></tr>
+     *   <tr><th>Rank</th> <th>Type</th>   <th>Used with</th></tr>
+     *   <tr><td>0</td>    <td>scalar</td> <td></td></tr>
+     *   <tr><td>1</td>    <td>vector</td> <td></td></tr>
+     *   <tr><td>2</td>    <td>matrix</td> <td>Affine general parametric transformation</td></tr>
      *   <tr><td><var>k</var></td><td>rank <var>k</var> tensor</td></tr>
      * </table>
      *
@@ -278,10 +387,23 @@ public class TensorParameters<E> impleme
     }
 
     /**
+     * Verifies that the length of the given array is equals to the tensor rank.
+     */
+    private void verifyRank(final int[] indices) {
+        if (indices.length != rank()) {
+            throw new IllegalArgumentException(Errors.format(
+                    Errors.Keys.UnexpectedArrayLength_2, rank(), indices.length));
+        }
+    }
+
+    /**
      * Returns the parameter descriptor for the dimension at the given index.
      *
      * @param  i The dimension index, from 0 inclusive to {@link #rank()} exclusive.
      * @return The parameter descriptor for the dimension at the given index.
+     *
+     * @see #getElementDescriptor(int...)
+     * @see #getAllDescriptors(int...)
      */
     public final ParameterDescriptor<Integer> getDimensionDescriptor(final int i) {
         return dimensions[i];
@@ -296,8 +418,12 @@ public class TensorParameters<E> impleme
      * @param  indices The indices of the tensor element for which to get the descriptor.
      * @return The parameter descriptor for the given tensor element.
      * @throws IllegalArgumentException If the given array does not have the expected length or have illegal value.
+     *
+     * @see #getDimensionDescriptor(int)
+     * @see #getAllDescriptors(int...)
      */
     public final ParameterDescriptor<E> getElementDescriptor(final int... indices) {
+        verifyRank(indices);
         final int cacheIndex = cacheIndex(indices);
         if (cacheIndex >= 0) {
             final ParameterDescriptor<E> param;
@@ -310,7 +436,7 @@ public class TensorParameters<E> impleme
         }
         /*
          * Parameter not found in the cache. Create a new one and cache it for future reuse.
-         * Note that an other thread could have created the same descriptor in the main time,
+         * Note that an other thread could have created the same descriptor in the meantime,
          * so we will need to check again.
          */
         final ParameterDescriptor<E> param = createElementDescriptor(indices);
@@ -333,6 +459,7 @@ public class TensorParameters<E> impleme
         int cacheIndex = 0;
         for (int i=0; i<indices.length; i++) {
             final int index = indices[i];
+            ArgumentChecks.ensurePositive("indices", index);
             if (i < CACHE_RANK) {
                 if (index >= 0 && index < CACHE_SIZE) {
                     cacheIndex = (cacheIndex * CACHE_SIZE) + index;
@@ -351,47 +478,41 @@ public class TensorParameters<E> impleme
      * This method is invoked by {@link #getElementDescriptor(int[])} when a new descriptor needs
      * to be created.
      *
-     * {@section Default implementation}
+     * <p><b>Default implementation</b></p>
      * The default implementation converts the given indices to a parameter name by invoking the
      * {@link #indicesToName(int[])} method, then creates a descriptor for an optional parameter
-     * of that name.
+     * of that name. The default value is given by {@link #getDefaultValue(int[])}.
      *
-     * {@section Subclassing}
+     * <p><b>Subclassing</b></p>
      * Subclasses can override this method if they want more control on descriptor properties
-     * like identification information, value domain and default values.
+     * like identification information, aliases or value domain.
      *
      * @param  indices The indices of the tensor element for which to create a parameter.
      * @return The parameter descriptor for the given tensor element.
      * @throws IllegalArgumentException If the given array does not have the expected length or have illegal value.
      *
      * @see #indicesToName(int[])
-     * @see #nameToIndices(String)
+     * @see #getDefaultValue(int[])
      */
     protected ParameterDescriptor<E> createElementDescriptor(final int[] indices) throws IllegalArgumentException {
-        boolean isDiagonal = true;
-        for (int i=1; i<indices.length; i++) {
-            if (indices[i] != indices[i-1]) {
-                isDiagonal = false;
-                break;
-            }
-        }
-        final Map<String,Object> properties = new HashMap<String,Object>(4);
-        properties.put(Identifier.CODE_KEY, indicesToName(indices));
-        properties.put(Identifier.AUTHORITY_KEY, dimensions[0].getName().getAuthority());
-        return new DefaultParameterDescriptor<E>(properties, 0, 1, elementType, null, null, isDiagonal ? one : zero);
+        final Citation authority = dimensions[0].getName().getAuthority();
+        final String name = indicesToName(indices);
+        return new DefaultParameterDescriptor<E>(
+                Collections.singletonMap(ParameterDescriptor.NAME_KEY, new NamedIdentifier(authority, name)),
+                0, 1, elementType, null, null, getDefaultValue(indices));
     }
 
     /**
      * Returns the parameter descriptor name of a matrix or tensor element at the given indices.
      * The returned name shall be parsable by the {@link #nameToIndices(String)} method.
      *
-     * {@section Default implementation}
+     * <p><b>Default implementation</b></p>
      * The default implementation requires an {@code indices} array having a length equals to the {@linkplain #rank()
      * rank}. That length is usually 2, where {@code indices[0]} is the <var>row</var> index and {@code indices[1]} is
      * the <var>column</var> index. Then this method builds a name with the “{@link #prefix} + <var>row</var> +
      * {@link #separator} + <var>column</var> + …” pattern (e.g. {@code "elt_0_0"}).
      *
-     * {@section Subclassing}
+     * <p><b>Subclassing</b></p>
      * If a subclass overrides this method for creating different names, then that subclass shall
      * also override {@link #nameToIndices(String)} for parsing those names.
      *
@@ -400,10 +521,7 @@ public class TensorParameters<E> impleme
      * @throws IllegalArgumentException If the given array does not have the expected length or have illegal value.
      */
     protected String indicesToName(final int[] indices) throws IllegalArgumentException {
-        if (indices.length != dimensions.length) {
-            throw new IllegalArgumentException(Errors.format(
-                    Errors.Keys.UnexpectedArrayLength_2, dimensions.length, indices.length));
-        }
+        verifyRank(indices);
         final StringBuilder name = new StringBuilder();
         String s = prefix;
         for (final int i : indices) {
@@ -417,7 +535,7 @@ public class TensorParameters<E> impleme
      * Returns the indices of matrix element for the given parameter name, or {@code null} if none.
      * This method is the converse of {@link #indicesToName(int[])}.
      *
-     * {@section Default implementation}
+     * <p><b>Default implementation</b></p>
      * The default implementation expects a name matching the “{@link #prefix} + <var>row</var> + {@link #separator} +
      * <var>column</var> + …” pattern and returns an array containing the <var>row</var>, <var>column</var> and other
      * indices, in that order.
@@ -432,7 +550,7 @@ public class TensorParameters<E> impleme
         if (!name.regionMatches(true, 0, prefix, 0, s)) {
             return null;
         }
-        final int[] indices = new int[dimensions.length];
+        final int[] indices = new int[rank()];
         final int last = indices.length - 1;
         for (int i=0; i<last; i++) {
             final int split = name.indexOf(separator, s);
@@ -447,9 +565,30 @@ public class TensorParameters<E> impleme
     }
 
     /**
+     * Returns the default value for the parameter descriptor at the given indices.
+     * The default implementation returns 1 if all indices are equals, or 0 otherwise.
+     *
+     * @param  indices The indices of the tensor element for which to get the default value.
+     * @return The default value for the tensor element at the given indices, or {@code null} if none.
+     *
+     * @see DefaultParameterDescriptor#getDefaultValue()
+     *
+     * @since 0.6
+     */
+    protected E getDefaultValue(final int[] indices) {
+        for (int i=1; i<indices.length; i++) {
+            if (indices[i] != indices[i-1]) {
+                return zero;
+            }
+        }
+        return one;
+    }
+
+    /**
      * Returns the descriptor in this group for the specified name.
      *
-     * @param  name The case insensitive name of the parameter to search for.
+     * @param  caller     The {@link TensorValues} instance invoking this method, used only in case of errors.
+     * @param  name       The case insensitive name of the parameter to search for.
      * @param  actualSize The current values of parameters that define the matrix (or tensor) dimensions.
      * @return The parameter for the given name.
      * @throws ParameterNotFoundException if there is no parameter for the given name.
@@ -498,35 +637,52 @@ public class TensorParameters<E> impleme
     }
 
     /**
+     * Returns the number of elements (e.g. {@code "elt_0_0"}) when formatting the parameter descriptors
+     * for a tensor of the given size. This is the total number of elements in the tensor.
+     */
+    private int numElements(final int[] actualSize) {
+        int n = 1;
+        for (int s : actualSize) {
+            ArgumentChecks.ensurePositive("actualSize", s);
+            n *= s;
+        }
+        return n;
+    }
+
+    /**
      * Returns all parameters in this group for a tensor of the specified dimensions.
+     * The returned array contains all descriptors returned by {@link #getDimensionDescriptor(int)}
+     * and {@link #getElementDescriptor(int...)}.
      *
-     * @param  actualSize The current values of parameters that define the matrix (or tensor) dimensions.
-     *         It is caller's responsibility to ensure that this array does not contain negative values.
-     * @return The matrix parameters, including all elements.
-     */
-    final List<GeneralParameterDescriptor> descriptors(final int[] actualSize) {
-        final int rank = dimensions.length; // 2 for a matrix, may be higher for a tensor.
-        int length = actualSize[0];
-        for (int i=1; i<rank; i++) {
-            length *= actualSize[i];
-        }
-        final GeneralParameterDescriptor[] parameters = new GeneralParameterDescriptor[rank + length];
-        System.arraycopy(dimensions, 0, parameters, 0, rank);
-        final int[] indices = new int[rank];
+     * @param  actualSize The matrix (or tensor) dimensions for which to get the parameters.
+     * @return The tensor parameters, including all elements.
+     *
+     * @see #getDimensionDescriptor(int)
+     * @see #getElementDescriptor(int...)
+     *
+     * @since 0.6
+     */
+    public ParameterDescriptor<?>[] getAllDescriptors(final int... actualSize) {
+        verifyRank(actualSize);
+        final int numDimensions = actualSize.length;
+        final int numElements   = numElements(actualSize);
+        final ParameterDescriptor<?>[] parameters = new ParameterDescriptor<?>[numDimensions + numElements];
+        System.arraycopy(dimensions, 0, parameters, 0, numDimensions);
+        final int[] indices = new int[rank()];
         /*
          * Iterates on all possible index values. Indes on the right side (usually the column index)
          * will vary faster, and index on the left side (usually the row index) will vary slowest.
          */
-        for (int i=0; i<length; i++) {
-            parameters[rank + i] = getElementDescriptor(indices);
-            for (int j=rank; --j >= 0;) {
+        for (int i=0; i<numElements; i++) {
+            parameters[numDimensions + i] = getElementDescriptor(indices);
+            for (int j=indices.length; --j >= 0;) {
                 if (++indices[j] < actualSize[j]) {
                     break;
                 }
                 indices[j] = 0; // We have done a full turn at that dimension. Will increment next dimension.
             }
         }
-        return UnmodifiableArrayList.wrap(parameters);
+        return parameters;
     }
 
     /**
@@ -583,7 +739,7 @@ public class TensorParameters<E> impleme
      * @return A new parameter group initialized to the given matrix.
      */
     public ParameterValueGroup createValueGroup(final Map<String,?> properties, final Matrix matrix) {
-        if (dimensions.length != 2) {
+        if (rank() != 2) {
             throw new IllegalStateException();
         }
         ArgumentChecks.ensureNonNull("matrix", matrix);
@@ -601,7 +757,7 @@ public class TensorParameters<E> impleme
      * @throws InvalidParameterNameException if a parameter name was not recognized.
      */
     public Matrix toMatrix(final ParameterValueGroup parameters) throws InvalidParameterNameException {
-        if (dimensions.length != 2) {
+        if (rank() != 2) {
             throw new IllegalStateException();
         }
         ArgumentChecks.ensureNonNull("parameters", parameters);

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorValues.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorValues.java?rev=1661575&r1=1661574&r2=1661575&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorValues.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorValues.java [UTF-8] Sun Feb 22 23:02:52 2015
@@ -34,6 +34,7 @@ import org.apache.sis.referencing.Identi
 import org.apache.sis.referencing.operation.matrix.Matrices;
 import org.apache.sis.internal.referencing.WKTUtilities;
 import org.apache.sis.internal.util.Numerics;
+import org.apache.sis.internal.util.UnmodifiableArrayList;
 import org.apache.sis.io.wkt.ElementKind;
 import org.apache.sis.io.wkt.Formatter;
 import org.apache.sis.util.Utilities;
@@ -54,7 +55,7 @@ import org.apache.sis.util.resources.Err
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.4
- * @version 0.5
+ * @version 0.6
  * @module
  */
 final class TensorValues<E> extends AbstractParameterDescriptor
@@ -66,7 +67,11 @@ final class TensorValues<E> extends Abst
     private static final long serialVersionUID = -7747712999115044943L;
 
     /**
-     * A provider of matrix descriptors.
+     * A provider of descriptors for matrix parameters. This object is used like a collection of
+     * {@link ParameterDescriptor}s, even if it does not implement any standard collection API.
+     *
+     * @see TensorParameters#descriptor(ParameterDescriptorGroup, String, int[])
+     * @see TensorParameters#getAllDescriptors(int[])
      */
     private final TensorParameters<E> descriptors;
 
@@ -102,7 +107,7 @@ final class TensorValues<E> extends Abst
      * If {@code clone} is true, the new group will be a clone of the given group.
      * If {@code clone} is false, the new group will be initialized to default values.
      */
-    private TensorValues(final TensorValues<E> other, final boolean clone) {
+    TensorValues(final TensorValues<E> other, final boolean clone) {
         super(other);
         descriptors = other.descriptors;
         dimensions = other.dimensions.clone();
@@ -166,13 +171,13 @@ final class TensorValues<E> extends Abst
      */
     @Override
     public List<GeneralParameterDescriptor> descriptors() {
-        return descriptors.descriptors(dimensions());
+        return UnmodifiableArrayList.<GeneralParameterDescriptor>wrap(descriptors.getAllDescriptors(size()));
     }
 
     /**
-     * Returns the current tensor dimensions.
+     * Returns the current tensor size for each dimensions.
      */
-    private int[] dimensions() {
+    private int[] size() {
         final int[] indices = new int[dimensions.length];
         for (int i=0; i<indices.length; i++) {
             indices[i] = dimensions[i].intValue();
@@ -191,7 +196,7 @@ final class TensorValues<E> extends Abst
     public GeneralParameterDescriptor descriptor(String name) throws ParameterNotFoundException {
         name = CharSequences.trimWhitespaces(name);
         ArgumentChecks.ensureNonEmpty("name", name);
-        return descriptors.descriptor(this, name, dimensions());
+        return descriptors.descriptor(this, name, size());
     }
 
     /**
@@ -213,7 +218,7 @@ final class TensorValues<E> extends Abst
             cause = exception;
         }
         if (indices != null) {
-            final int[] actualSize = dimensions();
+            final int[] actualSize = size();
             if (TensorParameters.isInBounds(indices, actualSize)) {
                 return parameter(indices, actualSize);
             }
@@ -298,9 +303,13 @@ final class TensorValues<E> extends Abst
      */
     @Override
     public List<GeneralParameterValue> values() {
-        final List<GeneralParameterValue> addTo = new ArrayList<GeneralParameterValue>(16);
-        addTo.addAll(Arrays.asList(dimensions));
-        addValues(values, dimensions(), 0, addTo);
+        final List<GeneralParameterValue> addTo = new ArrayList<GeneralParameterValue>();
+        for (final ParameterValue<Integer> dimension : dimensions) {
+            if (!isOmitted(dimension)) {
+                addTo.add(dimension);
+            }
+        }
+        addValues(values, size(), 0, addTo);
         return Collections.unmodifiableList(addTo);
     }
 
@@ -319,9 +328,9 @@ final class TensorValues<E> extends Abst
                 }
             } else {
                 for (int i=0; i<length; i++) {
-                    final Object value = values[i];
-                    if (value != null) {
-                        addTo.add((ParameterValue<?>) value);
+                    final ParameterValue<?> parameter = (ParameterValue<?>) values[i];
+                    if (parameter != null && !isOmitted(parameter)) {
+                        addTo.add(parameter);
                     }
                 }
             }
@@ -329,6 +338,19 @@ final class TensorValues<E> extends Abst
     }
 
     /**
+     * Returns {@code true} if the given parameter can be omitted. A parameter can be omitted
+     * if it is not mandatory and has a value equals to the default value.
+     */
+    private static boolean isOmitted(final ParameterValue<?> parameter) {
+        final Object value = parameter.getValue();
+        if (value == null) { // Implies that the default value is also null.
+            return true;
+        }
+        final ParameterDescriptor<?> descriptor = parameter.getDescriptor();
+        return descriptor.getMinimumOccurs() == 0 && value.equals(descriptor.getDefaultValue());
+    }
+
+    /**
      * Always throws an exception since this group does not contain subgroups.
      */
     @Override
@@ -377,7 +399,7 @@ final class TensorValues<E> extends Abst
      *
      * @param matrix The matrix to copy in this group of parameters.
      */
-    public void setMatrix(final Matrix matrix) {
+    final void setMatrix(final Matrix matrix) {
         final int numRow = matrix.getNumRow();
         final int numCol = matrix.getNumCol();
         dimensions[0].setValue(numRow);

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java?rev=1661575&r1=1661574&r2=1661575&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java [UTF-8] Sun Feb 22 23:02:52 2015
@@ -768,7 +768,7 @@ public class AbstractIdentifiedObject ex
      * @see IdentifiedObjects#isHeuristicMatchForName(IdentifiedObject, String)
      */
     public boolean isHeuristicMatchForName(final String name) {
-        return IdentifiedObjects.isHeuristicMatchForName(this, alias, name);
+        return IdentifiedObjects.isHeuristicMatchForName(this.name, alias, name);
     }
 
     /**

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java?rev=1661575&r1=1661574&r2=1661575&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java [UTF-8] Sun Feb 22 23:02:52 2015
@@ -29,7 +29,7 @@ import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.referencing.IdentifiedObject;
 import org.apache.sis.metadata.iso.ImmutableIdentifier;
-import org.apache.sis.metadata.iso.citation.Citations;
+import org.apache.sis.internal.util.Citations;
 import org.apache.sis.util.resources.Errors;
 
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
@@ -190,8 +190,8 @@ public abstract class Builder<B extends
     protected Builder() {
         assert verifyParameterizedType(getClass());
         properties  = new HashMap<String,Object>(8);
-        aliases     = new ArrayList<GenericName>(4);
-        identifiers = new ArrayList<Identifier> (4);
+        aliases     = new ArrayList<GenericName>();  // Will often stay empty (default constructor handles those cases well).
+        identifiers = new ArrayList<Identifier> ();
     }
 
     /**
@@ -464,7 +464,7 @@ public abstract class Builder<B extends
      */
     public B addIdentifier(final Citation authority, final String identifier) {
         ensureNonNull("identifier", identifier);
-        identifiers.add(new ImmutableIdentifier(authority, Citations.getIdentifier(authority), identifier));
+        identifiers.add(new ImmutableIdentifier(authority, Citations.getUnicodeIdentifier(authority), identifier));
         return self();
     }
 

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java?rev=1661575&r1=1661574&r2=1661575&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java [UTF-8] Sun Feb 22 23:02:52 2015
@@ -65,11 +65,11 @@ import org.apache.sis.measure.Units;
 
 import static java.util.Collections.singletonMap;
 import static org.opengis.referencing.IdentifiedObject.NAME_KEY;
-import static org.apache.sis.internal.referencing.HardCoded.CRS;
-import static org.apache.sis.internal.referencing.HardCoded.EPSG;
-import static org.apache.sis.internal.referencing.HardCoded.CRS27;
-import static org.apache.sis.internal.referencing.HardCoded.CRS83;
-import static org.apache.sis.internal.referencing.HardCoded.CRS84;
+import static org.apache.sis.internal.util.Constants.CRS;
+import static org.apache.sis.internal.util.Constants.EPSG;
+import static org.apache.sis.internal.util.Constants.CRS27;
+import static org.apache.sis.internal.util.Constants.CRS83;
+import static org.apache.sis.internal.util.Constants.CRS84;
 
 
 /**

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java?rev=1661575&r1=1661574&r2=1661575&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java [UTF-8] Sun Feb 22 23:02:52 2015
@@ -318,6 +318,10 @@ public final class IdentifiedObjects ext
      *
      * @param  object The identified object, or {@code null}.
      * @return The first name, alias or identifier which is a valid Unicode identifier, or {@code null} if none.
+     *
+     * @see org.apache.sis.metadata.iso.ImmutableIdentifier
+     * @see org.apache.sis.metadata.iso.citation.Citations#getUnicodeIdentifier(Citation)
+     * @see org.apache.sis.util.CharSequences#isUnicodeIdentifier(CharSequence)
      */
     public static String getUnicodeIdentifier(final IdentifiedObject object) {
         if (object != null) {
@@ -392,31 +396,30 @@ public final class IdentifiedObjects ext
             return ((AbstractIdentifiedObject) object).isHeuristicMatchForName(name);
         } else {
             ensureNonNull("object", object);
-            return isHeuristicMatchForName(object, object.getAlias(), name);
+            return isHeuristicMatchForName(object.getName(), object.getAlias(), name);
         }
     }
 
     /**
-     * Returns {@code true} if the {@linkplain AbstractIdentifiedObject#getName() primary name} of the given object
-     * or one of the given alias matches the given name. The comparison ignores case, some Latin diacritical signs
+     * Returns {@code true} if the given {@linkplain AbstractIdentifiedObject#getName() primary name} or one
+     * of the given aliases matches the given name. The comparison ignores case, some Latin diacritical signs
      * and any characters that are not letters or digits.
      *
-     * @param  object  The object to check.
-     * @param  aliases The list of alias in {@code object} (may be {@code null}).
-     *                 This method will never modify this list. Consequently, the
-     *                 given list can be a direct reference to an internal list.
-     * @param  name    The name for which to check for equality.
+     * @param  name     The name of the {@code IdentifiedObject} to check.
+     * @param  aliases  The list of alias in the {@code IdentifiedObject} (may be {@code null}).
+     *                  This method will never modify this list. Consequently, the
+     *                  given list can be a direct reference to an internal list.
+     * @param  toSearch The name for which to check for equality.
      * @return {@code true} if the primary name or at least one alias matches the given {@code name}.
      */
-    static boolean isHeuristicMatchForName(final IdentifiedObject object, final Collection<GenericName> aliases,
-            CharSequence name)
+    static boolean isHeuristicMatchForName(final Identifier name, final Collection<GenericName> aliases,
+            CharSequence toSearch)
     {
-        name = CharSequences.toASCII(name);
-        final Identifier id = object.getName();
-        if (id != null) { // Paranoiac check.
-            final CharSequence code = CharSequences.toASCII(id.getCode());
+        toSearch = CharSequences.toASCII(toSearch);
+        if (name != null) { // Paranoiac check.
+            final CharSequence code = CharSequences.toASCII(name.getCode());
             if (code != null) { // Paranoiac check.
-                if (CharSequences.equalsFiltered(name, code, LETTERS_AND_DIGITS, true)) {
+                if (CharSequences.equalsFiltered(toSearch, code, LETTERS_AND_DIGITS, true)) {
                     return true;
                 }
             }
@@ -425,7 +428,7 @@ public final class IdentifiedObjects ext
             for (final GenericName alias : aliases) {
                 if (alias != null) { // Paranoiac check.
                     final CharSequence tip = CharSequences.toASCII(alias.tip().toString());
-                    if (CharSequences.equalsFiltered(name, tip, LETTERS_AND_DIGITS, true)) {
+                    if (CharSequences.equalsFiltered(toSearch, tip, LETTERS_AND_DIGITS, true)) {
                         return true;
                     }
                     /*
@@ -475,10 +478,10 @@ public final class IdentifiedObjects ext
         }
         final String code = identifier.getCode();
         String cs = identifier.getCodeSpace();
-        if (cs == null) {
-            cs = org.apache.sis.internal.util.Citations.getIdentifier(identifier.getAuthority());
+        if (cs == null || cs.isEmpty()) {
+            cs = org.apache.sis.internal.util.Citations.getIdentifier(identifier.getAuthority(), true);
         }
-        if (cs != null && !cs.isEmpty()) {
+        if (cs != null) {
             return cs + DefaultNameSpace.DEFAULT_SEPARATOR + code;
         }
         return code;

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java?rev=1661575&r1=1661574&r2=1661575&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java [UTF-8] Sun Feb 22 23:02:52 2015
@@ -33,10 +33,12 @@ import org.opengis.metadata.Identifier;
 import org.opengis.parameter.InvalidParameterValueException;
 import org.apache.sis.internal.metadata.NameToIdentifier;
 import org.apache.sis.internal.system.DefaultFactories;
-import org.apache.sis.metadata.iso.citation.Citations;
+import org.apache.sis.metadata.iso.citation.Citations;  // For javadoc
 import org.apache.sis.metadata.iso.ImmutableIdentifier;
 import org.apache.sis.util.collection.WeakValueHashMap;
 
+import static org.apache.sis.internal.util.Citations.getUnicodeIdentifier;
+
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.Objects;
 
@@ -183,7 +185,7 @@ public class NamedIdentifier extends Imm
      * @param code      The code. This parameter is mandatory.
      */
     public NamedIdentifier(final Citation authority, final String code) {
-        super(authority, Citations.getIdentifier(authority), code);
+        super(authority, getUnicodeIdentifier(authority), code);
     }
 
     /**
@@ -239,14 +241,14 @@ public class NamedIdentifier extends Imm
      */
     private GenericName createName(final Citation authority, final CharSequence code) {
         final NameFactory factory = DefaultFactories.NAMES;
-        final String title = Citations.getIdentifier(authority); // Whitespaces trimed by Citations.
+        final String identifier = getUnicodeIdentifier(authority);      // Whitespaces trimed by Citations.
         NameSpace scope = null;
-        if (title != null) {
+        if (identifier != null) {
             synchronized (SCOPES) {
-                scope = SCOPES.get(title);
+                scope = SCOPES.get(identifier);
                 if (scope == null) {
-                    scope = factory.createNameSpace(factory.createLocalName(null, title), null);
-                    SCOPES.put(title, scope);
+                    scope = factory.createNameSpace(factory.createLocalName(null, identifier), null);
+                    SCOPES.put(identifier, scope);
                 }
             }
         }

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeographicCRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeographicCRS.java?rev=1661575&r1=1661574&r2=1661575&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeographicCRS.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeographicCRS.java [UTF-8] Sun Feb 22 23:02:52 2015
@@ -33,11 +33,11 @@ import org.apache.sis.referencing.Abstra
 import org.apache.sis.io.wkt.Formatter;
 import org.apache.sis.measure.Longitude;
 
-import static org.apache.sis.internal.referencing.HardCoded.CRS;
-import static org.apache.sis.internal.referencing.HardCoded.EPSG;
-import static org.apache.sis.internal.referencing.HardCoded.CRS27;
-import static org.apache.sis.internal.referencing.HardCoded.CRS83;
-import static org.apache.sis.internal.referencing.HardCoded.CRS84;
+import static org.apache.sis.internal.util.Constants.CRS;
+import static org.apache.sis.internal.util.Constants.EPSG;
+import static org.apache.sis.internal.util.Constants.CRS27;
+import static org.apache.sis.internal.util.Constants.CRS83;
+import static org.apache.sis.internal.util.Constants.CRS84;
 
 
 /**

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java?rev=1661575&r1=1661574&r2=1661575&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java [UTF-8] Sun Feb 22 23:02:52 2015
@@ -360,6 +360,9 @@ public class AbstractCS extends Abstract
     /**
      * Returns a coordinate system of the same type than this CS but with different axes.
      * This method shall be overridden by all {@code AbstractCS} subclasses in this package.
+     *
+     * @param  axes The set of axes to give to the new coordinate system.
+     * @return A new coordinate system of the same type than {@code this}, but using the given axes.
      */
     AbstractCS createSameType(final Map<String,?> properties, final CoordinateSystemAxis[] axes) {
         return new AbstractCS(properties, axes);

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java?rev=1661575&r1=1661574&r2=1661575&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java [UTF-8] Sun Feb 22 23:02:52 2015
@@ -16,7 +16,8 @@
  */
 package org.apache.sis.referencing.cs;
 
-import org.opengis.referencing.cs.AxisDirection; // For javadoc
+import org.opengis.referencing.cs.AxisDirection;    // For javadoc
+import org.opengis.referencing.cs.CoordinateSystem; // For javadoc
 
 
 /**
@@ -136,6 +137,7 @@ public enum AxesConvention {
      * changes are more difficult to handle by coordinate operation factories.
      * </div>
      *
+     * @see CoordinateSystems#normalize(CoordinateSystem)
      * @see org.apache.sis.referencing.CommonCRS#normalizedGeographic()
      */
     NORMALIZED,

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java?rev=1661575&r1=1661574&r2=1661575&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java [UTF-8] Sun Feb 22 23:02:52 2015
@@ -46,7 +46,7 @@ import org.apache.sis.internal.jdk7.Obje
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.4
- * @version 0.4
+ * @version 0.6
  * @module
  */
 public final class CoordinateSystems extends Static {
@@ -296,4 +296,40 @@ public final class CoordinateSystems ext
         }
         return matrix;
     }
+
+    /**
+     * Returns a coordinate system with {@linkplain AxesConvention#NORMALIZED normalized} axis order and units.
+     * This method is typically used together with {@link #swapAndScaleAxes swapAndScaleAxes} for the creation
+     * of a transformation step before some
+     * {@linkplain org.apache.sis.referencing.operation.transform.AbstractMathTransform math transform}.
+     * Example:
+     *
+     * {@preformat java
+     *     Matrix step1 = swapAndScaleAxes(sourceCS, normalize(sourceCS));
+     *     Matrix step2 = ... some transform operating on standard axis ...
+     *     Matrix step3 = swapAndScaleAxes(normalize(targetCS), targetCS);
+     * }
+     *
+     * A rational for normalized axis order and units is explained in the <cite>Axis units and
+     * direction</cite> section in the {@linkplain org.apache.sis.referencing.operation.projection
+     * description of map projection package}.
+     *
+     * @param  cs The coordinate system.
+     * @return A constant similar to the specified {@code cs} with normalized axes.
+     * @throws IllegalArgumentException if the specified coordinate system can not be normalized.
+     *
+     * @see AxesConvention#NORMALIZED
+     *
+     * @since 0.6
+     */
+    public static CoordinateSystem normalize(final CoordinateSystem cs) throws IllegalArgumentException {
+        if (cs == null) {
+            return null;
+        } else if (cs instanceof AbstractCS) {
+            // User may have overridden the 'forConvention' method.
+            return ((AbstractCS) cs).forConvention(AxesConvention.NORMALIZED);
+        } else {
+            return Normalizer.normalize(cs);
+        }
+    }
 }

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java?rev=1661575&r1=1661574&r2=1661575&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java [UTF-8] Sun Feb 22 23:02:52 2015
@@ -26,6 +26,7 @@ import javax.measure.converter.UnitConve
 import javax.measure.converter.ConversionException;
 import org.opengis.referencing.cs.RangeMeaning;
 import org.opengis.referencing.cs.AxisDirection;
+import org.opengis.referencing.cs.CoordinateSystem;
 import org.opengis.referencing.cs.CoordinateSystemAxis;
 import org.apache.sis.internal.referencing.AxisDirections;
 import org.apache.sis.referencing.IdentifiedObjects;
@@ -207,7 +208,19 @@ final class Normalizer implements Compar
     }
 
     /**
-     * Reorder the axes in an attempt to get a right-handed system.
+     * Reorders the axes in an attempt to get a right-handed system.
+     * If no axis change is needed, then this method returns {@code cs} unchanged.
+     *
+     * @param  cs The coordinate system to normalize.
+     * @return The normalized coordinate system.
+     */
+    static CoordinateSystem normalize(final CoordinateSystem cs) {
+        final CoordinateSystemAxis[] axes = normalizeAxes(cs, true, true);
+        return (axes != null) ? createSameType(AbstractCS.castOrCopy(cs), axes) : cs;
+    }
+
+    /**
+     * Reorders the axes in an attempt to get a right-handed system.
      * If no axis change is needed, then this method returns {@code cs} unchanged.
      *
      * @param  cs The coordinate system to normalize.
@@ -216,6 +229,22 @@ final class Normalizer implements Compar
      * @return The normalized coordinate system.
      */
     static AbstractCS normalize(final AbstractCS cs, final boolean normalizeAxes, final boolean normalizeUnits) {
+        final CoordinateSystemAxis[] axes = normalizeAxes(cs, normalizeAxes, normalizeUnits);
+        return (axes != null) ? createSameType(cs, axes) : cs;
+    }
+
+    /**
+     * Returns the normalized set of axes for the given coordinate system,
+     * or {@code null} if its axes were already normalized.
+     *
+     * @param  cs The coordinate system to normalize.
+     * @param  normalizeAxes  {@code true} for normalizing axis directions.
+     * @param  normalizeUnits {@code true} for normalizing units (currently ignored if {@code normalizeAxes} is {@code false}).
+     * @return The normalized set of coordinate system axes.
+     */
+    private static CoordinateSystemAxis[] normalizeAxes(final CoordinateSystem cs,
+            final boolean normalizeAxes, final boolean normalizeUnits)
+    {
         boolean changed = false;
         final int dimension = cs.getDimension();
         final CoordinateSystemAxis[] axes = new CoordinateSystemAxis[dimension];
@@ -227,13 +256,21 @@ final class Normalizer implements Compar
             axes[i] = axis;
         }
         /*
-         * Sorts the axis in an attempt to create a right-handed system
-         * and creates a new Coordinate System if at least one axis changed.
+         * Sorts the axis in an attempt to create a right-handed system.
+         * Caller will create a new Coordinate System only if at least one axis changed.
          */
         changed |= sort(axes);
-        if (!changed) {
-            return cs;
-        }
+        return changed ? axes : null;
+    }
+
+    /**
+     * Creates a new coordinate system of the same type than the given one, but with the given axes.
+     *
+     * @param  cs   The coordinate system to copy.
+     * @param  axes The set of axes to give to the new coordinate system.
+     * @return A new coordinate system of the same type than {@code cs}, but using the given axes.
+     */
+    private static AbstractCS createSameType(final AbstractCS cs, final CoordinateSystemAxis[] axes) {
         final StringBuilder buffer = (StringBuilder) CharSequences.camelCaseToSentence(cs.getInterface().getSimpleName());
         return cs.createSameType(singletonMap(AbstractCS.NAME_KEY, DefaultCompoundCS.createName(buffer, axes)), axes);
     }

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultFormula.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultFormula.java?rev=1661575&r1=1661574&r2=1661575&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultFormula.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultFormula.java [UTF-8] Sun Feb 22 23:02:52 2015
@@ -47,6 +47,7 @@ import org.apache.sis.internal.jdk7.Obje
  *
  * @see DefaultOperationMethod
  * @see org.apache.sis.referencing.operation.transform.AbstractMathTransform
+ * @see org.apache.sis.referencing.operation.transform.MathTransformProvider
  */
 public class DefaultFormula extends FormattableObject implements Formula, Serializable {
     /**

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultOperationMethod.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultOperationMethod.java?rev=1661575&r1=1661574&r2=1661575&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultOperationMethod.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultOperationMethod.java [UTF-8] Sun Feb 22 23:02:52 2015
@@ -25,7 +25,7 @@ import org.opengis.referencing.operation
 import org.opengis.referencing.operation.Projection;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.OperationMethod;
-import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.referencing.operation.SingleOperation;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.apache.sis.util.Utilities;
 import org.apache.sis.util.ComparisonMode;
@@ -45,12 +45,30 @@ import org.apache.sis.internal.jdk7.Obje
 
 
 /**
- * Defines the algorithm and describes the parameters used to perform a coordinate operation. An {@code OperationMethod}
- * contains an arbitrary amount of {@linkplain org.apache.sis.parameter.DefaultParameterDescriptor parameter descriptors}.
- * Values for those parameters will be assigned by {@linkplain DefaultSingleOperation coordinate operations}.
+ * Describes the algorithm and parameters used to perform a coordinate operation. An {@code OperationMethod}
+ * is a kind of metadata: it does not perform any coordinate operation (e.g. map projection) by itself, but
+ * tells us what is needed in order to perform such operation.
  *
- * <div class="note"><b>Departure from the ISO 19111 standard:</b>
- * the following properties are mandatory according ISO 19111,
+ * <p>The most important parts of an {@code OperationMethod} are its {@linkplain #getName() name} and its
+ * {@linkplain #getParameters() group of parameter descriptors}. The parameter descriptors do not contain
+ * any value, but tell us what are the expected parameters, together with their units of measurement.</p>
+ *
+ * <div class="note"><b>Example:</b>
+ * An operation method named “<cite>Mercator (variant A)</cite>” (EPSG:9804) expects the following parameters:
+ * <ul>
+ *   <li>“<cite>Latitude of natural origin</cite>” in degrees. Default value is 0°.</li>
+ *   <li>“<cite>Longitude of natural origin</cite>” in degrees. Default value is 0°.</li>
+ *   <li>“<cite>Scale factor at natural origin</cite>” as a dimensionless number. Default value is 1.</li>
+ *   <li>“<cite>False easting</cite>” in metres. Default value is 0 m.</li>
+ *   <li>“<cite>False northing</cite>” in metres. Default value is 0 m.</li>
+ * </ul></div>
+ *
+ * In Apache SIS implementation, the {@linkplain #getName() name} is the only mandatory property. However it is
+ * recommended to provide also {@linkplain #getIdentifiers() identifiers} (e.g. “EPSG:9804” in the above example)
+ * since names can sometime be ambiguous or be spelled in different ways.
+ *
+ * <div class="note"><b>Departure from the ISO 19111 standard</b><br>
+ * The following properties are mandatory according ISO 19111,
  * but may be missing under some conditions in Apache SIS:
  * <ul>
  *   <li>The {@linkplain #getFormula() formula} if it has not been provided to the
@@ -60,18 +78,44 @@ import org.apache.sis.internal.jdk7.Obje
  *     constructor can not infer them.</li>
  * </ul></div>
  *
+ * {@section Relationship with other classes or interfaces}
+ * {@code OperationMethod} describes parameters without providing any value (except sometime default values).
+ * When values have been assigned to parameters, the result is a {@link SingleOperation}.
+ * Note that there is different kinds of {@code SingleOperation} depending on the nature and accuracy of the
+ * coordinate operation. See {@link #getOperationType()} for more information.
+ *
+ * <p>The interface performing the actual work of taking coordinates in the
+ * {@linkplain AbstractCoordinateOperation#getSourceCRS() source CRS} and calculating the new coordinates in the
+ * {@linkplain AbstractCoordinateOperation#getTargetCRS() target CRS} is {@link MathTransform}.
+ * In order to allow Apache SIS to instantiate those {@code MathTransform}s from given parameter values,
+ * {@code DefaultOperationMethod} subclasses should implement the
+ * {@link org.apache.sis.referencing.operation.transform.MathTransformProvider} interface.</p>
+ *
+ * {@section Immutability and thread safety}
+ * This class is immutable and thread-safe if all properties given to the constructor are also immutable and thread-safe.
+ * It is strongly recommended for all subclasses to be thread-safe, especially the
+ * {@link org.apache.sis.referencing.operation.transform.MathTransformProvider} implementations to be used with
+ * {@link org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory}.
+ *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 0.5
+ * @version 0.6
  * @since   0.5
  * @module
  *
  * @see DefaultSingleOperation
+ * @see org.apache.sis.referencing.operation.transform.MathTransformProvider
  */
 public class DefaultOperationMethod extends AbstractIdentifiedObject implements OperationMethod {
+    /*
+     * NOTE FOR JAVADOC WRITER:
+     * The "method" word is ambiguous here, because it can be "Java method" or "coordinate operation method".
+     * In this class, we reserve the "method" word for "coordinate operation method" as much as possible.
+     */
+
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = -8181774670648793964L;
+    private static final long serialVersionUID = 2870579345991143357L;
 
     /**
      * Formula(s) or procedure used by this operation method. This may be a reference to a publication.
@@ -85,14 +129,14 @@ public class DefaultOperationMethod exte
      * May be {@code null} if this method can work with any number of
      * source dimensions (e.g. <cite>Affine Transform</cite>).
      */
-    private final Integer sourceDimension;
+    private final Integer sourceDimensions;
 
     /**
      * Number of dimensions in the target CRS of this operation method.
      * May be {@code null} if this method can work with any number of
      * target dimensions (e.g. <cite>Affine Transform</cite>).
      */
-    private final Integer targetDimension;
+    private final Integer targetDimensions;
 
     /**
      * The set of parameters, or {@code null} if none.
@@ -145,19 +189,19 @@ public class DefaultOperationMethod exte
      * The source and target dimensions may be {@code null} if this method can work
      * with any number of dimensions (e.g. <cite>Affine Transform</cite>).
      *
-     * @param properties      Set of properties. Shall contain at least {@code "name"}.
-     * @param sourceDimension Number of dimensions in the source CRS of this operation method, or {@code null}.
-     * @param targetDimension Number of dimensions in the target CRS of this operation method, or {@code null}.
-     * @param parameters      Description of parameters expected by this operation.
+     * @param properties       Set of properties. Shall contain at least {@code "name"}.
+     * @param sourceDimensions Number of dimensions in the source CRS of this operation method, or {@code null}.
+     * @param targetDimensions Number of dimensions in the target CRS of this operation method, or {@code null}.
+     * @param parameters       Description of parameters expected by this operation.
      */
     public DefaultOperationMethod(final Map<String,?> properties,
-                                  final Integer sourceDimension,
-                                  final Integer targetDimension,
+                                  final Integer sourceDimensions,
+                                  final Integer targetDimensions,
                                   final ParameterDescriptorGroup parameters)
     {
         super(properties);
-        if (sourceDimension != null) ensurePositive("sourceDimension", sourceDimension);
-        if (targetDimension != null) ensurePositive("targetDimension", targetDimension);
+        if (sourceDimensions != null) ensurePositive("sourceDimensions", sourceDimensions);
+        if (targetDimensions != null) ensurePositive("targetDimensions", targetDimensions);
         ensureNonNull("parameters", parameters);
 
         Object value = properties.get(FORMULA_KEY);
@@ -171,9 +215,9 @@ public class DefaultOperationMethod exte
             throw new IllegalArgumentException(Errors.getResources(properties)
                     .getString(Errors.Keys.IllegalPropertyClass_2, FORMULA_KEY, value.getClass()));
         }
-        this.parameters      = parameters;
-        this.sourceDimension = sourceDimension;
-        this.targetDimension = targetDimension;
+        this.parameters       = parameters;
+        this.sourceDimensions = sourceDimensions;
+        this.targetDimensions = targetDimensions;
     }
 
     /**
@@ -185,8 +229,8 @@ public class DefaultOperationMethod exte
      */
     public DefaultOperationMethod(final MathTransform transform) {
         super(getProperties(transform));
-        sourceDimension = transform.getSourceDimensions();
-        targetDimension = transform.getTargetDimensions();
+        sourceDimensions = transform.getSourceDimensions();
+        targetDimensions = transform.getTargetDimensions();
         if (transform instanceof Parameterized) {
             parameters = ((Parameterized) transform).getParameterDescriptors();
         } else {
@@ -250,15 +294,15 @@ public class DefaultOperationMethod exte
      */
     protected DefaultOperationMethod(final OperationMethod method) {
         super(method);
-        formula         = method.getFormula();
-        parameters      = method.getParameters();
-        sourceDimension = method.getSourceDimensions();
-        targetDimension = method.getTargetDimensions();
+        formula          = method.getFormula();
+        parameters       = method.getParameters();
+        sourceDimensions = method.getSourceDimensions();
+        targetDimensions = method.getTargetDimensions();
     }
 
     /**
      * Returns a SIS operation method implementation with the same values than the given arbitrary implementation.
-     * If the given object is {@code null}, then this method returns {@code null}.
+     * If the given object is {@code null}, then {@code null} is returned.
      * Otherwise if the given object is already a SIS implementation, then the given object is returned unchanged.
      * Otherwise a new SIS implementation is created and initialized to the attribute values of the given object.
      *
@@ -276,52 +320,140 @@ public class DefaultOperationMethod exte
      * The source and target dimensions may be {@code null} if this method can work with any number of dimensions
      * (e.g. <cite>Affine Transform</cite>).
      *
-     * @param method The operation method to copy.
-     * @param sourceDimension Number of dimensions in the source CRS of this operation method.
-     * @param targetDimension Number of dimensions in the target CRS of this operation method.
+     * @param method           The operation method to copy.
+     * @param sourceDimensions Number of dimensions in the source CRS of this operation method.
+     * @param targetDimensions Number of dimensions in the target CRS of this operation method.
      */
     private DefaultOperationMethod(final OperationMethod method,
-                                   final Integer sourceDimension,
-                                   final Integer targetDimension)
+                                   final Integer sourceDimensions,
+                                   final Integer targetDimensions)
     {
         super(method);
         this.formula    = method.getFormula();
         this.parameters = method.getParameters();
-        this.sourceDimension = sourceDimension;
-        this.targetDimension = targetDimension;
+        this.sourceDimensions = sourceDimensions;
+        this.targetDimensions = targetDimensions;
     }
 
     /**
-     * Returns an operation method with the same values than the specified one except the dimensions.
-     * The source and target dimensions may be {@code null} if this method can work with any number of dimensions
-     * (e.g. <cite>Affine Transform</cite>).
+     * Returns an operation method with different dimensions, if we are allowed to change dimensionality.
+     * This method accepts to change a dimension only if the value specified by the original method
+     * is {@code null}. Otherwise an {@link IllegalArgumentException} is thrown.
+     *
+     * @param method           The operation method to redimension.
+     * @param sourceDimensions The desired new source dimensions.
+     * @param methodSource     The current number of source dimensions (may be {@code null}).
+     * @param targetDimensions The desired new target dimensions.
+     * @param methodTarget     The current number of target dimensions (may be {@code null}).
+     * @throws IllegalArgumentException if the given dimensions are illegal for this operation method.
+     */
+    private static OperationMethod redimension(final OperationMethod method,
+            final int sourceDimensions, final Integer methodSource,
+            final int targetDimensions, final Integer methodTarget)
+    {
+        boolean sourceValids = (methodSource != null) && (methodSource == sourceDimensions);
+        boolean targetValids = (methodTarget != null) && (methodTarget == targetDimensions);
+        if (sourceValids && targetValids) {
+            return method;
+        }
+        sourceValids |= (methodSource == null);
+        targetValids |= (methodTarget == null);
+        ensurePositive("sourceDimensions", sourceDimensions);
+        ensurePositive("targetDimensions", targetDimensions);
+        if (!sourceValids || !targetValids) {
+            throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalOperationDimension_3,
+                    method.getName().getCode(), sourceDimensions, targetDimensions));
+        }
+        return new DefaultOperationMethod(method, sourceDimensions, targetDimensions);
+    }
+
+    /**
+     * Returns an operation method with different dimensions, if we are allowed to change dimensionality.
+     * The need to change an {@code OperationMethod} dimensionality may occur in two contexts:
+     *
+     * <ul>
+     *   <li><p>When the original method can work with any number of dimensions. Those methods do not know
+     *     in advance the number of dimensions, which is fixed only after the actual {@link MathTransform}
+     *     instance has been created.
+     *     Example: <cite>Affine</cite> conversion.</p></li>
+     *   <li><p>When a three-dimensional method can also be used in the two-dimensional case, typically by
+     *     assuming that the ellipsoidal height is zero everywhere.
+     *     Example: <cite>Molodensky</cite> transform.</p></li>
+     * </ul>
+     *
+     * This {@code redimension(…)} implementation performs the following choice:
      *
-     * @param  method The operation method to redimension, or {@code null}.
-     * @param  sourceDimension Number of dimensions in the source CRS of this operation method.
-     * @param  targetDimension Number of dimensions in the target CRS of this operation method.
-     * @return The redimensioned operation method, or {@code method} if the given method was {@code null}
-     *         or already had th given dimensions.
+     * <ul>
+     *   <li><p>If the given method is an instance of {@code DefaultOperationMethod}, then delegate to
+     *     {@link #redimension(int, int)} in order to allow subclasses to defines their own policy.
+     *     For example the <cite>Molodensky</cite> method needs to override.</p></li>
+     *   <li>Otherwise for each dimension (<var>source</var> and <var>target</var>):
+     *     <ul>
+     *       <li>If the corresponding dimension of the given method is {@code null}, then
+     *         set that dimension to the given value in a new {@code OperationMethod}.</li>
+     *       <li>Otherwise if the given value is not equal to the corresponding dimension
+     *         in the given method, throw an {@link IllegalArgumentException}.</li>
+     *     </ul>
+     *   </li>
+     * </ul>
+     *
+     * @param  method           The operation method to redimension, or {@code null}.
+     * @param  sourceDimensions The desired number of input dimensions.
+     * @param  targetDimensions The desired number of output dimensions.
+     * @return The redimensioned operation method, or {@code null} if the given method was null,
+     *         or {@code method} if no change is needed.
+     * @throws IllegalArgumentException if the given dimensions are illegal for the given operation method.
      */
     public static OperationMethod redimension(OperationMethod method,
-                                        final Integer sourceDimension,
-                                        final Integer targetDimension)
+            final int sourceDimensions, final int targetDimensions)
     {
-        if (sourceDimension != null) ensurePositive("sourceDimension", sourceDimension);
-        if (targetDimension != null) ensurePositive("targetDimension", targetDimension);
-        if (method != null && !(Objects.equals(sourceDimension, method.getSourceDimensions())
-                             && Objects.equals(targetDimension, method.getTargetDimensions())))
-        {
-            method = new DefaultOperationMethod(method, sourceDimension, targetDimension);
+        if (method != null) {
+            if (method instanceof DefaultOperationMethod) {
+                return ((DefaultOperationMethod) method).redimension(sourceDimensions, targetDimensions);
+            } else {
+                method = redimension(method, sourceDimensions, method.getSourceDimensions(),
+                                             targetDimensions, method.getTargetDimensions());
+            }
         }
         return method;
     }
 
     /**
+     * Returns this operation method with different dimensions, if we are allowed to change dimensionality.
+     * See {@link #redimension(OperationMethod, int, int)} for more information.
+     *
+     * <p>The default implementation performs the following choice:
+     * for each dimension (<var>source</var> and <var>target</var>):</p>
+     * <ul>
+     *   <li>If the corresponding dimension of the given method is {@code null}, then
+     *       set that dimension to the given value in a new {@code OperationMethod}.</li>
+     *   <li>Otherwise if the given value is not equal to the corresponding dimension
+     *       in the given method, throw an {@link IllegalArgumentException}.</li>
+     * </ul>
+     *
+     * Subclasses should override this method if they can work with different number of dimensions.
+     * For example a <cite>Molodensky</cite> transform usually works in a three-dimensional space,
+     * but can also work in a two-dimensional space by assuming that the ellipsoidal height is zero
+     * everywhere.
+     *
+     * @param  sourceDimensions The desired number of input dimensions.
+     * @param  targetDimensions The desired number of output dimensions.
+     * @return The redimensioned operation method, or {@code this} if no change is needed.
+     * @throws IllegalArgumentException if the given dimensions are illegal for this operation method.
+     *
+     * @since 0.6
+     */
+    public OperationMethod redimension(final int sourceDimensions, final int targetDimensions) {
+        return redimension(this, sourceDimensions, this.sourceDimensions,
+                                 targetDimensions, this.targetDimensions);
+    }
+
+    /**
      * Returns the GeoAPI interface implemented by this class.
      * The SIS implementation returns {@code OperationMethod.class}.
      *
      * <div class="note"><b>Note for implementors:</b>
-     * Subclasses usually do not need to override this method since GeoAPI does not define {@code OperationMethod}
+     * Subclasses usually do not need to override this information since GeoAPI does not define {@code OperationMethod}
      * sub-interface. Overriding possibility is left mostly for implementors who wish to extend GeoAPI with their
      * own set of interfaces.</div>
      *
@@ -337,29 +469,31 @@ public class DefaultOperationMethod exte
      * The base {@code CoordinateOperation} interface is usually one of the following subtypes:
      *
      * <ul>
-     *   <li>{@link org.opengis.referencing.operation.Transformation}
+     *   <li><p>{@link org.opengis.referencing.operation.Transformation}
      *     if the coordinate operation has some errors (typically of a few metres) because of the empirical process by
      *     which the operation parameters were determined. Those errors do not depend on the floating point precision
-     *     or the accuracy of the implementation algorithm.</li>
-     *   <li>{@link org.opengis.referencing.operation.Conversion}
+     *     or the accuracy of the implementation algorithm.</p></li>
+     *   <li><p>{@link org.opengis.referencing.operation.Conversion}
      *     if the coordinate operation is theoretically of infinite precision, ignoring the limitations of floating
-     *     point arithmetic (including rounding errors) and the approximations implied by finite series expansions.</li>
-     *   <li>{@link org.opengis.referencing.operation.Projection}
+     *     point arithmetic (including rounding errors) and the approximations implied by finite series expansions.</p></li>
+     *   <li><p>{@link org.opengis.referencing.operation.Projection}
      *     if the coordinate operation is a conversion (as defined above) converting geodetic latitudes and longitudes
      *     to plane (map) coordinates. This type can optionally be refined with one of the
      *     {@link org.opengis.referencing.operation.CylindricalProjection},
      *     {@link org.opengis.referencing.operation.ConicProjection} or
-     *     {@link org.opengis.referencing.operation.PlanarProjection} subtypes.</li>
+     *     {@link org.opengis.referencing.operation.PlanarProjection} subtypes.</p></li>
      * </ul>
      *
-     * In case of doubt, this method can conservatively return the base type.
-     * The default implementation returns {@code CoordinateOperation.class},
+     * In case of doubt, {@code getOperationType()} can conservatively return the base type.
+     * The default implementation returns {@code SingleOperation.class},
      * which is the most conservative return value.
      *
      * @return Interface implemented by all coordinate operations that use this method.
+     *
+     * @see org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory#getAvailableMethods(Class)
      */
-    public Class<? extends CoordinateOperation> getOperationType() {
-        return CoordinateOperation.class;
+    public Class<? extends SingleOperation> getOperationType() {
+        return SingleOperation.class;
     }
 
     /**
@@ -371,6 +505,9 @@ public class DefaultOperationMethod exte
      * this property is mandatory according ISO 19111, but optional in Apache SIS.</div>
      *
      * @return The formula used by this method, or {@code null} if unknown.
+     *
+     * @see DefaultFormula
+     * @see org.apache.sis.referencing.operation.transform.MathTransformProvider
      */
     @Override
     public Formula getFormula() {
@@ -382,10 +519,12 @@ public class DefaultOperationMethod exte
      * May be null if unknown, as in an <cite>Affine Transform</cite>.
      *
      * @return The dimension of source CRS, or {@code null} if unknown.
+     *
+     * @see org.apache.sis.referencing.operation.transform.AbstractMathTransform#getSourceDimensions()
      */
     @Override
     public Integer getSourceDimensions() {
-        return sourceDimension;
+        return sourceDimensions;
     }
 
     /**
@@ -393,10 +532,12 @@ public class DefaultOperationMethod exte
      * May be null if unknown, as in an <cite>Affine Transform</cite>.
      *
      * @return The dimension of target CRS, or {@code null} if unknown.
+     *
+     * @see org.apache.sis.referencing.operation.transform.AbstractMathTransform#getTargetDimensions()
      */
     @Override
     public Integer getTargetDimensions() {
-        return targetDimension;
+        return targetDimensions;
     }
 
     /**
@@ -404,7 +545,7 @@ public class DefaultOperationMethod exte
      *
      * <div class="note"><b>Departure from the ISO 19111 standard:</b>
      * this property is mandatory according ISO 19111, but may be null in Apache SIS if the
-     * {@linkplain #DefaultOperationMethod(MathTransform)} constructor has been unable to infer it.</div>
+     * {@link #DefaultOperationMethod(MathTransform)} constructor has been unable to infer it.</div>
      *
      * @return The parameters, or {@code null} if unknown.
      */
@@ -435,10 +576,10 @@ public class DefaultOperationMethod exte
                 case STRICT: {
                     // Name and identifiers have been compared by super.equals(object, mode).
                     final DefaultOperationMethod that = (DefaultOperationMethod) object;
-                    return Objects.equals(this.formula,         that.formula) &&
-                           Objects.equals(this.sourceDimension, that.sourceDimension) &&
-                           Objects.equals(this.targetDimension, that.targetDimension) &&
-                           Objects.equals(this.parameters,      that.parameters);
+                    return Objects.equals(this.formula,          that.formula) &&
+                           Objects.equals(this.sourceDimensions, that.sourceDimensions) &&
+                           Objects.equals(this.targetDimensions, that.targetDimensions) &&
+                           Objects.equals(this.parameters,       that.parameters);
                 }
                 case BY_CONTRACT: {
                     // Name and identifiers have been compared by super.equals(object, mode).
@@ -487,7 +628,7 @@ public class DefaultOperationMethod exte
      */
     @Override
     protected long computeHashCode() {
-        return super.computeHashCode() + Objects.hash(sourceDimension, targetDimension, parameters);
+        return super.computeHashCode() + Objects.hash(sourceDimensions, targetDimensions, parameters);
     }
 
     /**
@@ -515,7 +656,7 @@ public class DefaultOperationMethod exte
              * Transformation, ConcatenatedOperation, PassThroughOperation, or any user-defined type that
              * do not extend Projection. All other operation types are accepted.
              */
-            final Class<? extends CoordinateOperation> type = getOperationType();
+            final Class<? extends SingleOperation> type = getOperationType();
             if (Projection.class.isAssignableFrom(type) || type.isAssignableFrom(Projection.class)) {
                 return "Projection";
             }

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java?rev=1661575&r1=1661574&r2=1661575&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java [UTF-8] Sun Feb 22 23:02:52 2015
@@ -67,6 +67,8 @@ import org.apache.sis.internal.jdk7.Obje
  * @since   0.4
  * @version 0.5
  * @module
+ *
+ * @see org.apache.sis.parameter.TensorParameters
  */
 public final class Matrices extends Static {
     /**

Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java?rev=1661575&r1=1661574&r2=1661575&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java [UTF-8] Sun Feb 22 23:02:52 2015
@@ -41,6 +41,8 @@ import org.apache.sis.util.resources.Err
  * @since   0.4
  * @version 0.4
  * @module
+ *
+ * @see Matrices
  */
 public abstract class MatrixSIS implements Matrix, LenientComparable, Cloneable, Serializable {
     /**



Mime
View raw message