This is an automated email from the ASF dual-hosted git repository.
desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new af89c09 Test GeodeticCalculator against the data set provided by
Charles Karney (2010): Test set for geodesics [Data set] -
http://doi.org/10.5281/zenodo.32156 We have to use a tolerance threshold of 1%
of expected distance for now, because we do not yet implement ellipsoidal
formulas.
af89c09 is described below
commit af89c097dffe9e9a782bc364ef5f02b456ce6897
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Sun May 19 22:00:38 2019 +0200
Test GeodeticCalculator against the data set provided by Charles Karney
(2010): Test set for geodesics [Data set] - http://doi.org/10.5281/zenodo.32156
We have to use a tolerance threshold of 1% of expected distance for now,
because we do not yet implement ellipsoidal formulas.
---
.../sis/referencing/GeodeticCalculatorTest.java | 111 ++++++++++++++++++
.../apache/sis/internal/system/DataDirectory.java | 18 ++-
.../java/org/apache/sis/test/OptionalTestData.java | 126 +++++++++++++++++++++
3 files changed, 251 insertions(+), 4 deletions(-)
diff --git
a/core/sis-referencing/src/test/java/org/apache/sis/referencing/GeodeticCalculatorTest.java
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/GeodeticCalculatorTest.java
index 80c5610..0b004fb 100644
---
a/core/sis-referencing/src/test/java/org/apache/sis/referencing/GeodeticCalculatorTest.java
+++
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/GeodeticCalculatorTest.java
@@ -19,14 +19,19 @@ package org.apache.sis.referencing;
import java.awt.Shape;
import java.awt.geom.Point2D;
import java.awt.geom.PathIterator;
+import java.util.Arrays;
import java.util.Random;
+import java.io.IOException;
+import java.io.LineNumberReader;
import org.opengis.geometry.DirectPosition;
import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.operation.TransformException;
import org.apache.sis.internal.referencing.j2d.ShapeUtilities;
import org.apache.sis.internal.referencing.Formulas;
import org.apache.sis.geometry.DirectPosition2D;
+import org.apache.sis.util.CharSequences;
import org.apache.sis.measure.Units;
+import org.apache.sis.test.OptionalTestData;
import org.apache.sis.test.DependsOnMethod;
import org.apache.sis.test.TestUtilities;
import org.apache.sis.test.TestCase;
@@ -307,4 +312,110 @@ public final strictfp class GeodeticCalculatorTest
extends TestCase {
}
return length;
}
+
+ /**
+ * Compares computations against values provided in <cite>Karney (2010)
Test set for geodesics</cite>.
+ * This is an optional test executed only if the {@code
$SIS_DATA/Tests/GeodTest.dat} file is found.
+ *
+ * @throws IOException if an error occurred while reading the test file.
+ * @throws TransformException if an error occurred while transforming
coordinates.
+ */
+ @Test
+ public void compareAgainstDataset() throws IOException, TransformException
{
+ try (LineNumberReader reader = OptionalTestData.GEODESIC.reader()) {
+ final GeodeticCalculator c = new
GeodeticCalculator(CommonCRS.WGS84.geographic());
+ final Geodesic reference = new
Geodesic(Formulas.getAuthalicRadius(c.ellipsoid), 0);
+ final Random random = TestUtilities.createRandomNumberGenerator();
+ final double[] data = new double[7];
+ try {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ Arrays.fill(data, Double.NaN);
+ final CharSequence[] split = CharSequences.split(line, '
');
+ for (int i=min(split.length, data.length); --i >= 0;) {
+ data[i] = Double.parseDouble(split[i].toString());
+ }
+ /*
+ * We aim for an 1 cm accuracy. However when spherical
formulas are used instead
+ * than ellipsoidal formulas, an error up to 1% is
expected (Wikipedia).
+ */
+ final double tolerance = data[6] * 0.01; //
1% of distance.
+ final double cosφ = abs(cos(toRadians(data[3]))); //
For adjusting longitude tolerance.
+ c.setStartPoint(data[0], data[1]); //
(φ₁, λ₁)
+ if (random.nextBoolean()) {
+ /*
+ * Computes the end point from a distance and azimuth.
The angular tolerance
+ * is derived from the linear tolerance, except at
pole where we disable the
+ * check of longitude and azimuth values.
+ */
+ c.setStartingAzimuth (data[2]);
+ c.setGeodesicDistance(data[6]);
+ final double latitudeTolerance = tolerance *
(1d/6371007 * (180/PI));
+ final double longitudeTolerance;
+ if (data[3] > 89.5) {
+ longitudeTolerance = 180; // TODO:
remove after we use spherical formulas.
+ } else {
+ longitudeTolerance = latitudeTolerance / cosφ;
+ }
+ final double azimuthTolerance = 0.5 / cosφ;
+ compareGeodeticData(data, c, latitudeTolerance,
longitudeTolerance,
+ azimuthTolerance,
Formulas.LINEAR_TOLERANCE);
+ /*
+ * Replace the distance and azimuth values by values
computed using spherical formulas,
+ * then compare again with values computed by
GeodeticCalculator but with low tolerance.
+ */
+ final GeodesicData gd = reference.Direct(data[0],
data[1], data[2], data[6]);
+ data[3] = gd.lat2;
+ data[4] = gd.lon2;
+ data[5] = gd.azi2;
+ } else {
+ /*
+ * Compute the distance and azimuth values between two
points. We perform
+ * this test or the above test randomly instead of
always executing both
+ * of them for making sure that GeodeticCalculator
never see the expected
+ * values.
+ */
+ c.setEndPoint(data[3], data[4]); // (φ₂, λ₂)
+ compareGeodeticData(data, c,
+ Formulas.ANGULAR_TOLERANCE, //
Latitude tolerance
+ Formulas.ANGULAR_TOLERANCE, //
Longitude tolerance
+ 100 / cosφ, tolerance); // Azimuth
is inaccurate for reason not yet identified.
+ /*
+ * Replace the distance and azimuth values by values
computed using spherical formulas,
+ * then compare again with values computed by
GeodeticCalculator but with low tolerance.
+ */
+ final GeodesicData gd = reference.Inverse(data[0],
data[1], data[3], data[4]);
+ data[2] = gd.azi1;
+ data[5] = gd.azi2;
+ data[6] = gd.s12;
+ }
+ compareGeodeticData(data, c, Formulas.ANGULAR_TOLERANCE,
+ Formulas.ANGULAR_TOLERANCE, 1E-4,
Formulas.LINEAR_TOLERANCE);
+ }
+ } catch (AssertionError e) {
+ out.printf("Test failure at line %d%nGeodetic calculator
is:%n", reader.getLineNumber());
+ out.println(c);
+ throw e;
+ }
+ }
+ }
+
+ /**
+ * Verifies that geodetic calculator results are equal to the given values.
+ * Order in the {@code data} array is as documented in {@link
OptionalTestData#GEODESIC}.
+ */
+ private static void compareGeodeticData(final double[] expected, final
GeodeticCalculator c,
+ final double latitudeTolerance, final double longitudeTolerance,
final double azimuthTolerance,
+ final double linearTolerance) throws TransformException
+ {
+ final DirectPosition start = c.getStartPoint();
+ final DirectPosition end = c.getEndPoint();
+ assertEquals("φ₁", expected[0], start.getOrdinate(0),
Formulas.ANGULAR_TOLERANCE);
+ assertEquals("λ₁", expected[1], start.getOrdinate(1),
Formulas.ANGULAR_TOLERANCE);
+ assertEquals("α₁", expected[2], c.getStartingAzimuth(),
azimuthTolerance);
+ assertEquals("φ₂", expected[3], end.getOrdinate(0),
latitudeTolerance);
+ assertEquals("λ₂", expected[4], end.getOrdinate(1),
longitudeTolerance);
+ assertEquals("α₂", expected[5], c.getEndingAzimuth(),
azimuthTolerance);
+ assertEquals("s₁₂", expected[6], c.getGeodesicDistance(),
linearTolerance);
+ }
}
diff --git
a/core/sis-utility/src/main/java/org/apache/sis/internal/system/DataDirectory.java
b/core/sis-utility/src/main/java/org/apache/sis/internal/system/DataDirectory.java
index 40ba41b..b1af2c4 100644
---
a/core/sis-utility/src/main/java/org/apache/sis/internal/system/DataDirectory.java
+++
b/core/sis-utility/src/main/java/org/apache/sis/internal/system/DataDirectory.java
@@ -33,7 +33,7 @@ import org.apache.sis.util.resources.Messages;
* Sub-directories of {@code SIS_DATA} where SIS looks for EPSG database,
datum shift grids and other resources.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
* @since 0.7
* @module
*/
@@ -54,7 +54,14 @@ public enum DataDirectory {
* The {@code "DomainsOfValidity"} directory.
* This directory is used for storing shapefiles for the CRS domains of
validity.
*/
- DOMAINS_OF_VALIDITY;
+ DOMAINS_OF_VALIDITY,
+
+ /**
+ * The {@code "Tests" directory}.
+ * This directory is used for optional test files that are too large for
inclusion in source code repository.
+ * This is used at build time of Apache SIS project, but not used during
normal execution.
+ */
+ TESTS;
/**
* The name of the environment variable.
@@ -215,11 +222,14 @@ public enum DataDirectory {
}
/**
- * If the given path is relative, returns the path as a child of the
directory represented this enum.
+ * If the given path is relative, returns the path as a child of the
directory represented by this enum.
* If no valid directory is configured by the {@code SIS_DATA} environment
variable, then the relative
* path is returned as-is.
*
- * @param file The path to resolve, or {@code null}.
+ * <p>This method is invoked for files that may be user-specified, for
example datum shift file specified
+ * in {@link org.opengis.parameter.ParameterValue}.</p>
+ *
+ * @param file the path to resolve, or {@code null}.
* @return the path to use, or {@code null} if the given path was null.
*/
public Path resolve(Path file) {
diff --git
a/core/sis-utility/src/test/java/org/apache/sis/test/OptionalTestData.java
b/core/sis-utility/src/test/java/org/apache/sis/test/OptionalTestData.java
new file mode 100644
index 0000000..c322e0c
--- /dev/null
+++ b/core/sis-utility/src/test/java/org/apache/sis/test/OptionalTestData.java
@@ -0,0 +1,126 @@
+/*
+ * 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.test;
+
+import java.io.LineNumberReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.apache.sis.internal.system.DataDirectory;
+
+import static org.junit.Assume.assumeNotNull;
+
+
+/**
+ * All optional test data used by Apache SIS. Those data are not present on
the source code repository.
+ * They must be downloaded and installed by the developer in the {@code
$SIS_DATA/Tests} directory in
+ * order to enable the tests requiring those data.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ * @since 1.0
+ * @module
+ */
+public enum OptionalTestData {
+ /**
+ * Geodesic distances, rhumb line length and azimuths on WGS84 ellipsoid
computed from a set of points.
+ *
+ * <dl>
+ * <dt>File:</dt>
+ * <dd>{@code GeodTest.dat}</dd>
+ * <dt>Size:</dt>
+ * <dd>86558916 bytes (83 Mb)</dd>
+ * <dt>MD5 sum:</dt>
+ * <dd>{@code 3461c4dc2500a8bad9394cd530b13dbe}</dd>
+ * <dt>Source:</dt>
+ * <dd><a href="http://doi.org/10.5281/zenodo.32156">Karney, C. F. F.
(2010). Test set for geodesics [Data set]. Zenodo.</a></dd>
+ * </dl>
+ *
+ * Each line in the test file gives the following numbers (space
delimited):
+ *
+ * <ol>
+ * <li>φ₁ — latitude at point 1 (degrees)</li>
+ * <li>λ₁ — longitude at point 1 (degrees)</li>
+ * <li>α₁ — azimuth at point 1 (degrees, clockwise from north)</li>
+ * <li>φ₂ — latitude at point 2 (degrees)</li>
+ * <li>λ₂ — longitude at point 2 (degrees)</li>
+ * <li>α₂ — azimuth at point 2 (degrees, clockwise from north)</li>
+ * <li>s₁₂ — geodesic distance from point 1 to point 2 (metres)</li>
+ * <li>σ₁₂ — arc distance on the auxiliary sphere (degrees)</li>
+ * <li>m₁₂ — reduced length of the geodesic (meters)</li>
+ * <li>S₁₂ — the area between the geodesic and the equator (m²)</li>
+ * </ol>
+ */
+ GEODESIC("GeodTest.dat");
+
+ /**
+ * The filename in {@code $SIS_DATA/Tests} directory.
+ */
+ private final String filename;
+
+ /**
+ * Creates a new enumeration for the given file.
+ */
+ private OptionalTestData(final String filename) {
+ this.filename = filename;
+ }
+
+ /**
+ * Returns the path to the test file if {@code $IS_DATA} is defined an the
file exists, or {@code null} otherwise.
+ *
+ * @return path to the test file, or {@code null} if none.
+ */
+ private Path path() {
+ Path path = DataDirectory.TESTS.getDirectory();
+ if (path != null) {
+ path = path.resolve(filename);
+ if (Files.isRegularFile(path)) {
+ return path;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * If the test file represented by this enumeration exists, opens it as an
input stream.
+ * If the file does not exist, throws {@link
org.junit.AssumptionViolatedException} as
+ * by {@link org.junit.Assume} methods.
+ *
+ * @return an input stream for the test file represented by this
enumeration.
+ * @throws IOException if an error occurred while opening the test file.
+ */
+ public InputStream open() throws IOException {
+ final Path path = path();
+ assumeNotNull(name(), path);
+ return Files.newInputStream(path);
+ }
+
+ /**
+ * If the test file represented by this enumeration exists, opens it as a
UTF-8 character reader.
+ * If the file does not exist, throws {@link
org.junit.AssumptionViolatedException} as by
+ * {@link org.junit.Assume} methods.
+ *
+ * @return an UTF-8 character reader for the test file represented by this
enumeration.
+ * @throws IOException if an error occurred while opening the test file.
+ */
+ public LineNumberReader reader() throws IOException {
+ final InputStream in = open();
+ return new LineNumberReader(new InputStreamReader(in, "UTF-8"));
+ }
+}