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}.
*