Author: desruisseaux
Date: Fri Jun 6 20:25:35 2014
New Revision: 1600997
URL: http://svn.apache.org/r1600997
Log:
Cleaning and port of a first non-linear class.
Added:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PowerTransform1D.java
(with props)
Modified:
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PassThroughTransformTest.java
Modified:
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java?rev=1600997&r1=1600996&r2=1600997&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java
[UTF-8] Fri Jun 6 20:25:35 2014
@@ -170,7 +170,7 @@ public abstract class AbstractAssociatio
* Sets the features. All previous values are replaced by the given
collection.
*
* <p>The default implementation ensures that the given collection
contains at most one element,
- * then delegates to {@link #setValue(AbstractFeature)}.</p>
+ * then delegates to {@link #setValue(Feature)}.</p>
*
* @param values The new values.
* @throws IllegalArgumentException if the given collection contains too
many elements.
Modified:
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java?rev=1600997&r1=1600996&r2=1600997&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
[UTF-8] Fri Jun 6 20:25:35 2014
@@ -150,7 +150,7 @@ public abstract class AbstractFeature im
* }
*
* <div class="note"><b>Note:</b> This method is useful for storing
non-default {@code Attribute} or
- * {@code Association} implementations in this feature. When default
implementations are sufficient,
+ * {@code FeatureAssociation} implementations in this feature. When
default implementations are sufficient,
* the {@link #setPropertyValue(String, Object)} method is preferred.</div>
*
* @param property The property to set.
@@ -239,11 +239,11 @@ public abstract class AbstractFeature im
*
* <table class="sis">
* <caption>Class of returned value</caption>
- * <tr><th>Property type</th> <th>max. occurs</th> <th>Method
invoked</th> <th>Return type</th></tr>
- * <tr><td>{@link AttributeType}</td> <td>0 or 1</td> <td>{@link
Attribute#getValue()}</td> <td>{@link Object}</td></tr>
- * <tr><td>{@code AttributeType}</td> <td>2 or more</td> <td>{@link
Attribute#getValues()}</td> <td>{@code Collection<?>}</td></tr>
- * <tr><td>{@link AssociationRole}</td> <td>0 or 1</td> <td>{@link
Association#getValue()}</td> <td>{@link Feature}</td></tr>
- * <tr><td>{@code AssociationRole}</td> <td>2 or more</td> <td>{@link
Association#getValues()}</td> <td>{@code Collection<Feature>}</td></tr>
+ * <tr><th>Property type</th> <th>max. occurs</th> <th>Method
invoked</th> <th>Return type</th></tr>
+ * <tr><td>{@link AttributeType}</td> <td>0 or 1</td> <td>{@link
Attribute#getValue()}</td> <td>{@link Object}</td></tr>
+ * <tr><td>{@code AttributeType}</td> <td>2 or more</td> <td>{@link
Attribute#getValues()}</td> <td>{@code Collection<?>}</td></tr>
+ * <tr><td>{@link AssociationRole}</td> <td>0 or 1</td> <td>{@link
FeatureAssociation#getValue()}</td> <td>{@link Feature}</td></tr>
+ * <tr><td>{@code AssociationRole}</td> <td>2 or more</td> <td>{@link
FeatureAssociation#getValues()}</td> <td>{@code Collection<Feature>}</td></tr>
* </table>
*
* <div class="note"><b>Note:</b> “max. occurs” is the {@linkplain
DefaultAttributeType#getMaximumOccurs() maximum
Added:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PowerTransform1D.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PowerTransform1D.java?rev=1600997&view=auto
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PowerTransform1D.java
(added)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PowerTransform1D.java
[UTF-8] Fri Jun 6 20:25:35 2014
@@ -0,0 +1,202 @@
+/*
+ * 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.referencing.operation.transform;
+
+import java.io.Serializable;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.MathTransform1D;
+import org.apache.sis.internal.util.Numerics;
+import org.apache.sis.util.ComparisonMode;
+
+
+/**
+ * Raises the given value at some fixed power. Current implementation is
defined mostly for the
+ * needs of the {@link
ExponentialTransform1D#concatenateLog(LogarithmicTransform1D, boolean)}.
+ * Future version may expand on that.
+ *
+ * <p>Before to make this class public (if we do), we need to revisit the
class name, define
+ * parameters and improve the {@link #concatenate(MathTransform, boolean)}
method.</p>
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.5 (derived from geotk-3.17)
+ * @version 0.5
+ * @module
+ */
+final class PowerTransform1D extends AbstractMathTransform1D implements
Serializable {
+ /**
+ * Serial number for inter-operability with different versions.
+ */
+ private static final long serialVersionUID = 4618931749313510016L;
+
+ /**
+ * The power.
+ */
+ final double power;
+
+ /**
+ * The inverse of this transform. Created only when first needed.
+ * Serialized in order to avoid rounding error if this transform
+ * is actually the one which was created from the inverse.
+ */
+ private PowerTransform1D inverse;
+
+ /**
+ * Constructs a new exponential transform. This constructor is provided
for subclasses only.
+ * Instances should be created using the {@linkplain #create(double)
factory method}, which
+ * may returns optimized implementations for some particular argument
values.
+ *
+ * @param power The power at which to raise the values.
+ */
+ protected PowerTransform1D(final double power) {
+ this.power = power;
+ }
+
+ /**
+ * Constructs a new power transform.
+ *
+ * @param power The power at which to raise the values.
+ * @return The math transform.
+ */
+ public static MathTransform1D create(final double power) {
+ if (power == 1) return IdentityTransform1D.INSTANCE;
+ if (power == 0) return new ConstantTransform1D(1);
+ return new PowerTransform1D(power);
+ }
+
+ /**
+ * Creates the inverse transform of this object.
+ */
+ @Override
+ public MathTransform1D inverse() {
+ if (inverse == null) {
+ inverse = new PowerTransform1D(1 / power);
+ inverse.inverse = this;
+ }
+ return inverse;
+ }
+
+ /**
+ * Gets the derivative of this function at a value.
+ */
+ @Override
+ public double derivative(final double value) {
+ return power * Math.pow(value, power - 1);
+ }
+
+ /**
+ * Transforms the specified value.
+ */
+ @Override
+ public double transform(final double value) {
+ return Math.pow(value, power);
+ }
+
+ /**
+ * Transforms many coordinates in a list of ordinal values.
+ */
+ @Override
+ public void transform(final double[] srcPts, int srcOff, final double[]
dstPts, int dstOff, int numPts) {
+ if (srcPts!=dstPts || srcOff>=dstOff) {
+ while (--numPts >= 0) {
+ dstPts[dstOff++] = Math.pow(srcPts[srcOff++], power);
+ }
+ } else {
+ srcOff += numPts;
+ dstOff += numPts;
+ while (--numPts >= 0) {
+ dstPts[--dstOff] = Math.pow(srcPts[--srcOff], power);
+ }
+ }
+ }
+
+ /**
+ * Transforms many coordinates in a list of ordinal values.
+ */
+ @Override
+ public void transform(final float[] srcPts, int srcOff, final float[]
dstPts, int dstOff, int numPts) {
+ if (srcPts!=dstPts || srcOff>=dstOff) {
+ while (--numPts >= 0) {
+ dstPts[dstOff++] = (float) Math.pow(srcPts[srcOff++], power);
+ }
+ } else {
+ srcOff += numPts;
+ dstOff += numPts;
+ while (--numPts >= 0) {
+ dstPts[--dstOff] = (float) Math.pow(srcPts[--srcOff], power);
+ }
+ }
+ }
+
+ /**
+ * Transforms many coordinates in a list of ordinal values.
+ */
+ @Override
+ public void transform(final double[] srcPts, int srcOff, final float[]
dstPts, int dstOff, int numPts) {
+ while (--numPts >= 0) {
+ dstPts[dstOff++] = (float) Math.pow(srcPts[srcOff++], power);
+ }
+ }
+
+ /**
+ * Transforms many coordinates in a list of ordinal values.
+ */
+ @Override
+ public void transform(final float[] srcPts, int srcOff, final double[]
dstPts, int dstOff, int numPts) {
+ while (--numPts >= 0) {
+ dstPts[dstOff++] = Math.pow(srcPts[srcOff++], power);
+ }
+ }
+
+ /**
+ * Concatenates in an optimized way a {@link MathTransform} {@code other}
to this {@code MathTransform}.
+ *
+ * @param other The math transform to apply.
+ * @param applyOtherFirst {@code true} if the transformation order is
{@code other} followed by {@code this},
+ * or {@code false} if the transformation order is {@code this}
followed by {@code other}.
+ * @return The combined math transform, or {@code null} if no optimized
combined transform is available.
+ */
+ @Override
+ final MathTransform concatenate(final MathTransform other, final boolean
applyOtherFirst) {
+ if (other instanceof PowerTransform1D) {
+ return create(power + ((PowerTransform1D) other).power);
+ }
+ // TODO: more optimization could go here for logarithmic and
exponential cases.
+ return super.concatenate(other, applyOtherFirst);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected int computeHashCode() {
+ return super.computeHashCode() +
Numerics.hashCode(Double.doubleToLongBits(power));
+ }
+
+ /**
+ * Compares the specified object with this math transform for equality.
+ */
+ @Override
+ public boolean equals(final Object object, final ComparisonMode mode) {
+ if (object == this) {
+ return true; // Slight optimization
+ }
+ if (super.equals(object, mode)) {
+ return Numerics.equals(power, ((PowerTransform1D) object).power);
+ }
+ return false;
+ }
+}
Propchange:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PowerTransform1D.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PowerTransform1D.java
------------------------------------------------------------------------------
svn:mime-type = text/plain;charset=UTF-8
Modified:
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PassThroughTransformTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PassThroughTransformTest.java?rev=1600997&r1=1600996&r2=1600997&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PassThroughTransformTest.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PassThroughTransformTest.java
[UTF-8] Fri Jun 6 20:25:35 2014
@@ -23,13 +23,14 @@ import org.opengis.referencing.operation
import org.opengis.referencing.operation.TransformException;
import org.apache.sis.referencing.operation.matrix.Matrix3;
import org.apache.sis.internal.util.Numerics;
+import org.apache.sis.util.ArraysExt;
// Test imports
import org.junit.Test;
import org.opengis.test.CalculationType;
import org.opengis.test.ToleranceModifier;
import org.apache.sis.test.TestUtilities;
-import org.apache.sis.util.ArraysExt;
+import org.apache.sis.test.DependsOn;
import static org.junit.Assert.*;
@@ -37,14 +38,12 @@ import static org.junit.Assert.*;
/**
* Tests {@link PassThroughTransform}.
*
- * <p>The {@link DimensionFilter} class is also tested in order to ensure that
it
- * can gives back the original transform.</p>
- *
* @author Martin Desruisseaux (IRD, Geomatys)
* @since 0.5 (derived from geotk-2.0)
* @version 0.5
* @module
*/
+@DependsOn(LinearTransformTest.class)
public final strictfp class PassThroughTransformTest extends
MathTransformTestCase {
/**
* The random number generator to be used in this test.
@@ -102,16 +101,15 @@ public final strictfp class PassThroughT
}
/**
- * Tests the general pass-through transform. This test needs a non-linear
sub-transform
- * for preventing the factory method to optimize.
+ * Tests the general pass-through transform.
+ * This test uses a non-linear sub-transform for preventing the factory
method to optimize.
*
* @throws TransformException Should never happen.
*/
// TODO
// @Test
// public void testPassthrough() throws TransformException {
-// final ParameterValueGroup param =
mtFactory.getDefaultParameters("Exponential");
-// runTest(mtFactory.createParameterizedTransform(param),
PassThroughTransform.class);
+// runTest(ExponentialTransform1D.create(10, -2),
PassThroughTransform.class);
// }
/**
@@ -126,20 +124,13 @@ public final strictfp class PassThroughT
{
random = TestUtilities.createRandomNumberGenerator();
/*
- * Tests many combinations of "first affected ordinate" and "number of
trailing ordinates"
- * parameters. For each combination we create a passthrough transform,
test it with the
- * "verifyTransform" method, then try to split it back to the original
transform using
- * the DimensionFilter class.
+ * Test many combinations of "first affected ordinate" and "number of
trailing ordinates" parameters.
+ * For each combination we create a passthrough transform, test it
with the 'verifyTransform' method.
*/
-// TODO final DimensionFilter filter = new DimensionFilter(mtFactory);
for (int firstAffectedOrdinate=0; firstAffectedOrdinate<=3;
firstAffectedOrdinate++) {
- final int firstTrailingOrdinate = firstAffectedOrdinate +
subTransform.getSourceDimensions();
for (int numTrailingOrdinates=0; numTrailingOrdinates<=3;
numTrailingOrdinates++) {
final int numAdditionalOrdinates = firstAffectedOrdinate +
numTrailingOrdinates;
transform = PassThroughTransform.create(firstAffectedOrdinate,
subTransform, numTrailingOrdinates);
- /*
- * Test the PassthroughTransform.
- */
if (numAdditionalOrdinates == 0) {
assertSame("Failed to recognize that no passthrough was
needed.", subTransform, transform);
continue;
@@ -151,28 +142,6 @@ public final strictfp class PassThroughT
assertEquals ("Wrong number of target dimensions.",
subTransform.getTargetDimensions() +
numAdditionalOrdinates, transform.getTargetDimensions());
verifyTransform(subTransform, firstAffectedOrdinate);
- /*
- * Split the PassthroughTransform back to the original
sub-transform.
- */
-// if (firstAffectedOrdinate != 0) {
-// filter.addSourceDimensionRange(0, firstAffectedOrdinate);
-// assertTrue("Expected an identity transform.",
filter.separate(transform).isIdentity());
-// filter.clear();
-// }
-// if (numTrailingOrdinates != 0) {
-// filter.addSourceDimensionRange(firstTrailingOrdinate,
transform.getSourceDimensions());
-// assertTrue("Expected an identity transform.",
filter.separate(transform).isIdentity());
-// filter.clear();
-// }
-// filter.addSourceDimensionRange(firstAffectedOrdinate,
firstTrailingOrdinate);
-// assertEquals("Expected the sub-transform.", subTransform,
filter.separate(transform));
-// final int[] expectedDimensions = new
int[subTransform.getTargetDimensions()];
-// for (int i=0; i<expectedDimensions.length; i++) {
-// expectedDimensions[i] = firstAffectedOrdinate + i;
-// }
-// assertTrue("Unexpected output dimensions",
-// Arrays.equals(expectedDimensions,
filter.getTargetDimensions()));
-// filter.clear();
}
}
}
@@ -218,31 +187,37 @@ public final strictfp class PassThroughT
Arrays.equals(passthroughData, expectedData));
/*
* Now process to the transform and compares the results with the
expected ones.
- * We perform a copy of the source data before to transform them in
order to use
- * the same values for running the GeoAPI tests as the next step.
*/
tolerance = 0; // Results should be strictly identical because
we used the same inputs.
toleranceModifier = null;
- final float[] sourceAsFloat = Numerics.copyAsFloats(passthroughData);
- transform.transform(passthroughData, 0, passthroughData, 0, numPts);
- assertCoordinatesEqual("Expected a plain copy.", passthroughDim,
- expectedData, 0, passthroughData, 0, numPts,
CalculationType.IDENTITY);
+ final double[] transformedData = new double[expectedData.length];
+ transform.transform(passthroughData, 0, transformedData, 0, numPts);
+ assertCoordinatesEqual("Direct transform.", passthroughDim,
+ expectedData, 0, transformedData, 0, numPts,
CalculationType.DIRECT_TRANSFORM);
/*
- * Verify the consistency between different 'transform(…)' methods.
- * We use a relatively high tolerance threshold because result are
- * computed using inputs stored as float values.
+ * Test inverse transform.
*/
- tolerance = 1E-4f;
+ tolerance = 1E-8;
toleranceModifier = ToleranceModifier.RELATIVE;
+ Arrays.fill(transformedData, Double.NaN);
+ transform.inverse().transform(expectedData, 0, transformedData, 0,
numPts);
+ assertCoordinatesEqual("Inverse transform.", passthroughDim,
+ passthroughData, 0, transformedData, 0, numPts,
CalculationType.INVERSE_TRANSFORM);
+ /*
+ * Verify the consistency between different 'transform(…)' methods.
+ */
+ final float[] sourceAsFloat = Numerics.copyAsFloats(passthroughData);
final float[] targetAsFloat = verifyConsistency(sourceAsFloat);
assertEquals("Unexpected length of transformed array.",
expectedData.length, targetAsFloat.length);
- assertCoordinatesEqual("A transformed value is wrong.", passthroughDim,
- expectedData, 0, targetAsFloat, 0, numPts,
CalculationType.DIRECT_TRANSFORM);
/*
- * Test inverse transform.
+ * We use a relatively high tolerance threshold because result are
+ * computed using inputs stored as float values.
*/
- transform.inverse().transform(passthroughData, 0, passthroughData, 0,
numPts);
- assertCoordinatesEqual("A transformed value is wrong.", passthroughDim,
- sourceAsFloat, 0, passthroughData, 0, numPts,
CalculationType.DIRECT_TRANSFORM);
+ if (transform instanceof LinearTransform) {
+ tolerance = 1E-4;
+ toleranceModifier = ToleranceModifier.RELATIVE;
+ assertCoordinatesEqual("A transformed value is wrong.",
passthroughDim,
+ expectedData, 0, targetAsFloat, 0, numPts,
CalculationType.DIRECT_TRANSFORM);
+ }
}
}