sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jso...@apache.org
Subject svn commit: r1737191 - in /sis/branches/JDK8/core/sis-referencing/src: main/java/org/apache/sis/referencing/operation/transform/ test/java/org/apache/sis/referencing/operation/transform/ test/java/org/apache/sis/test/suite/
Date Thu, 31 Mar 2016 08:25:26 GMT
Author: jsorel
Date: Thu Mar 31 08:25:25 2016
New Revision: 1737191

URL: http://svn.apache.org/viewvc?rev=1737191&view=rev
Log:
Add non-linear transform 1D

Added:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LinearInterpolator1D.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/LinearInterpolator1DTest.java
Modified:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java

Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LinearInterpolator1D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LinearInterpolator1D.java?rev=1737191&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LinearInterpolator1D.java
(added)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LinearInterpolator1D.java
Thu Mar 31 08:25:25 2016
@@ -0,0 +1,149 @@
+/*
+ * 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.util.Arrays;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.ArraysExt;
+import org.opengis.referencing.operation.MathTransform1D;
+import org.opengis.referencing.operation.NoninvertibleTransformException;
+import org.opengis.referencing.operation.TransformException;
+
+/**
+ * {@link MathTransform1D} with linear interpolation between values.
+ *
+ * @author Johann Sorel (Geomatys)
+ * @author Remi Marechal (Geomatys)
+ */
+final class LinearInterpolator1D extends AbstractMathTransform1D {
+    private final double[] antecedent;
+    private final double[] values;
+    private boolean isIncreaseOrder = true;
+    private final int l;
+
+    /**
+     * <p>In this case an antecedents default table is construct such as : <br>
+     *
+     * [0, 1, ... , N] with N is length of image table values.<p>
+     *
+     * @param values image from antecedents table values.
+     */
+    public LinearInterpolator1D(double[] values) {
+        ArgumentChecks.ensureNonNull("values", values);
+        this.l          = values.length;
+        if (l < 2)
+            throw new IllegalArgumentException("table must have more than only two values");
+        this.values     = values;
+        this.antecedent = new double[l];
+        for (int v = 0;v<l;v++) this.antecedent[v] = v;
+    }
+
+    /**
+     * Two tables such as : f(antecedents) = values.
+     *
+     * @param antecedents "abscissa" table values.
+     * @param values image from antecedents table values.
+     */
+    public LinearInterpolator1D(double[] antecedents, double[] values) {
+        ArgumentChecks.ensureNonNull("values", values);
+        ArgumentChecks.ensureNonNull("antecedents", antecedents);
+        this.l = antecedents.length;
+        if (l<2)
+            throw new IllegalArgumentException("table must have more than only two values");
+        if (l != values.length)
+            throw new IllegalArgumentException("antecedents and values table must have same
length");
+        if (!ArraysExt.isSorted(antecedents, true)) {
+            final double[] antecedent2 = new double[l];
+            int id = l;
+            for (int i = 0; i < l; i++) antecedent2[i] = antecedents[--id];
+            if (!ArraysExt.isSorted(antecedent2, true))
+                throw new IllegalArgumentException("antecedents table must be strictly increasing
or decreasing");
+            isIncreaseOrder = false;
+        }
+        this.antecedent = antecedents;
+        this.values     = values;
+    }
+
+    /**
+     * {@inheritDoc }.
+     */
+    @Override
+    public double transform(double d) throws TransformException {
+        int ida, idb, idn, idn1;
+        if (isIncreaseOrder) {
+            ida = 0; idb  = l-1;
+            idn = 0; idn1 = 1;
+        } else {
+            ida = l-1; idb  = 0;
+            idn = 1;   idn1 = 0;
+        }
+        if (d <= antecedent[ida]) return values[ida];
+        if (d >= antecedent[idb]) return values[idb];
+        double x0, x1;
+        for (int id = 0; id < l-1; id++) {
+            x0 = antecedent[idn];
+            x1 = antecedent[idn1];
+            if      (d == x0) return values[idn];
+            else if (d == x1) return values[idn1];
+            else if (d > antecedent[idn] && d < antecedent[idn1])
+                return values[idn] + (values[idn1] - values[idn]) * ((d-x0) / (x1-x0));
+            idn++;idn1++;
+        }
+        return 0;//impossible
+    }
+
+    /**
+     * {@inheritDoc }.
+     * Note : for each segment lower sequence point derivative is inclusive
+     * whereas upper sequence point is exclusive.
+     */
+    @Override
+    public double derivative(double d) throws TransformException {
+        int idn, idn1;
+        if (isIncreaseOrder) {
+            idn  = 0; idn1 = 1;
+            if (d < antecedent[0] || d >= antecedent[l-1]) return 0;
+        } else {
+            idn  = 1; idn1 = 0;
+            if (d <= antecedent[l-1] || d > antecedent[0]) return 0;
+        }
+        for (int id = 0; id < l; id++) {
+            if ((d > antecedent[idn]  && d < antecedent[idn1]) || d == antecedent[id])
+                return (values[idn1]-values[idn]) / (antecedent[idn1]-antecedent[idn]);
+            idn++;idn1++;
+        }
+        return 0;//impossible
+    }
+
+    @Override
+    public MathTransform1D inverse() throws NoninvertibleTransformException {
+        if (!ArraysExt.isSorted(values, true)) {
+            final double[] values2 = new double[l];
+            int id = l;
+            for (int i = 0; i < l; i++) values2[i] = values[--id];
+            if (!ArraysExt.isSorted(values2, true))
+                throw new NoninvertibleTransformException("non inversible");
+        }
+        return new LinearInterpolator1D(values, antecedent);
+    }
+
+    @Override
+    public boolean isIdentity() {
+        return Arrays.equals(antecedent, values);
+    }
+
+}

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java?rev=1737191&r1=1737190&r2=1737191&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java
[UTF-8] Thu Mar 31 08:25:25 2016
@@ -419,4 +419,55 @@ public final class MathTransforms extend
         }
         return derivative;
     }
+
+    /**
+     * Create an 1D Transform for the given serie.
+     * <br>
+     * Values are expected to be in increasing or decreasing order and must
+     * not contain duplicates.
+     * <br>
+     * This method first try to find a regular scale between values to create a
+     * linear transform, otherwise a non linear transform is created.
+     *
+     * @param serie value serie
+     * @return MathTransform1D may not be linear
+     * @throws org.opengis.referencing.operation.TransformException
+     */
+    public static MathTransform1D create1D(final double[] serie) throws TransformException
{
+
+        if(serie.length==0){
+            throw new TransformException("Serie can not be empty");
+        }else if(serie.length==1){
+            //only one value, we use it as an offset
+            return (MathTransform1D) linear(1.0, serie[0]);
+        }
+
+        //search for a linear scale and verify values
+        boolean linear = true;
+        final double scale = serie[1]-serie[0];
+        final double sign = Math.signum(scale);
+        if(sign == 0.0) throw new TransformException("Serie contains a duplicated value at
index 0 and 1");
+
+        double candidate;
+        for(int i=1;i<serie.length-1;i++){
+            candidate = serie[i+1]-serie[i];
+            if(candidate == 0.0){
+                throw new TransformException("Serie contains a duplicated value at index
"+i+" and "+(i+1));
+            }
+            if(scale != candidate){
+                linear = false;
+                if(sign != Math.signum(candidate)){
+                    throw new TransformException("Serie is not sorted at index "+i+" and
"+(i+1));
+                }
+            }
+        }
+
+        if(linear){
+            return (MathTransform1D) linear(scale, serie[0]);
+        }else{
+            //unlinear transform
+            return new LinearInterpolator1D(serie);
+        }
+    }
+
 }

Added: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/LinearInterpolator1DTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/LinearInterpolator1DTest.java?rev=1737191&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/LinearInterpolator1DTest.java
(added)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/LinearInterpolator1DTest.java
Thu Mar 31 08:25:25 2016
@@ -0,0 +1,193 @@
+/*
+ * 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 org.apache.sis.test.TestCase;
+import org.junit.Assert;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.opengis.referencing.operation.MathTransform1D;
+import org.opengis.referencing.operation.NoninvertibleTransformException;
+import org.opengis.referencing.operation.TransformException;
+
+/**
+ * Test {@link LinearInterpolator1D} class.
+ *
+ * @author Remi Marechal (Geomatys).
+ */
+public class LinearInterpolator1DTest extends TestCase {
+
+    private double[] antecedent, values;
+
+    public LinearInterpolator1DTest() {
+    }
+
+    /**
+     * <p>antecedents in increasing order.<br>
+     * values in increasing order.</p>
+     * @throws TransformException
+     */
+    @Test
+    public void testIncreaseIncrease() throws TransformException{
+        antecedent = new double[]{0,1,2,3};
+        values     = new double[]{10,12,16,22};
+        testMath(true);
+    }
+
+    /**
+     * <p>antecedents in increasing order.<br>
+     * values in decreasing order.</p>
+     * @throws TransformException
+     */
+    @Test
+    public void testIncreaseDecrease() throws TransformException{
+        antecedent = new double[]{0,1,2,3};
+        values     = new double[]{35,27,22,5};
+        testMath(true);
+    }
+
+    /**
+     * <p>antecedents in decreasing order.<br>
+     * values in increasing order.</p>
+     * @throws TransformException
+     */
+    @Test
+    public void testDecreaseIncrease() throws TransformException{
+        antecedent = new double[]{2,-5,-96,-207};
+        values     = new double[]{-50,-20,7,105};
+        testMath(true);
+    }
+
+    /**
+     * <p>antecedents in decreasing order.<br>
+     * values in decreasing order.</p>
+     * @throws TransformException
+     */
+    @Test
+    public void testDecreaseDecrease() throws TransformException{
+        antecedent = new double[]{2,-5,-96,-207};
+        values     = new double[]{105,7,-19,-43};
+        testMath(true);
+    }
+
+    /**
+     * <p>antecedents in increasing order.<br>
+     * values in random order.</p>
+     * @throws TransformException
+     */
+    @Test
+    public void testIncreaseRandom() throws TransformException{
+        antecedent = new double[]{-52,-27,-13,2};
+        values     = new double[]{105,-19,7,-43};
+        testMath(false);
+    }
+
+    /**
+     * <p>antecedents in increasing order.<br>
+     * values in random order.</p>
+     * @throws TransformException
+     */
+    @Test
+    public void testDecreaseRandom() throws TransformException{
+        antecedent = new double[]{1017,525,24,12};
+        values     = new double[]{-43,7,-19,105};
+        testMath(false);
+    }
+
+    /**
+     * <p>antecedents in increasing order.<br>
+     * values in random order.</p>
+     * @throws TransformException
+     */
+    @Test
+    public void testDcnsPercent() throws TransformException{
+        antecedent = new double[]{5, 6.5, 8, 10, 25, 28, 30, 32};
+        values     = new double[]{100, 66, 33, 0, 0, 33, 66, 100};
+        testMath(false);
+    }
+
+    /**
+     * Test fail.
+     */
+    @Test
+    public void testFail() throws TransformException{
+        antecedent = new double[]{-43,7,-19,105};
+        values     = new double[]{1017,525,24,12};
+        try {
+            MathTransform1D mt = new LinearInterpolator1D(antecedent, values);
+            Assert.fail("test should had failed");
+        } catch (Exception e) {
+            //ok
+        }
+
+        antecedent = new double[]{1017,525,24,12};
+        values     = new double[]{-43,7,-19,105};
+        MathTransform1D mt = new LinearInterpolator1D(antecedent, values);
+        try {
+            mt.inverse();
+            Assert.fail("test should had failed");
+        } catch (Exception e) {
+            //ok
+        }
+        antecedent = new double[]{1017,525,24,12,45};
+        values     = new double[]{-43,7,-19,105};
+        try {
+            mt = new LinearInterpolator1D(antecedent, values);
+            Assert.fail("test should had failed");
+        } catch (Exception e) {
+            //ok
+        }
+    }
+
+    /**
+     * Test MathTransform.
+     *
+     * @param testInvert apply test on invert transform if true else not.
+     * @throws NoninvertibleTransformException
+     * @throws TransformException
+     */
+    private void testMath (boolean testInvert) throws NoninvertibleTransformException, TransformException
{
+        final MathTransform1D math1 = new LinearInterpolator1D(antecedent, values);
+        MathTransform1D mathInvert = null;
+        if (testInvert) mathInvert = math1.inverse();
+        int step = 10;
+        final int l = antecedent.length;
+        for (int i = 0; i < l-1; i++) {
+            final double a0    = antecedent[i];
+            final double v0    = values[i];
+            double pasX        = antecedent[i+1] - a0;
+            double pasY        = values[i+1] - v0;
+            final double deriv = pasY / pasX;
+            pasX /= step;
+            pasY /= step;
+            for (int s = 0; s < step; s++) {
+                //mathtransform
+                final double x = a0 + s*pasX;
+                final double y = math1.transform(x);
+                //derivative
+                assertTrue(y-(v0+s*pasY) <= 1E-9);
+                if (s != step-1) assertTrue(math1.derivative(x) - deriv <= 1E-9);
+                if (testInvert) {
+                    //inverse transform
+                    assertTrue(mathInvert.transform(y)-x <= 1E-9);
+                    //inverse derivative
+                    if (s != step-1) assertTrue(mathInvert.derivative(y)-(1/deriv) <=
1E-9);
+                }
+            }
+        }
+    }
+}

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java?rev=1737191&r1=1737190&r2=1737191&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
[UTF-8] Thu Mar 31 08:25:25 2016
@@ -112,6 +112,7 @@ import org.junit.BeforeClass;
     org.apache.sis.referencing.operation.transform.ScaleTransformTest.class,
     org.apache.sis.referencing.operation.transform.ProjectiveTransformTest.class,
     org.apache.sis.referencing.operation.transform.LinearTransformTest.class,
+    org.apache.sis.referencing.operation.transform.LinearInterpolator1DTest.class,
     org.apache.sis.referencing.operation.transform.ExponentialTransform1DTest.class,
     org.apache.sis.referencing.operation.transform.LogarithmicTransform1DTest.class,
     org.apache.sis.referencing.operation.transform.CopyTransformTest.class,



Mime
View raw message