sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1577771 - in /sis/branches/JDK7/core: sis-referencing/src/main/java/org/apache/sis/parameter/ sis-referencing/src/test/java/org/apache/sis/parameter/ sis-referencing/src/test/java/org/apache/sis/test/suite/ sis-utility/src/main/java/org/ap...
Date Sat, 15 Mar 2014 01:08:33 GMT
Author: desruisseaux
Date: Sat Mar 15 01:08:33 2014
New Revision: 1577771

URL: http://svn.apache.org/r1577771
Log:
Completed TensorParameters. Still need more tests.

Added:
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorValues.java
  (with props)
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/TensorParametersTest.java
  (with props)
Modified:
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorParameters.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorParameters.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorParameters.java?rev=1577771&r1=1577770&r2=1577771&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorParameters.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorParameters.java
[UTF-8] Sat Mar 15 01:08:33 2014
@@ -43,6 +43,9 @@ import org.apache.sis.util.Numbers;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
 
+// Related to JDK7
+import java.util.Objects;
+
 
 /**
  * Creates parameter groups from tensors (usually matrices), and conversely.
@@ -168,6 +171,7 @@ public class TensorParameters<E> impleme
 
     /**
      * The elements for the 0 and 1 values, or {@code null} if unknown.
+     * Computed by {@link #createCache()}.
      */
     private transient E zero, one;
 
@@ -215,9 +219,9 @@ public class TensorParameters<E> impleme
     }
 
     /**
-     * Initializes the fields used for cached values: {@link #zero}, {@link #one} and the
{@link #parameters} array.
-     * The later is not assigned to the {@code parameters} field, but rather returned -
caller shall assign himself
-     * the returned value to the {@link #parameters} field.
+     * Initializes the fields used for cached values: {@link #zero}, {@link #one}, {@link
#valuesArrayType} and the
+     * {@link #parameters} array. The later is not assigned to the {@code parameters} field,
but rather returned.
+     * Caller shall assign himself the returned value to the {@link #parameters} field.
      *
      * <p>This method is invoked by constructor and on deserialization.</p>
      */
@@ -404,7 +408,7 @@ public class TensorParameters<E> impleme
     }
 
     /**
-     * Returns the indices of matrix element for the given parameter name.
+     * 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}
@@ -467,10 +471,8 @@ public class TensorParameters<E> impleme
                 return param;
             }
         }
-        ParameterNotFoundException e = new ParameterNotFoundException(Errors.format(
-                Errors.Keys.ParameterNotFound_2, caller.getName(), name), name);
-        e.initCause(cause);
-        throw e;
+        throw (ParameterNotFoundException) new ParameterNotFoundException(Errors.format(
+                Errors.Keys.ParameterNotFound_2, caller.getName(), name), name).initCause(cause);
     }
 
     /**
@@ -479,7 +481,7 @@ public class TensorParameters<E> impleme
      * @param indices    The indices parsed from a parameter name.
      * @param actualSize The current values of parameters that define the matrix (or tensor)
dimensions.
      */
-    private static boolean isInBounds(final int[] indices, final int[] actualSize) {
+    static boolean isInBounds(final int[] indices, final int[] actualSize) {
         for (int i=0; i<indices.length; i++) {
             final int index = indices[i];
             if (index < 0 || index >= actualSize[i]) {
@@ -518,20 +520,70 @@ public class TensorParameters<E> impleme
                 indices[j] = 0; // We have done a full turn at that dimension. Will increment
next dimension.
             }
         }
-        assert Arrays.equals(actualSize, indices) : Arrays.toString(actualSize);
         return UnmodifiableArrayList.wrap(parameters);
     }
 
     /**
-     * Creates a new instance of parameter group with matrix elements initialized to the
1 on the diagonal,
-     * and 0 everywhere else. The returned parameter group is extensible, i.e. the number
of elements will
-     * depend upon the value associated to the {@code numRow} and {@code numCol} parameters.
-     *
-     * @return A new parameter initialized to the default value.
-     */
-//  public ParameterValueGroup createValue() {
-//      return new MatrixParameterValues(this);
-//  }
+     * Creates a new instance of parameter group with default values of 1 on the diagonal,
and 0 everywhere else.
+     * The returned parameter group is extensible, i.e. the number of elements will depend
upon the value associated
+     * to the parameters that define the matrix (or tensor) dimension.
+     *
+     * <p>The properties map is given unchanged to the
+     * {@linkplain org.apache.sis.referencing.AbstractIdentifiedObject#AbstractIdentifiedObject(Map)
+     * identified object constructor}. The following table is a reminder of main (not all)
properties:</p>
+     *
+     * <table class="sis">
+     *   <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.referencing.ReferenceIdentifier} or {@link String}</td>
+     *     <td>{@link DefaultParameterDescriptorGroup#getName()}</td>
+     *   </tr>
+     *   <tr>
+     *     <td>{@value org.opengis.referencing.IdentifiedObject#ALIAS_KEY}</td>
+     *     <td>{@link org.opengis.util.GenericName} or {@link CharSequence} (optionally
as array)</td>
+     *     <td>{@link DefaultParameterDescriptorGroup#getAlias()}</td>
+     *   </tr>
+     *   <tr>
+     *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
+     *     <td>{@link DefaultParameterDescriptorGroup#getIdentifiers()}</td>
+     *   </tr>
+     *   <tr>
+     *     <td>{@value org.opengis.referencing.IdentifiedObject#REMARKS_KEY}</td>
+     *     <td>{@link org.opengis.util.InternationalString} or {@link String}</td>
+     *     <td>{@link DefaultParameterDescriptorGroup#getRemarks()}</td>
+     *   </tr>
+     * </table>
+     *
+     * @param  properties The properties to be given to the identified object.
+     * @return A new parameter group initialized to the default values.
+     */
+    public ParameterValueGroup createValueGroup(final Map<String,?> properties) {
+        return new TensorValues<>(properties, this);
+    }
+
+    /**
+     * Creates a new instance of parameter group initialized to the given matrix.
+     * This operation is allowed only for tensors of {@linkplain #rank() rank} 2.
+     *
+     * @param  properties The properties to be given to the identified object.
+     * @param  matrix The matrix to copy in the new parameter group.
+     * @return A new parameter group initialized to the given matrix.
+     */
+    public ParameterValueGroup createValueGroup(final Map<String,?> properties, final
Matrix matrix) {
+        if (dimensions.length != 2) {
+            throw new IllegalStateException();
+        }
+        ArgumentChecks.ensureNonNull("matrix", matrix);
+        final TensorValues<E> values = new TensorValues<>(properties, this);
+        values.setMatrix(matrix);
+        return values;
+    }
 
     /**
      * Constructs a matrix from a group of parameters.
@@ -542,14 +594,13 @@ public class TensorParameters<E> impleme
      * @throws InvalidParameterNameException if a parameter name was not recognized.
      */
     public Matrix toMatrix(final ParameterValueGroup parameters) throws InvalidParameterNameException
{
-        ArgumentChecks.ensureNonNull("parameters", parameters);
         if (dimensions.length != 2) {
             throw new IllegalStateException();
         }
-//      if (parameters instanceof MatrixParameterValues) {
-//          // More efficient implementation
-//          return ((MatrixParameterValues) parameters).getMatrix();
-//      }
+        ArgumentChecks.ensureNonNull("parameters", parameters);
+        if (parameters instanceof TensorValues) {
+            return ((TensorValues) parameters).toMatrix(); // More efficient implementation
+        }
         // Fallback on the general case (others implementations)
         final ParameterValue<?> numRow = parameters.parameter(dimensions[0].getName().getCode());
         final ParameterValue<?> numCol = parameters.parameter(dimensions[1].getName().getCode());
@@ -579,12 +630,43 @@ public class TensorParameters<E> impleme
     }
 
     /**
+     * Returns a hash code value for this object.
+     *
+     * @return A hash code value.
+     */
+    @Override
+    public int hashCode() {
+        return Objects.hash(elementType, prefix, separator) ^ Arrays.hashCode(dimensions);
+    }
+
+    /**
+     * Compares this object with the given object for equality.
+     *
+     * @param other The other object to compare with this object.
+     * @return {@code true} if both object are equal.
+     */
+    @Override
+    public boolean equals(final Object other) {
+        if (other == this) {
+            return true;
+        }
+        if (other.getClass() == getClass()) {
+            final TensorParameters<?> that = (TensorParameters<?>) other;
+            return elementType.equals(that.elementType) &&
+                   prefix     .equals(that.prefix)      &&
+                   separator  .equals(that.separator)   &&
+                   Arrays.equals(dimensions, that.dimensions);
+        }
+        return false;
+    }
+
+    /**
      * Invoked on deserialization for restoring the {@link #parameters} array.
      */
     private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException
{
         in.defaultReadObject();
         try {
-            final Field field = TensorParameters.class.getField("parameters");
+            final Field field = TensorParameters.class.getDeclaredField("parameters");
             field.setAccessible(true);
             field.set(this, createCache());
         } catch (ReflectiveOperationException e) {

Added: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorValues.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorValues.java?rev=1577771&view=auto
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorValues.java
(added)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorValues.java
[UTF-8] Sat Mar 15 01:08:33 2014
@@ -0,0 +1,485 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.parameter;
+
+import java.util.Map;
+import java.util.List;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.lang.reflect.Array;
+import org.opengis.referencing.operation.Matrix;
+import org.opengis.parameter.ParameterValue;
+import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.parameter.ParameterDescriptor;
+import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.parameter.GeneralParameterValue;
+import org.opengis.parameter.GeneralParameterDescriptor;
+import org.opengis.parameter.ParameterNotFoundException;
+import org.apache.sis.referencing.IdentifiedObjects;
+import org.apache.sis.referencing.AbstractIdentifiedObject;
+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.io.wkt.Formatter;
+import org.apache.sis.util.Utilities;
+import org.apache.sis.util.Classes;
+import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.ComparisonMode;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.Debug;
+
+
+/**
+ * The values for a group of tensor parameters. This value group is 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. Consequently, this {@code ParameterValueGroup} is
also its own
+ * mutable {@code ParameterDescriptorGroup}.
+ *
+ * @param <E> The type of tensor element values.
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @since   0.4 (derived from geotk-2.0)
+ * @version 0.4
+ * @module
+ */
+final class TensorValues<E> extends AbstractIdentifiedObject
+        implements ParameterDescriptorGroup, ParameterValueGroup, Cloneable
+{
+    /**
+     * Serial number for inter-operability with different versions.
+     */
+    private static final long serialVersionUID = -7747712999115044943L;
+
+    /**
+     * A provider of matrix descriptors.
+     */
+    private final TensorParameters<E> descriptors;
+
+    /**
+     * The parameter for the number of row, columns and other dimensions in the tensor.
+     */
+    private final ParameterValue<Integer>[] dimensions;
+
+    /**
+     * The parameter values. Each array element is itself an {@code ParameterValue} array,
+     * and so on until we have nested {@link TensorParameters#rank()} arrays.
+     *
+     * <p>Will be constructed only when first requested.
+     * May be resized at any moment if a {@link #dimensions} parameter value change.</p>
+     */
+    private Object[] values;
+
+    /**
+     * Constructs a new group of tensor parameters for the given properties.
+     */
+    @SuppressWarnings({"unchecked","rawtypes"})
+    TensorValues(final Map<String,?> properties, final TensorParameters<E> descriptors)
{
+        super(properties);
+        this.descriptors = descriptors;
+        dimensions = new ParameterValue[descriptors.rank()];
+        for (int i=0; i<dimensions.length; i++) {
+            dimensions[i] = descriptors.getDimensionDescriptor(i).createValue();
+        }
+    }
+
+    /**
+     * Constructs a copy of the given matrix parameters.
+     * 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) {
+        super(other);
+        descriptors = other.descriptors;
+        dimensions = other.dimensions.clone();
+        for (int i=0; i<dimensions.length; i++) {
+            final ParameterValue<Integer> dim = dimensions[i];
+            dimensions[i] = clone ? dim.clone() : dim.getDescriptor().createValue();
+        }
+        if (clone) {
+            values = clone(other.values);
+        }
+    }
+
+    /**
+     * Clones the given array of parameters.
+     * This method invokes itself for cloning sub-arrays.
+     */
+    private static Object[] clone(Object[] values) {
+        if (values != null) {
+            values = values.clone();
+            for (int i=0; i<values.length; i++) {
+                Object element = values[i];
+                if (element instanceof GeneralParameterValue) {
+                    element = ((GeneralParameterValue) element).clone();
+                } else {
+                    element = clone((Object[]) element);
+                }
+                values[i] = element;
+            }
+        }
+        return values;
+    }
+
+    /**
+     * Returns a clone of this group.
+     */
+    @Override
+    public ParameterValueGroup clone() {
+        return new TensorValues<>(this, true);
+    }
+
+    /**
+     * Returns a new group initialized to default values.
+     */
+    @Override
+    public ParameterValueGroup createValue() {
+        return new TensorValues<>(this, false);
+    }
+
+    /**
+     * Returns a description of this parameter value group. Returns always {@code this},
since
+     * the description depends on {@code "num_row"} and {@code "num_col"} parameter values.
+     */
+    @Override
+    public ParameterDescriptorGroup getDescriptor() {
+        return this;
+    }
+
+    /**
+     * Returns the parameters descriptors in this group. The amount of parameters depends
+     * on the value of {@code "num_row"} and {@code "num_col"} parameters.
+     */
+    @Override
+    public List<GeneralParameterDescriptor> descriptors() {
+        return descriptors.descriptors(dimensions());
+    }
+
+    /**
+     * Returns 1 since this group is considered mandatory.
+     */
+    @Override
+    public int getMinimumOccurs() {
+        return 1;
+    }
+
+    /**
+     * Returns 1 since we expect exactly one instance of this group.
+     */
+    @Override
+    public int getMaximumOccurs() {
+        return 1;
+    }
+
+    /**
+     * Returns the current tensor dimensions.
+     */
+    private int[] dimensions() {
+        final int[] indices = new int[dimensions.length];
+        for (int i=0; i<indices.length; i++) {
+            indices[i] = dimensions[i].intValue();
+        }
+        return indices;
+    }
+
+    /**
+     * Returns the parameter descriptor in this group for the specified name.
+     *
+     * @param  name The name of the parameter to search for.
+     * @return The parameter descriptor for the given name.
+     * @throws ParameterNotFoundException if there is no parameter for the given name.
+     */
+    @Override
+    public GeneralParameterDescriptor descriptor(String name) throws ParameterNotFoundException
{
+        name = CharSequences.trimWhitespaces(name);
+        ArgumentChecks.ensureNonEmpty("name", name);
+        return descriptors.descriptor(this, name, dimensions());
+    }
+
+    /**
+     * Returns the parameter value in this group for the specified name.
+     *
+     * @param  name The name of the parameter to search for.
+     * @return The parameter value for the given name.
+     * @throws ParameterNotFoundException if there is no parameter for the given name.
+     */
+    @Override
+    public ParameterValue<?> parameter(String name) throws ParameterNotFoundException
{
+        name = CharSequences.trimWhitespaces(name);
+        ArgumentChecks.ensureNonEmpty("name", name);
+        IllegalArgumentException cause = null;
+        int[] indices = null;
+        try {
+            indices = descriptors.nameToIndices(name);
+        } catch (IllegalArgumentException exception) {
+            cause = exception;
+        }
+        if (indices != null) {
+            final int[] actualSize = dimensions();
+            if (TensorParameters.isInBounds(indices, actualSize)) {
+                return parameter(indices, actualSize);
+            }
+        }
+        /*
+         * The given name is not a matrix (or tensor) element name.
+         * Verify if the requested parameters is one of those that
+         * specify the matrix/tensor size ("num_row" or "num_col").
+         */
+        final int rank = descriptors.rank();
+        for (int i=0; i<rank; i++) {
+            final ParameterDescriptor<Integer> param = descriptors.getDimensionDescriptor(i);
+            if (IdentifiedObjects.isHeuristicMatchForName(param, name)) {
+                return dimensions[i];
+            }
+        }
+        throw (ParameterNotFoundException) new ParameterNotFoundException(Errors.format(
+                Errors.Keys.ParameterNotFound_2, getName(), name), name).initCause(cause);
+    }
+
+    /**
+     * Returns the tensor element at the given indices.
+     */
+    private ParameterValue<E> parameter(final int[] indices, final int[] actualSize)
{
+        final int rank = dimensions.length;
+        if (indices.length != rank) {
+            throw new IllegalArgumentException(Errors.format(
+                    Errors.Keys.UnexpectedArrayLength_2, rank, indices.length));
+        }
+        /*
+         * At the end of the following loop, 'element' will be the TensorValues element
+         * and 'parent' will be the array which contain it at index indices[rank - 1].
+         */
+        Object[] parent = null;
+        Object element = values;
+        for (int i=0; i<rank; i++) {
+            if (element == null) {
+                /*
+                 * Creates new arrays only when first needed.
+                 * For rank 2, creates ParameterValue[][];
+                 * For rank 3, creates ParameterValue[][][];
+                 * etc.
+                 */
+                final Class<?> componentType = Classes.changeArrayDimension(ParameterValue.class,
rank - i);
+                element = Array.newInstance(componentType, actualSize[i]);
+                if (parent != null) {
+                    parent[indices[i-1]] = element;
+                } else {
+                    values = (Object[]) element;
+                }
+            } else {
+                /*
+                 * If we already have an array, makes sure that its length is sufficient.
Note that the array
+                 * could also be too long if the user reduced some tensor dimensions. We
do not trim too long
+                 * arrays in order to avoid inconsistent behavior if the user later brings
back the sensor
+                 * dimension to its old value. The inconsistent behavior would be to discard
the references to
+                 * existing values above 'actualSize[i]', because we would have some sequences
of operations
+                 * that discard them and some other sequences of operations that do not discard
them.
+                 * The easiest strategy is to never discard those extraneous references -
may not be ideal,
+                 * but at least it keep the behavior consistent for all sequences of operations.
+                 */
+                if (((Object[]) element).length <= indices[i]) {
+                    element = Arrays.copyOf((Object[]) element, actualSize[i]);
+                    parent[indices[i-1]] = element;
+                }
+            }
+            parent = (Object[]) element;
+            element = parent[indices[i]];
+        }
+        if (element == null) {
+            element = descriptors.getElementDescriptor(indices);
+            parent[indices[rank - 1]] = element;
+        }
+        return Parameters.cast((ParameterValue<?>) element, descriptors.getElementType());
+    }
+
+    /**
+     * Returns the parameters values in this group. The amount of parameters depends on the
value of
+     * {@code "num_row"} and {@code "num_col"} parameters. The parameter array will contains
only
+     * matrix elements which have been requested at least once by one of {@code parameter(…)}
methods.
+     * Never requested elements are left to their default value and omitted from the returned
array.
+     */
+    @Override
+    public List<GeneralParameterValue> values() {
+        final List<GeneralParameterValue> addTo = new ArrayList<>(16);
+        addTo.addAll(Arrays.asList(dimensions));
+        addValues(values, dimensions(), 0, addTo);
+        return Collections.unmodifiableList(addTo);
+    }
+
+    /**
+     * Implementation of {@link #values()} which adds parameter values to the given list.
+     * This method invokes itself recursively.
+     */
+    private static void addValues(final Object[] values, final int[] actualSize, int j,
+            final List<GeneralParameterValue> addTo)
+    {
+        if (values != null) {
+            final int length = Math.min(values.length, actualSize[j]);
+            if (++j != actualSize.length) {
+                for (int i=0; i<length; i++) {
+                    addValues((Object[]) values[i], actualSize, j, addTo);
+                }
+            } else {
+                for (int i=0; i<length; i++) {
+                    final Object value = values[i];
+                    if (value != null) {
+                        addTo.add((ParameterValue<?>) value);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Always throws an exception since this group does not contain subgroups.
+     */
+    @Override
+    public List<ParameterValueGroup> groups(final String name) throws ParameterNotFoundException
{
+        throw new ParameterNotFoundException(Errors.format(Errors.Keys.ParameterNotFound_2,
getName(), name), name);
+    }
+
+    /**
+     * Always throws an exception since this group does not contain subgroups.
+     */
+    @Override
+    public ParameterValueGroup addGroup(String name) throws ParameterNotFoundException, IllegalStateException
{
+        throw new ParameterNotFoundException(Errors.format(Errors.Keys.ParameterNotFound_2,
getName(), name), name);
+    }
+
+    /**
+     * Creates a matrix from this group of parameters.
+     * This operation is allowed only for tensors of {@linkplain #rank() rank} 2.
+     *
+     * @return A matrix created from this group of parameters.
+     */
+    final Matrix toMatrix() {
+        final int numRow = dimensions[0].intValue();
+        final int numCol = dimensions[1].intValue();
+        final Matrix matrix = Matrices.createDiagonal(numRow, numCol);
+        if (values != null) {
+            for (int j=0; j<numRow; j++) {
+                final ParameterValue<?>[] row = (ParameterValue<?>[]) values[j];
+                if (row != null) {
+                    for (int i=0; i<numCol; i++) {
+                        final ParameterValue<?> element = row[i];
+                        if (element != null) {
+                            matrix.setElement(j, i, element.doubleValue());
+                        }
+                    }
+                }
+            }
+        }
+        return matrix;
+    }
+
+    /**
+     * Sets all parameter values to the element value in the specified matrix.
+     * After this method call, {@link #values} will returns only the elements
+     * different from the default value.
+     *
+     * @param matrix The matrix to copy in this group of parameters.
+     */
+    public void setMatrix(final Matrix matrix) {
+        final int numRow = matrix.getNumRow();
+        final int numCol = matrix.getNumCol();
+        dimensions[0].setValue(numRow);
+        dimensions[1].setValue(numCol);
+        values = null;
+        final int[] indices = new int[2];
+        for (int j=0; j<numRow; j++) {
+            indices[0] = j;
+            ParameterValue<?>[] row = null;
+            for (int i=0; i<numCol; i++) {
+                indices[1] = i;
+                ParameterDescriptor<E> descriptor = descriptors.getElementDescriptor(indices);
+                final E def = descriptor.getDefaultValue();
+                final double element = matrix.getElement(j,i);
+                if (!(def instanceof Number) || !Numerics.equalsIgnoreZeroSign(element, ((Number)
def).doubleValue())) {
+                    final ParameterValue<?> value = descriptor.createValue();
+                    value.setValue(element);
+                    if (row == null) {
+                        row = new ParameterValue<?>[numCol];
+                        if (values == null) {
+                            values = new ParameterValue<?>[numRow][];
+                        }
+                        values[j] = row;
+                    }
+                    row[i] = value;
+                }
+            }
+        }
+    }
+
+    /**
+     * Compares this object with the specified one for equality.
+     */
+    @Override
+    public boolean equals(final Object object, final ComparisonMode mode) {
+        if (object == this) {
+            return true; // Slight optimization.
+        }
+        if (super.equals(object)) {
+            final TensorValues<?> that = (TensorValues<?>) object;
+            return Utilities.deepEquals(descriptors, that.descriptors, mode) &&
+                   Utilities.deepEquals(values(),    that.values(),    mode);
+        }
+        return false;
+    }
+
+    /**
+     * Invoked by {@link #hashCode()} for computing the hash code when first needed.
+     *
+     * @return {@inheritDoc}
+     */
+    @Override
+    protected long computeHashCode() {
+        return super.computeHashCode() + descriptors.hashCode();
+        // Do not use any field other than descriptors, because they are not immutable.
+    }
+
+    /**
+     * Returns a string representation of this group.
+     */
+    @Debug
+    @Override
+    public String toString() {
+        return ParameterFormat.sharedFormat(this);
+    }
+
+    /**
+     * Prints a string representation of this group to the {@linkplain System#out standard
output stream}.
+     */
+    @Debug
+    @Override
+    public void print() {
+        ParameterFormat.print(this);
+    }
+
+    /**
+     * Formats this group as a pseudo-<cite>Well Known Text</cite> element.
+     *
+     * @param  formatter The formatter where to format the inner content of this WKT element.
+     * @return {@code "ParameterGroup"}.
+     */
+    @Override
+    protected String formatTo(final Formatter formatter) {
+        super.formatTo(formatter);
+        WKTUtilities.append(this, formatter);
+        return "ParameterGroup";
+    }
+}

Propchange: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorValues.java
------------------------------------------------------------------------------
    svn:eol-style = native

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

Added: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/TensorParametersTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/TensorParametersTest.java?rev=1577771&view=auto
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/TensorParametersTest.java
(added)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/TensorParametersTest.java
[UTF-8] Sat Mar 15 01:08:33 2014
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.parameter;
+
+import java.util.Map;
+import java.util.List;
+import java.util.Random;
+import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.parameter.GeneralParameterDescriptor;
+import org.opengis.referencing.operation.Matrix;
+import org.apache.sis.referencing.operation.matrix.Matrices;
+import org.apache.sis.test.TestUtilities;
+import org.apache.sis.test.DependsOnMethod;
+import org.apache.sis.test.DependsOn;
+import org.apache.sis.test.TestCase;
+import org.junit.Test;
+
+import static java.util.Collections.singletonMap;
+import static org.opengis.test.Validators.validate;
+import static org.opengis.referencing.IdentifiedObject.NAME_KEY;
+import static org.apache.sis.parameter.TensorParameters.WKT1;
+import static org.apache.sis.test.MetadataAssert.*;
+
+
+/**
+ * Tests the {@link TensorParameters} class.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.4
+ * @version 0.4
+ * @module
+ */
+@DependsOn(ParametersTest.class)
+public final strictfp class TensorParametersTest extends TestCase {
+    /**
+     * Tests the list of WKT descriptors for a 1×1, 2×3 and 3×3 matrices.
+     */
+    @Test
+    public void testDescriptors() {
+        List<GeneralParameterDescriptor> descriptors = WKT1.descriptors(new int[] {1,
1});
+        assertEquals("num_row", descriptors.get(0).getName().getCode());
+        assertEquals("num_col", descriptors.get(1).getName().getCode());
+        assertEquals("elt_0_0", descriptors.get(2).getName().getCode());
+        assertEquals("size", 3, descriptors.size());
+
+        descriptors = WKT1.descriptors(new int[] {2, 3});
+        assertEquals("num_row", descriptors.get(0).getName().getCode());
+        assertEquals("num_col", descriptors.get(1).getName().getCode());
+        assertEquals("elt_0_0", descriptors.get(2).getName().getCode());
+        assertEquals("elt_0_1", descriptors.get(3).getName().getCode());
+        assertEquals("elt_0_2", descriptors.get(4).getName().getCode());
+        assertEquals("elt_1_0", descriptors.get(5).getName().getCode());
+        assertEquals("elt_1_1", descriptors.get(6).getName().getCode());
+        assertEquals("elt_1_2", descriptors.get(7).getName().getCode());
+        assertEquals("size", 8, descriptors.size());
+
+        descriptors = WKT1.descriptors(new int[] {3, 3});
+        assertEquals("num_row",  descriptors.get( 0).getName().getCode());
+        assertEquals("num_col",  descriptors.get( 1).getName().getCode());
+        assertEquals("elt_0_0",  descriptors.get( 2).getName().getCode());
+        assertEquals("elt_0_1",  descriptors.get( 3).getName().getCode());
+        assertEquals("elt_0_2",  descriptors.get( 4).getName().getCode());
+        assertEquals("elt_1_0",  descriptors.get( 5).getName().getCode());
+        assertEquals("elt_1_1",  descriptors.get( 6).getName().getCode());
+        assertEquals("elt_1_2",  descriptors.get( 7).getName().getCode());
+        assertEquals("elt_2_0",  descriptors.get( 8).getName().getCode());
+        assertEquals("elt_2_1",  descriptors.get( 9).getName().getCode());
+        assertEquals("elt_2_2",  descriptors.get(10).getName().getCode());
+        assertEquals("size", 11, descriptors.size());
+    }
+
+    /**
+     * Tests {@link TensorParameters#createValueGroup(Map, Matrix)} and its converse
+     * {@link TensorParameters#toMatrix(ParameterValueGroup)}.
+     */
+    @Test
+    @DependsOnMethod("testDescriptors")
+    public void testMatrixConversion() {
+        final int size = 8;
+        final Random random = TestUtilities.createRandomNumberGenerator();
+        for (int numRow = 2; numRow <= size; numRow++) {
+            for (int numCol = 2; numCol <= size; numCol++) {
+                final Matrix matrix = Matrices.createZero(numRow, numCol);
+                for (int j=0; j<numRow; j++) {
+                    for (int i=0; i<numCol; i++) {
+                        matrix.setElement(j, i, 200*random.nextDouble() - 100);
+                    }
+                }
+                final ParameterValueGroup group = WKT1.createValueGroup(singletonMap(NAME_KEY,
"Test"), matrix);
+                validate(group);
+                assertEquals("num_row",  numRow, group.parameter("num_row").intValue());
+                assertEquals("num_col",  numCol, group.parameter("num_col").intValue());
+                assertEquals("elements", matrix, WKT1.toMatrix(group));
+            }
+        }
+    }
+
+    /**
+     * Tests WKT formatting.
+     */
+    @Test
+    @DependsOnMethod("testMatrixConversion")
+    public void testWKT() {
+        final Matrix matrix = Matrices.createIdentity(4);
+        matrix.setElement(0,2,  4);
+        matrix.setElement(1,0, -2);
+        matrix.setElement(2,3,  7);
+        final ParameterValueGroup group = WKT1.createValueGroup(singletonMap(NAME_KEY, "Affine"),
matrix);
+        validate(group);
+        assertWktEquals(
+                "ParameterGroup[“Affine”,\n"      +
+                "  Parameter[“num_row”, 4],\n"    +
+                "  Parameter[“num_col”, 4],\n"    +
+                "  Parameter[“elt_0_2”, 4.0],\n"  +
+                "  Parameter[“elt_1_0”, -2.0],\n" +
+                "  Parameter[“elt_2_3”, 7.0]]", group);
+    }
+
+    /**
+     * Tests serialization.
+     */
+    @Test
+    public void testSerialization() {
+        assertSerializedEquals(TensorParameters.WKT1);
+    }
+}

Propchange: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/TensorParametersTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/TensorParametersTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java?rev=1577771&r1=1577770&r2=1577771&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
[UTF-8] Sat Mar 15 01:08:33 2014
@@ -58,6 +58,7 @@ import org.junit.BeforeClass;
     org.apache.sis.parameter.ParametersTest.class,
     org.apache.sis.parameter.ParameterBuilderTest.class,
     org.apache.sis.parameter.ParameterFormatTest.class,
+    org.apache.sis.parameter.TensorParametersTest.class,
     org.apache.sis.referencing.datum.BursaWolfParametersTest.class,
     org.apache.sis.referencing.datum.TimeDependentBWPTest.class,
     org.apache.sis.referencing.datum.DefaultEllipsoidTest.class,

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java?rev=1577771&r1=1577770&r2=1577771&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
[UTF-8] Sat Mar 15 01:08:33 2014
@@ -199,8 +199,9 @@ public final class Numerics extends Stat
     }
 
     /**
-     * Returns {@code true} if the given doubles are equals. Positive and negative zero are
-     * considered different, while a NaN value is considered equal to all other NaN values.
+     * Returns {@code true} if the given doubles are equal.
+     * Positive and negative zeros are considered different.
+     * NaN values are considered equal to all other NaN values.
      *
      * @param  o1 The first value to compare.
      * @param  o2 The second value to compare.
@@ -213,6 +214,18 @@ public final class Numerics extends Stat
     }
 
     /**
+     * Returns {@code true} if the given doubles are equal, ignoring the sign of zero values.
+     * NaN values are considered equal to all other NaN values.
+     *
+     * @param  o1 The first value to compare.
+     * @param  o2 The second value to compare.
+     * @return {@code true} if both values are equal.
+     */
+    public static boolean equalsIgnoreZeroSign(final double o1, final double o2) {
+        return (o1 == o2) || Double.doubleToLongBits(o1) == Double.doubleToLongBits(o2);
+    }
+
+    /**
      * Returns {@code true} if the given values are approximatively equal,
      * up to the {@linkplain #COMPARISON_THRESHOLD comparison threshold}.
      *



Mime
View raw message