blob: 145c6c53537b0b8438cde3a41cea145912266c4b [file] [log] [blame]
/*
* 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.internal.referencing.provider;
import java.net.URISyntaxException;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.Path;
import javax.measure.quantity.Angle;
import javax.measure.quantity.Length;
import org.opengis.geometry.Envelope;
import org.opengis.util.FactoryException;
import org.opengis.referencing.operation.TransformException;
import org.apache.sis.test.DependsOnMethod;
import org.apache.sis.test.TestStep;
import org.junit.Test;
import static org.opengis.test.Assert.*;
/**
* Tests {@link FranceGeocentricInterpolation}.
*
* @author Martin Desruisseaux (Geomatys)
* @version 0.7
* @since 0.7
* @module
*/
public final strictfp class FranceGeocentricInterpolationTest extends DatumShiftTestCase {
/**
* Name of the file containing a small extract of the "{@code GR3DF97A.txt}" file.
* The amount of data in this test file is less than 0.14% of the original file.
*/
public static final String TEST_FILE = "GR3DF-extract.txt";
/**
* Returns the sample point for a step in the example given by the NTG_88 guidance note.
* The steps numbers go from 1 (NTF) to 3 (RGF93).
* Precision is given by {@link #ANGULAR_TOLERANCE}.
*
* <blockquote><b>Source:</b>
* <cite>"Grille de paramètres de transformation de coordonnées GR3DF97A"</cite>
* version 1.0, April 1997 in <a href="http://www.ign.fr">http://www.ign.fr</a>
* </blockquote>
*
* @param step the step as a value from 1 to 3 inclusive.
* @return the sample point at the given step.
*/
public static double[] samplePoint(final int step) {
switch (step) {
case 1: return new double[] { // NTF
2 + (25 + 32.4187/60)/60, // 2°25′32.4187″
48 + (50 + 40.2441/60)/60 // 48°50′40.2441″
};
case 2: return new double[] { // RGF93 with constant (ΔX,ΔY,ΔZ)
2 + (25 + 29.8273/60)/60, // 2°25′29.8273″
48 + (50 + 39.9967/60)/60 // 48°50′39.9967″
};
case 3: return new double[] { // RGF93 with interpolated (ΔX,ΔY,ΔZ)
2 + (25 + 29.89599/60)/60, // 2°25′29.89599″
48 + (50 + 40.00502/60)/60 // 48°50′40.00502″
};
default: throw new AssertionError(step);
}
}
/**
* The precision of values returned by {@link #samplePoint(int)}, in degrees.
* Use as the tolerance threshold in assertions.
*/
public static final double ANGULAR_TOLERANCE = (0.0001 / 60 / 60) / 2;
/**
* Tests {@link FranceGeocentricInterpolation#isRecognized(Path)}.
*/
@Test
public void testIsRecognized() {
assertTrue (FranceGeocentricInterpolation.isRecognized(Paths.get("GR3DF97A.txt")));
assertTrue (FranceGeocentricInterpolation.isRecognized(Paths.get("gr3df")));
assertFalse(FranceGeocentricInterpolation.isRecognized(Paths.get("gr3d")));
assertTrue (FranceGeocentricInterpolation.isRecognized(Paths.get(TEST_FILE)));
}
/**
* Tests {@link FranceGeocentricInterpolation#redimension(int, int)}.
*/
@Test
public void testRedimension() {
MolodenskyTest.testRedimension(new FranceGeocentricInterpolation());
}
/**
* Tests a small grid file with interpolations in geocentric coordinates.
*
* @throws URISyntaxException if the URL to the test file can not be converted to a path.
* @throws IOException if an error occurred while loading the grid.
* @throws FactoryException if an error occurred while computing the grid.
* @throws TransformException if an error occurred while computing the envelope.
*/
@Test
public void testGrid() throws URISyntaxException, IOException, FactoryException, TransformException {
testGridAsShorts(testGridAsFloats());
}
/**
* Tests a small grid file with interpolations in geocentric coordinates as {@code float} values.
*
* <p>This method is part of a chain.
* The next method is {@link #testGridAsShorts(DatumShiftGridFile)}.</p>
*
* @return the loaded grid with values as {@code float}.
* @throws URISyntaxException if the URL to the test file can not be converted to a path.
* @throws IOException if an error occurred while loading the grid.
* @throws FactoryException if an error occurred while computing the grid.
* @throws TransformException if an error occurred while computing the envelope.
*/
@TestStep
private static DatumShiftGridFile<Angle,Length> testGridAsFloats()
throws URISyntaxException, IOException, FactoryException, TransformException
{
final Path file = getResource(TEST_FILE);
final DatumShiftGridFile.Float<Angle,Length> grid;
try (BufferedReader in = Files.newBufferedReader(file)) {
grid = FranceGeocentricInterpolation.load(in, file);
}
assertEquals("cellPrecision", 0.005, grid.getCellPrecision(), STRICT);
assertEquals("getCellMean", 168.2587, grid.getCellMean(0), 0.0001);
assertEquals("getCellMean", 58.7163, grid.getCellMean(1), 0.0001);
assertEquals("getCellMean", -320.1801, grid.getCellMean(2), 0.0001);
verifyGrid(grid);
return grid;
}
/**
* Tests a small grid file with interpolations in geocentric coordinates as {@code short} values.
*
* <p>This method is part of a chain.
* The previous method is {@link #testGridAsFloats()}.</p>
*
* @param grid the grid created by {@link #testGridAsFloats()}.
* @return the given grid, but compressed as {@code short} values.
* @throws TransformException if an error occurred while computing the envelope.
*/
@TestStep
private static DatumShiftGridFile<Angle,Length> testGridAsShorts(DatumShiftGridFile<Angle,Length> grid)
throws TransformException
{
grid = DatumShiftGridCompressed.compress((DatumShiftGridFile.Float<Angle,Length>) grid, new double[] {
FranceGeocentricInterpolation.TX, // 168 metres
FranceGeocentricInterpolation.TY, // 60 metres
FranceGeocentricInterpolation.TZ}, // -320 metres
FranceGeocentricInterpolation.PRECISION);
assertInstanceOf("Failed to compress 'float' values into 'short' values.", DatumShiftGridCompressed.class, grid);
assertEquals("cellPrecision", 0.0005, grid.getCellPrecision(), STRICT);
assertEquals("getCellMean", 168, grid.getCellMean(0), STRICT);
assertEquals("getCellMean", 60, grid.getCellMean(1), STRICT);
assertEquals("getCellMean", -320, grid.getCellMean(2), STRICT);
verifyGrid(grid);
return grid;
}
/**
* Verifies the envelope and the interpolation performed by the given grid.
*
* @throws TransformException if an error occurred while computing the envelope.
*/
private static void verifyGrid(final DatumShiftGridFile<Angle,Length> grid) throws TransformException {
final Envelope envelope = grid.getDomainOfValidity();
assertEquals("xmin", 2.2 - 0.05, envelope.getMinimum(0), 1E-12);
assertEquals("xmax", 2.5 + 0.05, envelope.getMaximum(0), 1E-12);
assertEquals("ymin", 48.5 - 0.05, envelope.getMinimum(1), 1E-12);
assertEquals("ymax", 49.0 + 0.05, envelope.getMaximum(1), 1E-12);
/*
* The values in the NTG_88 document are:
*
* (gridX=2, gridY=3) 00002 2.400000000 48.800000000 -168.252 -58.630 320.170 01 2314
* (gridX=2, gridY=4) 00002 2.400000000 48.900000000 -168.275 -58.606 320.189 01 2314
* (gridX=3, gridY=3) 00002 2.500000000 48.800000000 -168.204 -58.594 320.125 01 2314
* (gridX=3, gridY=4) 00002 2.500000000 48.900000000 -168.253 -58.554 320.165 01 2314
*
* Directions (signs) are reversed compared to NTG_88 document.
*/
assertEquals("translationDimensions", 3, grid.getTranslationDimensions());
assertEquals("grid.accuracy", 0.05, grid.accuracy, STRICT);
assertEquals("getCellValue", 168.196, grid.getCellValue(0, 2, 1), STRICT);
assertEquals("getCellValue", 58.778, grid.getCellValue(1, 2, 1), STRICT);
assertEquals("getCellValue", -320.127, grid.getCellValue(2, 2, 1), STRICT);
/*
* Interpolate the (ΔX, ΔY, ΔZ) at a point.
* Directions (signs) are reversed compared to NTG_88 document.
*/
final double[] expected = {
168.253, // ΔX: Toward prime meridian
58.609, // ΔY: Toward 90° east
-320.170 // ΔZ: Toward north pole
};
final double[] point = samplePoint(3);
final double[] vector = grid.interpolateAt(point[0], point[1]);
assertArrayEquals("(ΔX, ΔY, ΔZ)", expected, vector, 0.0005);
}
/**
* Tests the {@link FranceGeocentricInterpolation#getOrLoad(Path, double[], double)} method and its cache.
*
* @throws URISyntaxException if the URL to the test file can not be converted to a path.
* @throws FactoryException if an error occurred while computing the grid.
* @throws TransformException if an error occurred while computing the envelope.
*/
@Test
@DependsOnMethod("testGrid")
public void testGetOrLoad() throws URISyntaxException, FactoryException, TransformException {
final DatumShiftGridFile<Angle,Length> grid = FranceGeocentricInterpolation.getOrLoad(
getResource(TEST_FILE), new double[] {
FranceGeocentricInterpolation.TX,
FranceGeocentricInterpolation.TY,
FranceGeocentricInterpolation.TZ},
FranceGeocentricInterpolation.PRECISION);
verifyGrid(grid);
assertSame("Expected a cached value.", grid, FranceGeocentricInterpolation.getOrLoad(
getResource(TEST_FILE), new double[] {
FranceGeocentricInterpolation.TX,
FranceGeocentricInterpolation.TY,
FranceGeocentricInterpolation.TZ},
FranceGeocentricInterpolation.PRECISION));
}
}