You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2017/03/27 16:34:20 UTC
svn commit: r1788982 [2/2] - in /sis/branches/JDK7: ./
core/sis-feature/src/main/java/org/apache/sis/feature/
core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/
core/sis-referencing/src/main/java/org/apache/sis/inte...
Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilderTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilderTest.java?rev=1788982&r1=1788981&r2=1788982&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilderTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilderTest.java [UTF-8] Mon Mar 27 16:34:20 2017
@@ -16,8 +16,11 @@
*/
package org.apache.sis.referencing.operation.builder;
+import java.util.Map;
+import java.util.HashMap;
import java.util.Random;
import java.awt.geom.AffineTransform;
+import org.opengis.util.FactoryException;
import org.opengis.referencing.operation.Matrix;
import org.apache.sis.geometry.DirectPosition1D;
import org.apache.sis.geometry.DirectPosition2D;
@@ -34,23 +37,28 @@ import static org.junit.Assert.*;
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.5
- * @version 0.5
+ * @version 0.8
* @module
*/
public final strictfp class LinearTransformBuilderTest extends TestCase {
/**
* Tests a very simple case where an exact answer is expected.
+ *
+ * @throws FactoryException if the transform can not be created.
*/
@Test
- public void testMinimalist1D() {
+ public void testMinimalist1D() throws FactoryException {
final LinearTransformBuilder builder = new LinearTransformBuilder();
- builder.setSourcePoints(
- new DirectPosition1D(1),
- new DirectPosition1D(2));
- builder.setTargetPoints(
- new DirectPosition1D(1),
- new DirectPosition1D(3));
- final Matrix m = builder.create().getMatrix();
+ final Map<DirectPosition1D,DirectPosition1D> pos = new HashMap<>(4);
+ assertNull(pos.put(new DirectPosition1D(1), new DirectPosition1D(1)));
+ assertNull(pos.put(new DirectPosition1D(2), new DirectPosition1D(3)));
+ builder.setControlPoints(pos);
+
+ assertArrayEquals(new double[] {1}, builder.getControlPoint(new int[] {1}), STRICT);
+ assertArrayEquals(new double[] {3}, builder.getControlPoint(new int[] {2}), STRICT);
+ assertNull( builder.getControlPoint(new int[] {3}));
+
+ final Matrix m = builder.create(null).getMatrix();
assertEquals("m\u2080\u2080", 2, m.getElement(0, 0), STRICT);
assertEquals("m\u2080\u2081", -1, m.getElement(0, 1), STRICT);
assertArrayEquals("correlation", new double[] {1}, builder.correlation(), STRICT);
@@ -61,9 +69,11 @@ public final strictfp class LinearTransf
* Tolerance threshold is set to zero because the math transform has been built from exactly 3 points,
* in which case we expect an exact solution without rounding errors at the scale of the {@code double}
* type. This is possible because SIS implementation uses double-double arithmetic.
+ *
+ * @throws FactoryException if the transform can not be created.
*/
@Test
- public void testMinimalist2D() {
+ public void testMinimalist2D() throws FactoryException {
final LinearTransformBuilder builder = new LinearTransformBuilder();
builder.setSourcePoints(
new DirectPosition2D(1, 1),
@@ -73,7 +83,13 @@ public final strictfp class LinearTransf
new DirectPosition2D(3, 2),
new DirectPosition2D(3, 5),
new DirectPosition2D(5, 5));
- final Matrix m = builder.create().getMatrix();
+
+ assertArrayEquals(new double[] {3, 2}, builder.getControlPoint(new int[] {1, 1}), STRICT);
+ assertArrayEquals(new double[] {3, 5}, builder.getControlPoint(new int[] {1, 2}), STRICT);
+ assertArrayEquals(new double[] {5, 5}, builder.getControlPoint(new int[] {2, 2}), STRICT);
+ assertNull( builder.getControlPoint(new int[] {2, 1}));
+
+ final Matrix m = builder.create(null).getMatrix();
// First row (x)
assertEquals("m\u2080\u2080", 2, m.getElement(0, 0), STRICT);
@@ -89,11 +105,96 @@ public final strictfp class LinearTransf
}
/**
+ * Tests a two-dimensional case where sources coordinates are explicitely given.
+ *
+ * @throws FactoryException if the transform can not be created.
+ *
+ * @since 0.8
+ */
+ @Test
+ public void testExplicitSource2D() throws FactoryException {
+ testSetAllPoints(new LinearTransformBuilder());
+ testSetEachPoint(new LinearTransformBuilder());
+ }
+
+ /**
+ * Same test than {@link #testExplicitSource2D()}, but using the
+ * {@link LinearTransformBuilder#LinearTransformBuilder(int...)} constructor.
+ *
+ * @throws FactoryException if the transform can not be created.
+ *
+ * @since 0.8
+ */
+ @Test
+ @DependsOnMethod("testExplicitSource2D")
+ public void testImplicitSource2D() throws FactoryException {
+ testSetAllPoints(new LinearTransformBuilder(2, 3));
+ testSetEachPoint(new LinearTransformBuilder(2, 3));
+ }
+
+ /**
+ * Execution of {@link #testExplicitSource2D()} and {@link #testImplicitSource2D()}
+ * where all control points are specified by a map.
+ */
+ private void testSetAllPoints(final LinearTransformBuilder builder) throws FactoryException {
+ final Map<DirectPosition2D,DirectPosition2D> pos = new HashMap<>(8);
+ assertNull(pos.put(new DirectPosition2D(0, 0), new DirectPosition2D(3, 9)));
+ assertNull(pos.put(new DirectPosition2D(0, 1), new DirectPosition2D(4, 7)));
+ assertNull(pos.put(new DirectPosition2D(0, 2), new DirectPosition2D(6, 6)));
+ assertNull(pos.put(new DirectPosition2D(1, 0), new DirectPosition2D(4, 8)));
+ assertNull(pos.put(new DirectPosition2D(1, 1), new DirectPosition2D(5, 4)));
+ assertNull(pos.put(new DirectPosition2D(1, 2), new DirectPosition2D(8, 2)));
+ builder.setControlPoints(pos);
+ verify(builder);
+ }
+
+ /**
+ * Execution of {@link #testExplicitSource2D()} and {@link #testImplicitSource2D()}
+ * where all control points are specified one-by-one.
+ */
+ private void testSetEachPoint(final LinearTransformBuilder builder) throws FactoryException {
+ builder.setControlPoint(new int[] {0, 0}, new double[] {3, 9});
+ builder.setControlPoint(new int[] {0, 1}, new double[] {4, 7});
+ builder.setControlPoint(new int[] {0, 2}, new double[] {6, 6});
+ builder.setControlPoint(new int[] {1, 0}, new double[] {4, 8});
+ builder.setControlPoint(new int[] {1, 1}, new double[] {5, 4});
+ builder.setControlPoint(new int[] {1, 2}, new double[] {8, 2});
+ verify(builder);
+ }
+
+ /**
+ * Verifies the transform created by {@link #testExplicitSource2D()} and {@link #testImplicitSource2D()}.
+ */
+ private void verify(final LinearTransformBuilder builder) throws FactoryException {
+ final Matrix m = builder.create(null).getMatrix();
+
+ assertArrayEquals(new double[] {3, 9}, builder.getControlPoint(new int[] {0, 0}), STRICT);
+ assertArrayEquals(new double[] {4, 7}, builder.getControlPoint(new int[] {0, 1}), STRICT);
+ assertArrayEquals(new double[] {6, 6}, builder.getControlPoint(new int[] {0, 2}), STRICT);
+ assertArrayEquals(new double[] {4, 8}, builder.getControlPoint(new int[] {1, 0}), STRICT);
+ assertArrayEquals(new double[] {5, 4}, builder.getControlPoint(new int[] {1, 1}), STRICT);
+ assertArrayEquals(new double[] {8, 2}, builder.getControlPoint(new int[] {1, 2}), STRICT);
+ /*
+ * Expect STRICT results because Apache SIS uses double-double arithmetic.
+ */
+ assertEquals("m\u2080\u2080", 16 / 12d, m.getElement(0, 0), STRICT); // First row (x)
+ assertEquals("m\u2080\u2081", 21 / 12d, m.getElement(0, 1), STRICT);
+ assertEquals("m\u2080\u2082", 31 / 12d, m.getElement(0, 2), STRICT);
+ assertEquals("m\u2081\u2080", -32 / 12d, m.getElement(1, 0), STRICT); // Second row (y)
+ assertEquals("m\u2081\u2081", -27 / 12d, m.getElement(1, 1), STRICT);
+ assertEquals("m\u2081\u2082", 115 / 12d, m.getElement(1, 2), STRICT);
+
+ assertArrayEquals("correlation", new double[] {0.9656, 0.9536}, builder.correlation(), 0.0001);
+ }
+
+ /**
* Tests with a random number of points with an exact solution expected.
+ *
+ * @throws FactoryException if the transform can not be created.
*/
@Test
@DependsOnMethod("testMinimalist1D")
- public void testExact1D() {
+ public void testExact1D() throws FactoryException {
final Random rd = TestUtilities.createRandomNumberGenerator(-6080923837183751016L);
for (int i=0; i<10; i++) {
test1D(rd, rd.nextInt(900) + 100, false, 1E-14, 1E-12);
@@ -106,10 +207,12 @@ public final strictfp class LinearTransf
* <p><b>Note:</b> this test can pass with a random seed most of the time. But we fix the seed anyway
* because there is always a small probability that truly random points are all colinear, in which case
* the test would fail. Even if the probability is low, we do not take the risk of random build failures.</p>
+ *
+ * @throws FactoryException if the transform can not be created.
*/
@Test
@DependsOnMethod("testMinimalist2D")
- public void testExact2D() {
+ public void testExact2D() throws FactoryException {
final Random rd = TestUtilities.createRandomNumberGenerator(41632405806929L);
for (int i=0; i<10; i++) {
test2D(rd, rd.nextInt(900) + 100, false, 1E-14, 1E-12);
@@ -118,10 +221,12 @@ public final strictfp class LinearTransf
/**
* Tests with a random number of points and a random errors in target points.
+ *
+ * @throws FactoryException if the transform can not be created.
*/
@Test
@DependsOnMethod("testExact1D")
- public void testNonExact1D() {
+ public void testNonExact1D() throws FactoryException {
final Random rd = TestUtilities.createRandomNumberGenerator(8819436190826166876L);
for (int i=0; i<4; i++) {
test1D(rd, rd.nextInt(900) + 100, true, 0.02, 0.5);
@@ -136,10 +241,12 @@ public final strictfp class LinearTransf
* of errors are in the same directions (thus introducing a larger bias than expected), in which case
* the test would fail. Even if the probability is low, we do not take the risk of such random build
* failures.</p>
+ *
+ * @throws FactoryException if the transform can not be created.
*/
@Test
@DependsOnMethod("testExact2D")
- public void testNonExact2D() {
+ public void testNonExact2D() throws FactoryException {
final Random rd = TestUtilities.createRandomNumberGenerator(270575025643864L);
for (int i=0; i<4; i++) {
test2D(rd, rd.nextInt(900) + 100, true, 0.02, 0.5);
@@ -155,28 +262,25 @@ public final strictfp class LinearTransf
* @param scaleTolerance tolerance threshold for floating point comparisons.
*/
private static void test1D(final Random rd, final int numPts, final boolean addErrors,
- final double scaleTolerance, final double translationTolerance)
+ final double scaleTolerance, final double translationTolerance) throws FactoryException
{
final double scale = rd.nextDouble() * 30 - 12;
final double offset = rd.nextDouble() * 10 - 4;
- final DirectPosition1D[] sources = new DirectPosition1D[numPts];
- final DirectPosition1D[] targets = new DirectPosition1D[numPts];
+ final Map<DirectPosition1D,DirectPosition1D> pos = new HashMap<>(numPts);
for (int i=0; i<numPts; i++) {
final DirectPosition1D src = new DirectPosition1D(rd.nextDouble() * 100 - 50);
final DirectPosition1D tgt = new DirectPosition1D(src.ordinate * scale + offset);
if (addErrors) {
tgt.ordinate += rd.nextDouble() * 10 - 5;
}
- sources[i] = src;
- targets[i] = tgt;
+ assertNull(pos.put(src, tgt));
}
/*
* Create the fitted transform to test.
*/
final LinearTransformBuilder builder = new LinearTransformBuilder();
- builder.setSourcePoints(sources);
- builder.setTargetPoints(targets);
- final Matrix m = builder.create().getMatrix();
+ builder.setControlPoints(pos);
+ final Matrix m = builder.create(null).getMatrix();
assertEquals("m\u2080\u2080", scale, m.getElement(0, 0), scaleTolerance);
assertEquals("m\u2080\u2081", offset, m.getElement(0, 1), translationTolerance);
assertEquals("correlation", 1, StrictMath.abs(builder.correlation()[0]), scaleTolerance);
@@ -191,7 +295,7 @@ public final strictfp class LinearTransf
* @param scaleTolerance tolerance threshold for floating point comparisons.
*/
private static void test2D(final Random rd, final int numPts, final boolean addErrors,
- final double scaleTolerance, final double translationTolerance)
+ final double scaleTolerance, final double translationTolerance) throws FactoryException
{
/*
* Create an AffineTransform to use as the reference implementation.
@@ -200,8 +304,7 @@ public final strictfp class LinearTransf
rd.nextDouble() * (2 * StrictMath.PI), // Rotation angle
rd.nextDouble() * 30 - 12, // Center X
rd.nextDouble() * 10 - 8); // Center Y
- final DirectPosition2D[] sources = new DirectPosition2D[numPts];
- final DirectPosition2D[] targets = new DirectPosition2D[numPts];
+ final Map<DirectPosition2D,DirectPosition2D> pos = new HashMap<>(numPts);
for (int i=0; i<numPts; i++) {
final DirectPosition2D src = new DirectPosition2D(rd.nextDouble() * 100 - 50, rd.nextDouble() * 200 - 75);
final DirectPosition2D tgt = new DirectPosition2D();
@@ -210,16 +313,14 @@ public final strictfp class LinearTransf
tgt.x += rd.nextDouble() * 10 - 5;
tgt.y += rd.nextDouble() * 10 - 5;
}
- sources[i] = src;
- targets[i] = tgt;
+ assertNull(pos.put(src, tgt));
}
/*
* Create the fitted transform to test.
*/
final LinearTransformBuilder builder = new LinearTransformBuilder();
- builder.setSourcePoints(sources);
- builder.setTargetPoints(targets);
- final Matrix m = builder.create().getMatrix();
+ builder.setControlPoints(pos);
+ final Matrix m = builder.create(null).getMatrix();
/*
* Compare the coefficients with the reference implementation.
*/
Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java?rev=1788982&r1=1788981&r2=1788982&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java [UTF-8] Mon Mar 27 16:34:20 2017
@@ -28,7 +28,7 @@ import static org.junit.Assert.*;
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.4
- * @version 0.6
+ * @version 0.8
* @module
*/
public final strictfp class GeneralMatrixTest extends MatrixTestCase {
@@ -117,4 +117,15 @@ public final strictfp class GeneralMatri
testConvertAfter(new GeneralMatrix(3, 3, true, 1)); // Double precision
testConvertAfter(new GeneralMatrix(3, 3, true, 2)); // Double-double precision
}
+
+ /**
+ * Tests {@link MatrixSIS#multiply(double[])} using {@link AffineTranform} as a reference implementation.
+ *
+ * @since 0.8
+ */
+ @Test
+ public void testMultiplyVector() {
+ testMultiplyVector(new GeneralMatrix(3, 3, true, 1)); // Double precision
+ testMultiplyVector(new GeneralMatrix(3, 3, true, 2)); // Double-double precision
+ }
}
Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java?rev=1788982&r1=1788981&r2=1788982&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java [UTF-8] Mon Mar 27 16:34:20 2017
@@ -29,7 +29,7 @@ import static org.apache.sis.referencing
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.4
- * @version 0.6
+ * @version 0.8
* @module
*/
@DependsOn(SolverTest.class)
@@ -122,4 +122,14 @@ public final strictfp class Matrix3Test
public void testConvertAfter() {
testConvertAfter(new Matrix3());
}
+
+ /**
+ * Tests {@link MatrixSIS#multiply(double[])} using {@link AffineTranform} as a reference implementation.
+ *
+ * @since 0.8
+ */
+ @Test
+ public void testMultiplyVector() {
+ testMultiplyVector(new Matrix3());
+ }
}
Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java?rev=1788982&r1=1788981&r2=1788982&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java [UTF-8] Mon Mar 27 16:34:20 2017
@@ -46,7 +46,7 @@ import static org.apache.sis.test.Assert
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.4
- * @version 0.6
+ * @version 0.8
* @module
*/
public abstract strictfp class MatrixTestCase extends TestCase {
@@ -269,7 +269,7 @@ public abstract strictfp class MatrixTes
* End of initialization - now perform the actual test.
*/
assertEqualsJAMA(reference, matrix, STRICT);
- for (int k=0; k<50; k++) {
+ for (int k=0; k<NUMBER_OF_REPETITIONS; k++) {
final int j = random.nextInt(numRow);
final int i = random.nextInt(numCol);
final double e = random.nextDouble() * 100;
@@ -410,7 +410,7 @@ public abstract strictfp class MatrixTes
matrix.setElement(0, 1, at.getShearX());
matrix.setElement(1, 0, at.getShearY());
}
- for (int i=0; i<100; i++) {
+ for (int i=0; i<NUMBER_OF_REPETITIONS; i++) {
/*
* 1) For the first 30 iterations, test the result of applying only a scale.
* 2) For the next 30 iterations, test the result of applying only a translation.
@@ -476,7 +476,7 @@ public abstract strictfp class MatrixTes
final AffineTransform at = AffineTransform.getShearInstance(nextNonZeroRandom(), nextNonZeroRandom());
matrix.setElement(0, 1, at.getShearX());
matrix.setElement(1, 0, at.getShearY());
- for (int i=0; i<30; i++) {
+ for (int i=0; i<NUMBER_OF_REPETITIONS; i++) {
final Number scale = nextNonZeroRandom();
final Number offset = nextNonZeroRandom();
final int tgtDim = (i & 1);
@@ -496,6 +496,41 @@ public abstract strictfp class MatrixTes
}
}
+ /**
+ * Tests {@link MatrixSIS#multiply(double[])} using {@link AffineTranform} as a reference implementation.
+ * This test can be run only with matrices of size 3�3. Consequently it is sub-classes responsibility to
+ * add a {@code testMultiplyVector()} method which invoke this method.
+ *
+ * @param matrix the matrix of size 3�3 to test.
+ *
+ * @since 0.8
+ */
+ final void testMultiplyVector(final MatrixSIS matrix) {
+ initialize(8433903323905121506L);
+ final AffineTransform at = new AffineTransform();
+ final double vector[] = new double[3];
+ for (int n=0; n<NUMBER_OF_REPETITIONS; n++) {
+ if ((n % 10) == 0) {
+ at.setToRotation(random.nextDouble() * StrictMath.PI);
+ at.scale(nextNonZeroRandom(), nextNonZeroRandom());
+ at.translate(random.nextDouble() * 100 - 50,
+ random.nextDouble() * 100 - 50);
+ matrix.setElements(new double[] {
+ at.getScaleX(), at.getShearX(), at.getTranslateX(),
+ at.getShearY(), at.getScaleY(), at.getTranslateY(),
+ 0, 0, 1
+ });
+ }
+ vector[0] = random.nextDouble() * 50 - 25;
+ vector[1] = random.nextDouble() * 50 - 25;
+ vector[2] = 1;
+ final double[] result = matrix.multiply(vector); // The result to verify.
+ at.transform(vector, 0, vector, 0, 1); // The expected result.
+ assertEquals("x", vector[0], result[0], TOLERANCE);
+ assertEquals("y", vector[1], result[1], TOLERANCE);
+ }
+ }
+
/**
* Tests {@link MatrixSIS#multiply(Matrix)}.
*/
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=1788982&r1=1788981&r2=1788982&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] Mon Mar 27 16:34:20 2017
@@ -225,6 +225,7 @@ import org.junit.BeforeClass;
org.apache.sis.referencing.operation.CoordinateOperationFinderTest.class,
org.apache.sis.referencing.operation.DefaultCoordinateOperationFactoryTest.class,
org.apache.sis.referencing.operation.builder.LinearTransformBuilderTest.class,
+ org.apache.sis.referencing.operation.builder.LocalizationGridBuilderTest.class,
// Geometry
org.apache.sis.geometry.AbstractDirectPositionTest.class,
Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/ArrayVector.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/ArrayVector.java?rev=1788982&r1=1788981&r2=1788982&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/ArrayVector.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/ArrayVector.java [UTF-8] Mon Mar 27 16:34:20 2017
@@ -213,7 +213,7 @@ abstract class ArrayVector<E extends Num
/**
* A vector backed by an array of type {@code double[]}.
*/
- private static final class Doubles extends ArrayVector<Double> {
+ static final class Doubles extends ArrayVector<Double> {
/** For cross-version compatibility. */
private static final long serialVersionUID = -2900375382498345812L;
Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/CompoundDirectPositions.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/CompoundDirectPositions.java?rev=1788982&r1=1788981&r2=1788982&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/CompoundDirectPositions.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/CompoundDirectPositions.java [UTF-8] Mon Mar 27 16:34:20 2017
@@ -35,14 +35,14 @@ import org.apache.sis.util.resources.Err
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.5
- * @version 0.5
+ * @version 0.8
* @module
*/
final class CompoundDirectPositions implements DirectPosition, Iterable<DirectPosition>, Iterator<DirectPosition> {
/**
* The arrays of ordinate values, for example (x[], y[], z[]).
*/
- private final double[][] ordinates;
+ private final Vector[] ordinates;
/**
* Length of all ordinate values minus one.
@@ -57,15 +57,16 @@ final class CompoundDirectPositions impl
/**
* Wraps the given array of ordinate values.
*/
- CompoundDirectPositions(final double[]... ordinates) {
+ CompoundDirectPositions(final Vector... ordinates) {
this.ordinates = ordinates;
- final int length = ordinates[0].length;
+ final int length = ordinates[0].size();
for (int i=1; i<ordinates.length; i++) {
- if (ordinates[i].length != length) {
+ if (ordinates[i].size() != length) {
throw new IllegalArgumentException(Errors.format(Errors.Keys.MismatchedArrayLengths));
}
}
- last = length - 1;
+ last = length - 1;
+ index = length;
}
/**
@@ -75,6 +76,9 @@ final class CompoundDirectPositions impl
*/
@Override
public Iterator<DirectPosition> iterator() {
+ if (hasNext()) {
+ throw new UnsupportedOperationException(Errors.format(Errors.Keys.CanIterateOnlyOnce));
+ }
index = -1;
return this;
}
@@ -131,7 +135,7 @@ final class CompoundDirectPositions impl
*/
@Override
public double getOrdinate(final int dimension) {
- return ordinates[dimension][index];
+ return ordinates[dimension].doubleValue(index);
}
/**
Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/Line.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/Line.java?rev=1788982&r1=1788981&r2=1788982&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/Line.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/Line.java [UTF-8] Mon Mar 27 16:34:20 2017
@@ -22,6 +22,7 @@ import org.opengis.geometry.MismatchedDi
import org.apache.sis.internal.util.DoubleDouble;
import org.apache.sis.internal.util.Numerics;
import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.ArgumentChecks;
import static java.lang.Double.*;
@@ -42,7 +43,7 @@ import static java.lang.Double.*;
*
* @author Martin Desruisseaux (MPO, IRD)
* @since 0.5
- * @version 0.5
+ * @version 0.8
* @module
*
* @see Plane
@@ -194,6 +195,21 @@ public class Line implements Cloneable,
}
/**
+ * Sets this line from values of arbitrary {@code Number} type. This method is invoked by algorithms that
+ * may produce other kind of numbers (for example with different precision) than the usual {@code double}
+ * primitive type. The default implementation delegates to {@link #setEquation(double, double)}, but
+ * subclasses can override this method if they want to process other kind of numbers in a special way.
+ *
+ * @param slope the slope.
+ * @param y0 the <var>y</var> value at <var>x</var> = 0.
+ *
+ * @since 0.8
+ */
+ public void setEquation(final Number slope, final Number y0) {
+ setEquation(slope.doubleValue(), y0.doubleValue());
+ }
+
+ /**
* Sets a line through the specified points.
* The line will continue toward infinity after the points.
*
@@ -219,8 +235,10 @@ public class Line implements Cloneable,
/**
* Given a set of data points <var>x</var>[0 \u2026 <var>n</var>-1], <var>y</var>[0 \u2026 <var>n</var>-1],
* fits them to a straight line <var>y</var> = <var>slope</var>\u22c5<var>x</var> + <var>y\u2080</var> in a
- * least-squares senses. This method assume that the <var>x</var> values are precise and all uncertainty
- * is in <var>y</var>.
+ * least-squares senses.
+ * This method assumes that the <var>x</var> values are precise and all uncertainty is in <var>y</var>.
+ *
+ * <p>The default implementation delegates to {@link #fit(Vector, Vector)}.</p>
*
* @param x vector of <var>x</var> values (independent variable).
* @param y vector of <var>y</var> values (dependent variable).
@@ -229,30 +247,46 @@ public class Line implements Cloneable,
* @throws IllegalArgumentException if <var>x</var> and <var>y</var> do not have the same length.
*/
public double fit(final double[] x, final double[] y) {
- // Do not invoke an overrideable method with our tricky iterable.
- return doFit(new CompoundDirectPositions(x, y));
+ ArgumentChecks.ensureNonNull("x", x);
+ ArgumentChecks.ensureNonNull("y", y);
+ return fit(new ArrayVector.Doubles(x), new ArrayVector.Doubles(y));
}
/**
- * Given a sequence of points, fits them to a straight line <var>y</var> = <var>slope</var>\u22c5<var>x</var> +
- * <var>y\u2080</var> in a least-squares senses. This method assume that the <var>x</var> values are precise and
- * all uncertainty is in <var>y</var>.
+ * Given a set of data points <var>x</var>[0 \u2026 <var>n</var>-1], <var>y</var>[0 \u2026 <var>n</var>-1],
+ * fits them to a straight line <var>y</var> = <var>slope</var>\u22c5<var>x</var> + <var>y\u2080</var> in a
+ * least-squares senses.
+ * This method assumes that the <var>x</var> values are precise and all uncertainty is in <var>y</var>.
*
- * <p>Points shall be two dimensional with ordinate values in the (<var>x</var>,<var>y</var>) order.
- * {@link Double#NaN} ordinate values are ignored.</p>
+ * <p>The default implementation delegates to {@link #fit(Iterable)}.</p>
*
- * @param points the two-dimensional points.
+ * @param x vector of <var>x</var> values (independent variable).
+ * @param y vector of <var>y</var> values (dependent variable).
* @return estimation of the correlation coefficient. The closer this coefficient is to +1 or -1, the better the fit.
- * @throws MismatchedDimensionException if a point is not two-dimensional.
+ *
+ * @throws IllegalArgumentException if <var>x</var> and <var>y</var> do not have the same length.
+ *
+ * @since 0.8
*/
- public double fit(final Iterable<? extends DirectPosition> points) {
- return doFit(points);
+ public double fit(final Vector x, final Vector y) {
+ ArgumentChecks.ensureNonNull("x", x);
+ ArgumentChecks.ensureNonNull("y", y);
+ return fit(new CompoundDirectPositions(x, y));
}
/**
- * Implementation of public {@code fit(\u2026)} methods.
+ * Given a sequence of points, fits them to a straight line
+ * <var>y</var> = <var>slope</var>\u22c5<var>x</var> + <var>y\u2080</var> in a least-squares senses.
+ * Points shall be two dimensional with ordinate values in the (<var>x</var>,<var>y</var>) order.
+ * This method assumes that the <var>x</var> values are precise and all uncertainty is in <var>y</var>.
+ * {@link Double#NaN} ordinate values are ignored.
+ *
+ * @param points the two-dimensional points.
+ * @return estimation of the correlation coefficient. The closer this coefficient is to +1 or -1, the better the fit.
+ * @throws MismatchedDimensionException if a point is not two-dimensional.
*/
- private double doFit(final Iterable<? extends DirectPosition> points) {
+ public double fit(final Iterable<? extends DirectPosition> points) {
+ ArgumentChecks.ensureNonNull("points", points);
int i = 0, n = 0;
final DoubleDouble mean_x = new DoubleDouble();
final DoubleDouble mean_y = new DoubleDouble();
@@ -325,7 +359,7 @@ public class Line implements Cloneable,
b.multiply(a);
b.negate();
b.add(mean_y); // y\u2080 = mean_y - mean_x * slope
- setEquation(a.value, b.value);
+ setEquation(a, b);
/*
* Compute the correlation coefficient:
* mean_xy / sqrt(mean_x2 * (mean_y2 - mean_y * mean_y))
Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/Plane.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/Plane.java?rev=1788982&r1=1788981&r2=1788982&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/Plane.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/Plane.java [UTF-8] Mon Mar 27 16:34:20 2017
@@ -16,17 +16,22 @@
*/
package org.apache.sis.math;
+import java.util.Iterator;
import java.io.Serializable;
import org.opengis.geometry.DirectPosition;
import org.opengis.geometry.MismatchedDimensionException;
import org.apache.sis.internal.util.DoubleDouble;
import org.apache.sis.internal.util.Numerics;
import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.ArgumentChecks;
import static java.lang.Math.abs;
import static java.lang.Math.sqrt;
import static java.lang.Math.ulp;
+// Branch-dependent imports
+import org.apache.sis.internal.jdk8.JDK8;
+
/**
* Equation of a plane in a three-dimensional space (<var>x</var>,<var>y</var>,<var>z</var>).
@@ -44,7 +49,7 @@ import static java.lang.Math.ulp;
* @author Martin Desruisseaux (MPO, IRD)
* @author Howard Freeland (MPO, for algorithmic inspiration)
* @since 0.5
- * @version 0.5
+ * @version 0.8
* @module
*
* @see Line
@@ -211,13 +216,28 @@ public class Plane implements Cloneable,
}
/**
+ * Sets this plane from values of arbitrary {@code Number} type. This method is invoked by algorithms that
+ * may produce other kind of numbers (for example with different precision) than the usual {@code double}
+ * primitive type. The default implementation delegates to {@link #setEquation(double, double, double)},
+ * but subclasses can override this method if they want to process other kind of numbers in a special way.
+ *
+ * @param sx the slope along the <var>x</var> values.
+ * @param sy the slope along the <var>y</var> values.
+ * @param z0 the <var>z</var> value at (<var>x</var>,<var>y</var>) = (0,0).
+ *
+ * @since 0.8
+ */
+ public void setEquation(final Number sx, final Number sy, final Number z0) {
+ setEquation(sx.doubleValue(), sy.doubleValue(), z0.doubleValue());
+ }
+
+ /**
* Computes the plane's coefficients from the given ordinate values.
- * This method uses a linear regression in the least-square sense,
- * with the assumption that the (<var>x</var>,<var>y</var>) values are precise
- * and all uncertainty is in <var>z</var>.
+ * This method uses a linear regression in the least-square sense, with the assumption that
+ * the (<var>x</var>,<var>y</var>) values are precise and all uncertainty is in <var>z</var>.
+ * {@link Double#NaN} values are ignored. The result is undetermined if all points are colinear.
*
- * <p>{@link Double#NaN} values are ignored.
- * The result is undetermined if all points are colinear.</p>
+ * <p>The default implementation delegates to {@link #fit(Vector, Vector, Vector)}.</p>
*
* @param x vector of <var>x</var> coordinates.
* @param y vector of <var>y</var> coordinates.
@@ -226,154 +246,313 @@ public class Plane implements Cloneable,
* @throws IllegalArgumentException if <var>x</var>, <var>y</var> and <var>z</var> do not have the same length.
*/
public double fit(final double[] x, final double[] y, final double[] z) {
- // Do not invoke an overrideable method with our tricky iterable.
- return fit(new CompoundDirectPositions(x, y, z), true, true, true);
+ ArgumentChecks.ensureNonNull("x", x);
+ ArgumentChecks.ensureNonNull("y", y);
+ ArgumentChecks.ensureNonNull("z", z);
+ return fit(new ArrayVector.Doubles(x), new ArrayVector.Doubles(y), new ArrayVector.Doubles(z));
+ }
+
+ /**
+ * Computes the plane's coefficients from the given ordinate values.
+ * This method uses a linear regression in the least-square sense, with the assumption that
+ * the (<var>x</var>,<var>y</var>) values are precise and all uncertainty is in <var>z</var>.
+ * {@link Double#NaN} values are ignored. The result is undetermined if all points are colinear.
+ *
+ * <p>The default implementation delegates to {@link #fit(Iterable)}.</p>
+ *
+ * @param x vector of <var>x</var> coordinates.
+ * @param y vector of <var>y</var> coordinates.
+ * @param z vector of <var>z</var> values.
+ * @return an estimation of the Pearson correlation coefficient.
+ * @throws IllegalArgumentException if <var>x</var>, <var>y</var> and <var>z</var> do not have the same length.
+ *
+ * @since 0.8
+ */
+ public double fit(final Vector x, final Vector y, final Vector z) {
+ ArgumentChecks.ensureNonNull("x", x);
+ ArgumentChecks.ensureNonNull("y", y);
+ ArgumentChecks.ensureNonNull("z", z);
+ return fit(new CompoundDirectPositions(x, y, z));
+ }
+
+ /**
+ * Computes the plane's coefficients from values distributed on a regular grid. Invoking this method
+ * is equivalent (except for NaN handling) to invoking {@link #fit(Vector, Vector, Vector)} where all
+ * vectors have a length of {@code nx} � {@code ny} and the <var>x</var> and <var>y</var> vectors have
+ * the following content:
+ *
+ * <blockquote>
+ * <table class="compact" summary="x and y vector content">
+ * <tr>
+ * <th><var>x</var> vector</th>
+ * <th><var>y</var> vector</th>
+ * </tr><tr>
+ * <td>
+ * 0 1 2 3 4 5 \u2026 n<sub>x</sub>-1<br>
+ * 0 1 2 3 4 5 \u2026 n<sub>x</sub>-1<br>
+ * 0 1 2 3 4 5 \u2026 n<sub>x</sub>-1<br>
+ * \u2026<br>
+ * 0 1 2 3 4 5 \u2026 n<sub>x</sub>-1<br>
+ * </td><td>
+ * 0 0 0 0 0 0 \u2026 0<br>
+ * 1 1 1 1 1 1 \u2026 1<br>
+ * 2 2 2 2 2 2 \u2026 2<br>
+ * \u2026<br>
+ * n<sub>y</sub>-1 n<sub>y</sub>-1 n<sub>y</sub>-1 \u2026 n<sub>y</sub>-1<br>
+ * </td>
+ * </tr>
+ * </table>
+ * </blockquote>
+ *
+ * This method uses a linear regression in the least-square sense, with the assumption that
+ * the (<var>x</var>,<var>y</var>) values are precise and all uncertainty is in <var>z</var>.
+ * The result is undetermined if all points are colinear.
+ *
+ * @param nx number of columns.
+ * @param ny number of rows.
+ * @param z values of a matrix of {@code nx}�columns by {@code ny} rows organized in a row-major fashion.
+ * @return an estimation of the Pearson correlation coefficient.
+ * @throws IllegalArgumentException if <var>z</var> does not have the expected length or if a <var>z</var>
+ * value is {@link Double#NaN}.
+ *
+ * @since 0.8
+ */
+ public double fit(final int nx, final int ny, final Vector z) {
+ ArgumentChecks.ensureStrictlyPositive("nx", nx);
+ ArgumentChecks.ensureStrictlyPositive("ny", ny);
+ ArgumentChecks.ensureNonNull("z", z);
+ final int length = JDK8.multiplyExact(nx, ny);
+ if (z.size() != length) {
+ throw new IllegalArgumentException(Errors.format(Errors.Keys.UnexpectedArrayLength_2, length, z.size()));
+ }
+ final Fit r = new Fit(nx, ny, z);
+ r.resolve();
+ final double p = r.correlation(nx, length, z, null);
+ setEquation(r.sx, r.sy, r.z0);
+ return p;
}
/**
* Computes the plane's coefficients from the given sequence of points.
- * This method uses a linear regression in the least-square sense,
- * with the assumption that the (<var>x</var>,<var>y</var>) values are precise
- * and all uncertainty is in <var>z</var>.
- *
- * <p>Points shall be three dimensional with ordinate values in the (<var>x</var>,<var>y</var>,<var>z</var>) order.
- * {@link Double#NaN} ordinate values are ignored.
- * The result is undetermined if all points are colinear.</p>
+ * This method uses a linear regression in the least-square sense, with the assumption that
+ * the (<var>x</var>,<var>y</var>) values are precise and all uncertainty is in <var>z</var>.
+ * Points shall be three dimensional with ordinate values in the (<var>x</var>,<var>y</var>,<var>z</var>) order.
+ * {@link Double#NaN} values are ignored. The result is undetermined if all points are colinear.
*
* @param points the three-dimensional points.
* @return an estimation of the Pearson correlation coefficient.
* @throws MismatchedDimensionException if a point is not three-dimensional.
*/
public double fit(final Iterable<? extends DirectPosition> points) {
- return fit(points, true, true, true);
+ ArgumentChecks.ensureNonNull("points", points);
+ final Fit r = new Fit(points);
+ r.resolve();
+ final double p = r.correlation(0, 0, null, points.iterator());
+ /*
+ * Store the result only when we are done, so we have a "all or nothing" behavior.
+ * We invoke the setEquation(sx, sy, z\u2080) method in case the user override it.
+ */
+ setEquation(r.sx, r.sy, r.z0);
+ return p;
}
/**
- * Implementation of public {@code fit(\u2026)} methods.
- * This method needs to iterate over the points two times:
+ * Computes the plane coefficients. This class needs to iterate over the points two times:
* one for computing the coefficients, and one for the computing the Pearson coefficient.
* The second pass can also opportunistically checks if some small coefficients can be replaced by zero.
*/
- private double fit(final Iterable<? extends DirectPosition> points,
- boolean detectZeroSx, boolean detectZeroSy, boolean detectZeroZ0)
- {
- int i = 0, n = 0;
- final DoubleDouble sum_x = new DoubleDouble();
- final DoubleDouble sum_y = new DoubleDouble();
- final DoubleDouble sum_z = new DoubleDouble();
- final DoubleDouble sum_xx = new DoubleDouble();
- final DoubleDouble sum_yy = new DoubleDouble();
- final DoubleDouble sum_xy = new DoubleDouble();
- final DoubleDouble sum_zx = new DoubleDouble();
- final DoubleDouble sum_zy = new DoubleDouble();
- final DoubleDouble xx = new DoubleDouble();
- final DoubleDouble yy = new DoubleDouble();
- final DoubleDouble xy = new DoubleDouble();
- final DoubleDouble zx = new DoubleDouble();
- final DoubleDouble zy = new DoubleDouble();
- for (final DirectPosition p : points) {
- final int dimension = p.getDimension();
- if (dimension != DIMENSION) {
- throw new MismatchedDimensionException(Errors.format(
- Errors.Keys.MismatchedDimension_3, "points[" + i + ']', DIMENSION, dimension));
+ private static final class Fit {
+ private final DoubleDouble sum_x = new DoubleDouble();
+ private final DoubleDouble sum_y = new DoubleDouble();
+ private final DoubleDouble sum_z = new DoubleDouble();
+ private final DoubleDouble sum_xx = new DoubleDouble();
+ private final DoubleDouble sum_yy = new DoubleDouble();
+ private final DoubleDouble sum_xy = new DoubleDouble();
+ private final DoubleDouble sum_zx = new DoubleDouble();
+ private final DoubleDouble sum_zy = new DoubleDouble();
+ private final DoubleDouble xx = new DoubleDouble();
+ private final DoubleDouble yy = new DoubleDouble();
+ private final DoubleDouble xy = new DoubleDouble();
+ private final DoubleDouble zx = new DoubleDouble();
+ private final DoubleDouble zy = new DoubleDouble();
+ private final int n;
+
+ /** Solution of the plane equation. */ DoubleDouble sx, sy, z0;
+
+ /**
+ * Computes the values of all {@code sum_*} fields from randomly distributed points.
+ * Value of all other fields are undetermined..
+ */
+ Fit(final Iterable<? extends DirectPosition> points) {
+ int i = 0, n = 0;
+ for (final DirectPosition p : points) {
+ final int dimension = p.getDimension();
+ if (dimension != DIMENSION) {
+ throw new MismatchedDimensionException(Errors.format(
+ Errors.Keys.MismatchedDimension_3, "points[" + i + ']', DIMENSION, dimension));
+ }
+ i++;
+ final double x = p.getOrdinate(0); if (Double.isNaN(x)) continue;
+ final double y = p.getOrdinate(1); if (Double.isNaN(y)) continue;
+ final double z = p.getOrdinate(2); if (Double.isNaN(z)) continue;
+ xx.setToProduct(x, x);
+ yy.setToProduct(y, y);
+ xy.setToProduct(x, y);
+ zx.setToProduct(z, x);
+ zy.setToProduct(z, y);
+ sum_x .add(x );
+ sum_y .add(y );
+ sum_z .add(z );
+ sum_xx.add(xx);
+ sum_yy.add(yy);
+ sum_xy.add(xy);
+ sum_zx.add(zx);
+ sum_zy.add(zy);
+ n++;
}
- i++;
- final double x = p.getOrdinate(0); if (Double.isNaN(x)) continue;
- final double y = p.getOrdinate(1); if (Double.isNaN(y)) continue;
- final double z = p.getOrdinate(2); if (Double.isNaN(z)) continue;
- xx.setToProduct(x, x);
- yy.setToProduct(y, y);
- xy.setToProduct(x, y);
- zx.setToProduct(z, x);
- zy.setToProduct(z, y);
- sum_x.add(x);
- sum_y.add(y);
- sum_z.add(z);
- sum_xx.add(xx);
- sum_yy.add(yy);
- sum_xy.add(xy);
- sum_zx.add(zx);
- sum_zy.add(zy);
- n++;
+ this.n = n;
}
- /*
- * ( sum_zx - sum_z*sum_x ) = sx*(sum_xx - sum_x*sum_x) + sy*(sum_xy - sum_x*sum_y)
- * ( sum_zy - sum_z*sum_y ) = sx*(sum_xy - sum_x*sum_y) + sy*(sum_yy - sum_y*sum_y)
- */
- zx.setFrom(sum_x); zx.divide(-n, 0); zx.multiply(sum_z); zx.add(sum_zx); // zx = sum_zx - sum_z*sum_x/n
- zy.setFrom(sum_y); zy.divide(-n, 0); zy.multiply(sum_z); zy.add(sum_zy); // zy = sum_zy - sum_z*sum_y/n
- xx.setFrom(sum_x); xx.divide(-n, 0); xx.multiply(sum_x); xx.add(sum_xx); // xx = sum_xx - sum_x*sum_x/n
- xy.setFrom(sum_y); xy.divide(-n, 0); xy.multiply(sum_x); xy.add(sum_xy); // xy = sum_xy - sum_x*sum_y/n
- yy.setFrom(sum_y); yy.divide(-n, 0); yy.multiply(sum_y); yy.add(sum_yy); // yy = sum_yy - sum_y*sum_y/n
- /*
- * den = (xy*xy - xx*yy)
- */
- final DoubleDouble tmp = new DoubleDouble(xx); tmp.multiply(yy);
- final DoubleDouble den = new DoubleDouble(xy); den.multiply(xy);
- den.subtract(tmp);
- /*
- * sx = (zy*xy - zx*yy) / den
- * sy = (zx*xy - zy*xx) / den
- * z\u2080 = (sum_z - (sx*sum_x + sy*sum_y)) / n
- */
- final DoubleDouble sx = new DoubleDouble(zy); sx.multiply(xy); tmp.setFrom(zx); tmp.multiply(yy); sx.subtract(tmp); sx.divide(den);
- final DoubleDouble sy = new DoubleDouble(zx); sy.multiply(xy); tmp.setFrom(zy); tmp.multiply(xx); sy.subtract(tmp); sy.divide(den);
- final DoubleDouble z0 = new DoubleDouble(sy);
- z0.multiply(sum_y);
- tmp.setFrom(sx);
- tmp.multiply(sum_x);
- tmp.add(z0);
- z0.setFrom(sum_z);
- z0.subtract(tmp);
- z0.divide(n, 0);
- /*
- * At this point, the model is computed. Now computes an estimation of the Pearson
- * correlation coefficient. Note that both the z array and the z computed from the
- * model have the same average, called sum_z below (the name is not true anymore).
- *
- * We do not use double-double arithmetic here since the Pearson coefficient is
- * for information purpose (quality estimation).
+
+ /**
+ * Computes the values of all {@code sum_*} fields from the <var>z</var> values on a regular grid.
+ * Value of all other fields are undetermined..
*/
- final double mean_x = sum_x.value / n;
- final double mean_y = sum_y.value / n;
- final double mean_z = sum_z.value / n;
- final double offset = abs((sx.value * mean_x + sy.value * mean_y) + z0.value); // Offsetted z\u2080 - see comment before usage.
- double sum_ds2 = 0, sum_dz2 = 0, sum_dsz = 0;
- for (final DirectPosition p : points) {
- final double x = (p.getOrdinate(0) - mean_x) * sx.value;
- final double y = (p.getOrdinate(1) - mean_y) * sy.value;
- final double z = (p.getOrdinate(2) - mean_z);
- final double s = x + y;
- if (!Double.isNaN(s) && !Double.isNaN(z)) {
- sum_ds2 += s * s;
- sum_dz2 += z * z;
- sum_dsz += s * z;
- }
+ Fit(final int nx, final int ny, final Vector vz) {
/*
- * Algorithm for detecting if a coefficient should be zero:
- * If for every points given by the user, adding (sx\u22c5x) in (sx\u22c5x + sy\u22c5y + z\u2080) does not make any difference
- * because (sx\u22c5x) is smaller than 1 ULP of (sy\u22c5y + z\u2080), then it is not worth adding it and sx can be set
- * to zero. The same rational applies to (sy\u22c5y) and z\u2080.
- *
- * Since we work with differences from the means, the z = sx\u22c5x + sy\u22c5y + z\u2080 equation can be rewritten as:
+ * Computes the sum of x, y and z values. Computes also the sum of x�, y�, x\u22c5y, z\u22c5x and z\u22c5y values.
+ * When possible, we will avoid to compute the sum inside the loop and use the following identities
+ * instead:
*
- * \u0394z = sx\u22c5\u0394x + sy\u22c5\u0394y + (sx\u22c5mx + sy\u22c5my + z\u2080 - mz) where the term between (\u2026) is close to zero.
+ * 1 + 2 + 3 ... + n = n\u22c5(n+1)/2 (arithmetic series)
+ * 1� + 2� + 3� ... + n� = n\u22c5(n+0.5)\u22c5(n+1)/3
*
- * The check for (sx\u22c5\u0394x) and (sy\u22c5\u0394y) below ignore the (\u2026) term since it is close to zero.
- * The check for z\u2080 is derived from an equation without the -mz term.
+ * Note that for exclusive upper bound, we need to replace n by n-1 in above formulas.
*/
- if (detectZeroSx && abs(x) >= ulp(y * ZERO_THRESHOLD)) detectZeroSx = false;
- if (detectZeroSy && abs(y) >= ulp(x * ZERO_THRESHOLD)) detectZeroSy = false;
- if (detectZeroZ0 && offset >= ulp(s * ZERO_THRESHOLD)) detectZeroZ0 = false;
+ int n = 0;
+ for (int y=0; y<ny; y++) {
+ for (int x=0; x<nx; x++) {
+ final double z = vz.doubleValue(n);
+ if (Double.isNaN(z)) {
+ throw new IllegalArgumentException(Errors.format(Errors.Keys.NotANumber_1, "z[" + n + ']'));
+ }
+ zx.setToProduct(z, x);
+ zy.setToProduct(z, y);
+ sum_z .add(z );
+ sum_zx.add(zx);
+ sum_zy.add(zy);
+ n++;
+ }
+ }
+ sum_x .value = n/2d; sum_x .multiply(nx-1, 0); // Division by 2 is exact.
+ sum_y .value = n/2d; sum_y .multiply(ny-1, 0);
+ sum_xx.value = n; sum_xx.multiply(nx-0.5, 0); sum_xx.multiply(nx-1, 0); sum_xx.divide(3, 0);
+ sum_yy.value = n; sum_yy.multiply(ny-0.5, 0); sum_yy.multiply(ny-1, 0); sum_yy.divide(3, 0);
+ sum_xy.value = n/4d; sum_xy.multiply(ny-1, 0); sum_xy.multiply(nx-1, 0);
+ this.n = n;
}
- /*
- * Store the result only when we are done, so we have a "all or nothing" behavior.
- * We invoke the setEquation(sx, sy, z\u2080) method in case the user override it.
+
+ /**
+ * Computes the {@link #sx}, {@link #sy} and {@link #z0} values using the sums computed by the constructor.
*/
- setEquation(detectZeroSx ? 0 : sx.value,
- detectZeroSy ? 0 : sy.value,
- detectZeroZ0 ? 0 : z0.value);
- return Math.min(sum_dsz / sqrt(sum_ds2 * sum_dz2), 1);
+ private void resolve() {
+ /*
+ * ( sum_zx - sum_z\u22c5sum_x ) = sx\u22c5(sum_xx - sum_x\u22c5sum_x) + sy\u22c5(sum_xy - sum_x\u22c5sum_y)
+ * ( sum_zy - sum_z\u22c5sum_y ) = sx\u22c5(sum_xy - sum_x\u22c5sum_y) + sy\u22c5(sum_yy - sum_y\u22c5sum_y)
+ */
+ zx.setFrom(sum_x); zx.divide(-n, 0); zx.multiply(sum_z); zx.add(sum_zx); // zx = sum_zx - sum_z\u22c5sum_x/n
+ zy.setFrom(sum_y); zy.divide(-n, 0); zy.multiply(sum_z); zy.add(sum_zy); // zy = sum_zy - sum_z\u22c5sum_y/n
+ xx.setFrom(sum_x); xx.divide(-n, 0); xx.multiply(sum_x); xx.add(sum_xx); // xx = sum_xx - sum_x\u22c5sum_x/n
+ xy.setFrom(sum_y); xy.divide(-n, 0); xy.multiply(sum_x); xy.add(sum_xy); // xy = sum_xy - sum_x\u22c5sum_y/n
+ yy.setFrom(sum_y); yy.divide(-n, 0); yy.multiply(sum_y); yy.add(sum_yy); // yy = sum_yy - sum_y\u22c5sum_y/n
+ /*
+ * den = (xy\u22c5xy - xx\u22c5yy)
+ */
+ final DoubleDouble tmp = new DoubleDouble(xx); tmp.multiply(yy);
+ final DoubleDouble den = new DoubleDouble(xy); den.multiply(xy);
+ den.subtract(tmp);
+ /*
+ * sx = (zy\u22c5xy - zx\u22c5yy) / den
+ * sy = (zx\u22c5xy - zy\u22c5xx) / den
+ * z\u2080 = (sum_z - (sx\u22c5sum_x + sy\u22c5sum_y)) / n
+ */
+ sx = new DoubleDouble(zy); sx.multiply(xy); tmp.setFrom(zx); tmp.multiply(yy); sx.subtract(tmp); sx.divide(den);
+ sy = new DoubleDouble(zx); sy.multiply(xy); tmp.setFrom(zy); tmp.multiply(xx); sy.subtract(tmp); sy.divide(den);
+ z0 = new DoubleDouble(sy);
+ z0.multiply(sum_y);
+ tmp.setFrom(sx);
+ tmp.multiply(sum_x);
+ tmp.add(z0);
+ z0.setFrom(sum_z);
+ z0.subtract(tmp);
+ z0.divide(n, 0);
+ }
+
+ /**
+ * Computes an estimation of the Pearson correlation coefficient. We do not use double-double arithmetic
+ * here since the Pearson coefficient is for information purpose (quality estimation).
+ *
+ * <p>Only one of ({@code nx}, {@code length}, {@code z}) tuple or {@code points} argument should be non-null.</p>
+ */
+ double correlation(final int nx, final int length, final Vector vz,
+ final Iterator<? extends DirectPosition> points)
+ {
+ boolean detectZeroSx = true;
+ boolean detectZeroSy = true;
+ boolean detectZeroZ0 = true;
+ final double sx = this.sx.value;
+ final double sy = this.sy.value;
+ final double z0 = this.z0.value;
+ final double mean_x = sum_x.value / n;
+ final double mean_y = sum_y.value / n;
+ final double mean_z = sum_z.value / n;
+ final double offset = abs((sx * mean_x + sy * mean_y) + z0); // Offsetted z\u2080 - see comment before usage.
+ int index = 0;
+ double sum_ds2 = 0, sum_dz2 = 0, sum_dsz = 0;
+ for (;;) {
+ double x, y, z;
+ if (vz != null) {
+ if (index >= length) break;
+ x = index % nx;
+ y = index / nx;
+ z = vz.doubleValue(index++);
+ } else {
+ if (!points.hasNext()) break;
+ final DirectPosition p = points.next();
+ x = p.getOrdinate(0);
+ y = p.getOrdinate(1);
+ z = p.getOrdinate(2);
+ }
+ x = (x - mean_x) * sx;
+ y = (y - mean_y) * sy;
+ z = (z - mean_z);
+ final double s = x + y;
+ if (!Double.isNaN(s) && !Double.isNaN(z)) {
+ sum_ds2 += s * s;
+ sum_dz2 += z * z;
+ sum_dsz += s * z;
+ }
+ /*
+ * Algorithm for detecting if a coefficient should be zero:
+ * If for every points given by the user, adding (sx\u22c5x) in (sx\u22c5x + sy\u22c5y + z\u2080) does not make any difference
+ * because (sx\u22c5x) is smaller than 1 ULP of (sy\u22c5y + z\u2080), then it is not worth adding it and sx can be set
+ * to zero. The same rational applies to (sy\u22c5y) and z\u2080.
+ *
+ * Since we work with differences from the means, the z = sx\u22c5x + sy\u22c5y + z\u2080 equation can be rewritten as:
+ *
+ * \u0394z = sx\u22c5\u0394x + sy\u22c5\u0394y + (sx\u22c5mx + sy\u22c5my + z\u2080 - mz) where the term between (\u2026) is close to zero.
+ *
+ * The check for (sx\u22c5\u0394x) and (sy\u22c5\u0394y) below ignore the (\u2026) term since it is close to zero.
+ * The check for z\u2080 is derived from an equation without the -mz term.
+ */
+ if (detectZeroSx && abs(x) >= ulp(y * ZERO_THRESHOLD)) detectZeroSx = false;
+ if (detectZeroSy && abs(y) >= ulp(x * ZERO_THRESHOLD)) detectZeroSy = false;
+ if (detectZeroZ0 && offset >= ulp(s * ZERO_THRESHOLD)) detectZeroZ0 = false;
+ }
+ if (detectZeroSx) this.sx.clear();
+ if (detectZeroSy) this.sy.clear();
+ if (detectZeroZ0) this.z0.clear();
+ return Math.min(sum_dsz / sqrt(sum_ds2 * sum_dz2), 1);
+ }
}
/**
Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/StatisticsFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/StatisticsFormat.java?rev=1788982&r1=1788981&r2=1788982&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/StatisticsFormat.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/StatisticsFormat.java [UTF-8] Mon Mar 27 16:34:20 2017
@@ -54,12 +54,11 @@ import static java.lang.Math.*;
* }
* </div>
*
- * Like most {@link java.text.Format} implementations, this class is not thread-safe.
- * Each thread should use its own {@code StatisticsFormat} instance or apply synchronization.
- *
- * <div class="warning"><b>Limitation:</b>
- * the current implementation can only format statistics \u2014 parsing is not yet implemented.
- * </div>
+ * <p><b>Limitations:</b></p>
+ * <ul>
+ * <li>The current implementation can only format features \u2014 parsing is not yet implemented.</li>
+ * <li>{@code StatisticsFormat}, like most {@code java.text.Format} subclasses, is not thread-safe.</li>
+ * </ul>
*
* @author Martin Desruisseaux (MPO, IRD, Geomatys)
* @since 0.3
Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1788982&r1=1788981&r2=1788982&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] Mon Mar 27 16:34:20 2017
@@ -70,6 +70,11 @@ public final class Errors extends Indexe
public static final short AmbiguousName_3 = 1;
/**
+ * This object can iterate only once.
+ */
+ public static final short CanIterateOnlyOnce = 172;
+
+ /**
* No element can be added to this set because properties \u2018{0}\u2019 and \u2018{1}\u2019 are mutually
* exclusive.
*/
@@ -640,6 +645,11 @@ public final class Errors extends Indexe
public static final short NotAUnicodeIdentifier_1 = 112;
/**
+ * {0} is not an integer value.
+ */
+ public static final short NotAnInteger_1 = 171;
+
+ /**
* Argument \u2018{0}\u2019 shall not be null.
*/
public static final short NullArgument_1 = 113;
Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1788982&r1=1788981&r2=1788982&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] Mon Mar 27 16:34:20 2017
@@ -25,6 +25,7 @@
# can reorder the parameters as they want.
#
AmbiguousName_3 = Name \u201c{2}\u201d is ambiguous because it can be understood as either \u201c{0}\u201d or \u201c{1}\u201d.
+CanIterateOnlyOnce = This object can iterate only once.
CanNotAddToExclusiveSet_2 = No element can be added to this set because properties \u2018{0}\u2019 and \u2018{1}\u2019 are mutually exclusive.
CanNotAssign_2 = Can not assign \u201c{1}\u201d to \u201c{0}\u201d.
CanNotAssignUnitToDimension_2 = Can not assign units \u201c{1}\u201d to dimension \u201c{0}\u201d.
@@ -133,6 +134,7 @@ NonTemporalUnit_1 = \u20
NonSystemUnit_1 = \u201c{0}\u201d is not a fundamental or derived unit.
NonRatioUnit_1 = The scale of measurement for \u201c{0}\u201d unit is not a ratio scale.
NotABackwardReference_1 = No element for the \u201c{0}\u201d identifier, or the identifier is a forward reference.
+NotAnInteger_1 = {0} is not an integer value.
NotAKeyValuePair_1 = \u201c{0}\u201d is not a key-value pair.
NotANumber_1 = Argument \u2018{0}\u2019 shall not be NaN (Not-a-Number).
NotAPrimitiveWrapper_1 = Class \u2018{0}\u2019 is not a primitive type wrapper.
Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties?rev=1788982&r1=1788981&r2=1788982&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties [ISO-8859-1] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties [ISO-8859-1] Mon Mar 27 16:34:20 2017
@@ -22,6 +22,7 @@
# U+00A0 NO-BREAK SPACE before :
#
AmbiguousName_3 = Le nom \u00ab\u202f{2}\u202f\u00bb est ambigu\u00eb car il peut \u00eatre interpr\u00e9t\u00e9 comme \u00ab\u202f{0}\u202f\u00bb ou \u00ab\u202f{1}\u202f\u00bb.
+CanIterateOnlyOnce = Cet objet ne peut it\u00e9rer qu\u2019une seule fois.
CanNotAddToExclusiveSet_2 = Aucun \u00e9l\u00e9ment ne peut \u00eatre ajout\u00e9 \u00e0 cet ensemble car les propri\u00e9t\u00e9s \u2018{0}\u2019 et \u2018{1}\u2019 sont mutuellement exclusives.
CanNotAssign_2 = Ne peut pas assigner \u00ab\u202f{1}\u202f\u00bb \u00e0 \u00ab\u202f{0}\u202f\u00bb.
CanNotAssignUnitToDimension_2 = Ne peut pas assigner les unit\u00e9s \u00ab\u202f{1}\u202f\u00bb \u00e0 la dimension \u00ab\u202f{0}\u202f\u00bb.
@@ -130,6 +131,7 @@ NonTemporalUnit_1 = \u00
NonSystemUnit_1 = \u00ab\u202f{0}\u202f\u00bb n\u2019est pas une unit\u00e9 fondamentale ou d\u00e9riv\u00e9e.
NonRatioUnit_1 = L\u2019\u00e9chelle de mesure de l\u2019unit\u00e9 \u00ab\u202f{0}\u202f\u00bb n\u2019est pas une \u00e9chelle de rapports.
NotABackwardReference_1 = Il n\u2019y a pas d\u2019\u00e9l\u00e9ment pour l\u2019identifiant \u201c{0}\u201d, ou l\u2019identifiant est une r\u00e9f\u00e9rence vers l\u2019avant.
+NotAnInteger_1 = {0} n\u2019est pas un nombre entier.
NotAKeyValuePair_1 = \u00ab\u202f{0}\u202f\u00bb n\u2019est pas une paire cl\u00e9-valeur.
NotANumber_1 = L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre NaN (Not-a-Number).
NotAPrimitiveWrapper_1 = La classe \u2018{0}\u2019 n\u2019est pas un adaptateur d\u2019un type primitif.
Modified: sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/math/PlaneTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/math/PlaneTest.java?rev=1788982&r1=1788981&r2=1788982&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/math/PlaneTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/math/PlaneTest.java [UTF-8] Mon Mar 27 16:34:20 2017
@@ -31,12 +31,18 @@ import static org.apache.sis.test.Assert
*
* @author Martin Desruisseaux (MPO, IRD)
* @since 0.5
- * @version 0.5
+ * @version 0.8
* @module
*/
@DependsOn(org.apache.sis.internal.util.DoubleDoubleTest.class)
public final strictfp class PlaneTest extends TestCase {
/**
+ * The Pearson coefficient computed by the last call to
+ * {@link #assertFitEquals(double, double[], double[], double[])}.
+ */
+ private double pearson;
+
+ /**
* Invokes {@link Plane#fit(DirectPosition[])} with the given arrays,
* and compares the fitted values against the original values.
*
@@ -44,9 +50,9 @@ public final strictfp class PlaneTest ex
*
* @param tolerance the maximal difference allowed between the fitted and the original values.
*/
- private static Plane assertFitEquals(final double tolerance, final double[] x, final double[] y, final double[] z) {
+ private Plane assertFitEquals(final double tolerance, final double[] x, final double[] y, final double[] z) {
final Plane plan = new Plane();
- final double pearson = plan.fit(x, y, z);
+ pearson = plan.fit(x, y, z);
assertEquals("Pearson correlation coefficient", 1, pearson, 0.01);
for (int i = 0; i < z.length; i++) {
assertEquals("z(x,y)", z[i], plan.z(x[i], y[i]), tolerance);
@@ -59,11 +65,11 @@ public final strictfp class PlaneTest ex
*
* @param rd the random number generator to use.
* @param length the desired array length.
- * @param offset the minimal value allowed in the returned array.
* @param scale the difference between the minimal and maximal allowed values.
+ * @param offset the minimal value allowed in the returned array.
* @return the array of random values.
*/
- private static double[] random(final Random rd, final int length, final double offset, final double scale) {
+ private static double[] random(final Random rd, final int length, final double scale, final double offset) {
final double[] x = new double[length];
for (int i=0; i<length; i++) {
x[i] = offset + scale * rd.nextDouble();
@@ -77,10 +83,9 @@ public final strictfp class PlaneTest ex
*/
@Test
public void testFit3Points() {
- // We fix the random seed in order to avoid colinear points.
- final Random rd = new Random(4762038814364076443L);
+ final Random rd = new Random(4762038814364076443L); // Fix the random seed for avoiding colinear points.
for (int n=0; n<10; n++) {
- assertFitEquals(1E-9, // We expect close to exact matches.
+ assertFitEquals(1E-9, // We expect close to exact matches.
random(rd, 3, 100, -25),
random(rd, 3, 80, -20),
random(rd, 3, 150, -40));
@@ -96,16 +101,67 @@ public final strictfp class PlaneTest ex
final Random rd = new Random(7241997054993322309L);
final double x[] = random(rd, 4000, 100, -25);
final double y[] = random(rd, 4000, 80, -20);
- final double z[] = random(rd, 4000, 150, -40);
- final Plane plan = new Plane(2, 3, -4);
+ final double z[] = random(rd, 4000, 10, -5);
+ final Plane reference = new Plane(2, 3, -4);
for (int i=0; i<z.length; i++) {
- // Compute points with random displacements above or below a known plane.
- z[i] = plan.z(x[i], y[i]) + (10 * rd.nextDouble() - 5);
+ z[i] += reference.z(x[i], y[i]); // Compute points with random displacements above or below a known plane.
}
+ /*
+ * For a random seed fixed to 7241997054993322309, the coefficients are:
+ *
+ * - reference: z(x,y) = 2.0\u22c5x + 3.0\u22c5y + -4.0
+ * - fitted: z(x,y) = 2.001595888896693\u22c5x + 3.0021028196088055\u22c5y + -4.105960575835259
+ */
final Plane fitted = assertFitEquals(6, x, y, z);
- assertEquals("sx", plan.slopeX(), fitted.slopeX(), 0.01);
- assertEquals("sy", plan.slopeY(), fitted.slopeY(), 0.01);
- assertEquals("z\u2080", plan.z0(), fitted.z0(), 1);
+ assertEquals("sx", reference.slopeX(), fitted.slopeX(), 0.002);
+ assertEquals("sy", reference.slopeY(), fitted.slopeY(), 0.003);
+ assertEquals("z\u2080", reference.z0(), fitted.z0(), 0.2);
+ }
+
+ /**
+ * Verifies that {@link Plane#fit(int, int, Vector)} produces the same result than
+ * {@link Plane#fit(double[], double[], double[])}.
+ *
+ * @since 0.8
+ */
+ @Test
+ @DependsOnMethod("testFitManyPoints")
+ public void testFitGrid() {
+ final int nx = 20;
+ final int ny = 30;
+ final Random rd = new Random(1224444984079270867L);
+ final double z[] = random(rd, nx*ny, 12, -6);
+ final double x[] = new double[z.length];
+ final double y[] = new double[z.length];
+ final Plane reference = new Plane(-46, 17, 35);
+ for (int i=0; i<z.length; i++) {
+ x[i] = i % nx;
+ y[i] = i / nx;
+ z[i] += reference.z(x[i], y[i]);
+ }
+ /*
+ * Opportunistically verify the result of fit(double[], double[], double[]), but it is
+ * not the purpose of this test (it should have been verified by testFitManyPoints()).
+ * For a random seed fixed to 7241997054993322309, the coefficients are:
+ *
+ * - reference: z(x,y) = -46.0\u22c5x + 17.0\u22c5y + 35.0
+ * - fitted: z(x,y) = -45.96034442769177\u22c5x + 16.981792790278828\u22c5y + 34.901440258861314
+ */
+ final Plane fitted = assertFitEquals(7, x, y, z);
+ assertEquals("sx", reference.slopeX(), fitted.slopeX(), 0.05);
+ assertEquals("sy", reference.slopeY(), fitted.slopeY(), 0.02);
+ assertEquals("z\u2080", reference.z0(), fitted.z0(), 0.1);
+ final double ep = pearson;
+ /*
+ * Verify that the optimized code path for a grid produces the exact same result than the
+ * generic code path.
+ */
+ final Plane gf = new Plane();
+ gf.fit(nx, ny, Vector.create(z, false));
+ assertEquals("sx", fitted.slopeX(), gf.slopeX(), STRICT);
+ assertEquals("sy", fitted.slopeY(), gf.slopeY(), STRICT);
+ assertEquals("z\u2080", fitted.z0(), gf.z0(), STRICT);
+ assertEquals("Pearson", ep, pearson, STRICT);
}
/**
Modified: sis/branches/JDK7/ide-project/NetBeans/nbproject/project.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/ide-project/NetBeans/nbproject/project.properties?rev=1788982&r1=1788981&r2=1788982&view=diff
==============================================================================
--- sis/branches/JDK7/ide-project/NetBeans/nbproject/project.properties [ISO-8859-1] (original)
+++ sis/branches/JDK7/ide-project/NetBeans/nbproject/project.properties [ISO-8859-1] Mon Mar 27 16:34:20 2017
@@ -96,15 +96,17 @@ jdom1.version = 1.0
jdom2.version = 2.0.4
jee.version = 7.0
osgi.version = 6.0.0
-netcdf.version = 4.6.6
-joda-time.version = 2.2
-httpclient.version = 4.3.6
+netcdf.version = 4.6.8
+joda-time.version = 2.8.1
+httpclient.version = 4.5.1
+httpcore.version = 4.4.4
+cm-logging.version = 1.2
slf4j.version = 1.7.7
junit.version = 4.12
hamcrest.version = 1.3
jaxb-ns-mapper = 2.2.4
hsqldb.version = 2.3.4
-postgresql.version = 9.4.1212.jre7
+postgresql.version = 42.0.0.jre7
#
# Classpaths for compilation, execution and tests.
@@ -146,6 +148,8 @@ run.test.classpath=\
${maven.repository}/edu/ucar/udunits/${netcdf.version}/udunits-${netcdf.version}.jar:\
${maven.repository}/edu/ucar/httpservices/${netcdf.version}/httpservices-${netcdf.version}.jar:\
${maven.repository}/joda-time/joda-time/${joda-time.version}/joda-time-${joda-time.version}.jar:\
+ ${maven.repository}/commons-logging/commons-logging/${cm-logging.version}/commons-logging-${cm-logging.version}.jar:\
+ ${maven.repository}/org/apache/httpcomponents/httpcore/${httpcore.version}/httpcore-${httpcore.version}.jar:\
${maven.repository}/org/apache/httpcomponents/httpclient/${httpclient.version}/httpclient-${httpclient.version}.jar:\
${maven.repository}/org/slf4j/slf4j-api/${slf4j.version}/slf4j-api-${slf4j.version}.jar:\
${maven.repository}/org/slf4j/slf4j-jdk14/${slf4j.version}/slf4j-jdk14-${slf4j.version}.jar
Modified: sis/branches/JDK7/pom.xml
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/pom.xml?rev=1788982&r1=1788981&r2=1788982&view=diff
==============================================================================
--- sis/branches/JDK7/pom.xml (original)
+++ sis/branches/JDK7/pom.xml Mon Mar 27 16:34:20 2017
@@ -429,7 +429,7 @@ Apache SIS is a free software, Java lang
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
- <version>1.12</version>
+ <version>1.13</version>
</dependency>
<!-- Databases -->
@@ -442,7 +442,7 @@ Apache SIS is a free software, Java lang
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
- <version>9.4.1212.jre7</version>
+ <version>42.0.0.jre7</version>
<scope>test</scope>
</dependency>
@@ -488,7 +488,7 @@ Apache SIS is a free software, Java lang
The last properties in this list depend on the Apache SIS branch.
=================================================================== -->
<properties>
- <netcdf.version>4.6.6</netcdf.version>
+ <netcdf.version>4.6.8</netcdf.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<website.encoding>UTF-8</website.encoding>
<website.locale>en</website.locale>