blob: b6ac4fc1d2a1d586a06643eddd2ba962d71a0115 [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.referencing.datum;
import java.util.Map;
import java.util.HashMap;
import java.util.Locale;
import javax.xml.bind.JAXBException;
import org.opengis.metadata.extent.Extent;
import org.opengis.referencing.operation.Matrix;
import org.opengis.referencing.datum.GeodeticDatum;
import org.opengis.test.Validators;
import org.apache.sis.measure.Units;
import org.apache.sis.xml.Namespaces;
import org.apache.sis.io.wkt.Convention;
import org.apache.sis.metadata.iso.extent.DefaultExtent;
import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox;
import org.apache.sis.test.xml.TestCase;
import org.apache.sis.test.DependsOnMethod;
import org.apache.sis.test.DependsOn;
import org.apache.sis.test.TestStep;
import org.junit.Test;
import static org.apache.sis.test.ReferencingAssert.*;
import static org.apache.sis.referencing.GeodeticObjectVerifier.*;
/**
* Tests the {@link DefaultGeodeticDatum} class.
*
* @author Martin Desruisseaux (Geomatys)
* @version 0.8
* @since 0.4
* @module
*/
@DependsOn({
DefaultPrimeMeridianTest.class,
DefaultEllipsoidTest.class,
BursaWolfParametersTest.class
})
public final strictfp class DefaultGeodeticDatumTest extends TestCase {
/**
* An XML file in this package containing a geodetic datum definition.
*/
private static final String XML_FILE = "GeodeticDatum.xml";
/**
* Tests the creation and serialization of a {@link DefaultGeodeticDatum}.
*/
@Test
public void testCreateAndSerialize() {
final Map<String,Object> properties = new HashMap<>();
assertNull(properties.put(DefaultEllipsoid.NAME_KEY, "Asteroid"));
final DefaultEllipsoid ellipsoid = DefaultEllipsoid.createEllipsoid(properties, 1200, 1000, Units.METRE);
properties.clear();
assertNull(properties.put(DefaultEllipsoid.NAME_KEY, "Somewhere"));
final DefaultPrimeMeridian primeMeridian = new DefaultPrimeMeridian(properties, 12, Units.DEGREE);
properties.clear();
assertNull(properties.put("name", "This is a name"));
assertNull(properties.put("scope", "This is a scope"));
assertNull(properties.put("scope_fr", "Valide pour tel usage"));
assertNull(properties.put("remarks", "There is remarks"));
assertNull(properties.put("remarks_fr", "Voici des remarques"));
assertNull(properties.put("remarks_ja", "注です。"));
final DefaultGeodeticDatum datum = new DefaultGeodeticDatum(properties, ellipsoid, primeMeridian);
validate(datum);
validate(assertSerializedEquals(datum));
}
/**
* Compares the properties of the given datum objects with the properties set by the
* {@link #testCreateAndSerialize()} method.
*/
private static void validate(final DefaultGeodeticDatum datum) {
Validators.validate(datum);
assertEquals("name", "This is a name", datum.getName ().getCode());
assertEquals("scope", "This is a scope", datum.getScope ().toString(Locale.ROOT));
assertEquals("scope_fr", "Valide pour tel usage", datum.getScope ().toString(Locale.FRENCH));
assertEquals("remarks", "There is remarks", datum.getRemarks().toString(Locale.ROOT));
assertEquals("remarks_fr", "Voici des remarques", datum.getRemarks().toString(Locale.FRENCH));
assertEquals("remarks_ja", "注です。", datum.getRemarks().toString(Locale.JAPANESE));
}
/**
* Tests {@link DefaultGeodeticDatum#isHeuristicMatchForName(String)}.
*/
@Test
public void testIsHeuristicMatchForName() {
DefaultGeodeticDatum datum = new DefaultGeodeticDatum(GeodeticDatumMock.WGS84);
assertFalse(datum.isHeuristicMatchForName("WGS72"));
assertTrue (datum.isHeuristicMatchForName("WGS84"));
assertTrue (datum.isHeuristicMatchForName("WGS 84"));
assertTrue (datum.isHeuristicMatchForName("WGS_84"));
assertTrue (datum.isHeuristicMatchForName("D_WGS_84"));
assertFalse(datum.isHeuristicMatchForName("E_WGS_84"));
datum = HardCodedDatum.NTF;
assertFalse(datum.isHeuristicMatchForName("WGS84"));
assertTrue (datum.isHeuristicMatchForName("Nouvelle Triangulation Française"));
assertTrue (datum.isHeuristicMatchForName("Nouvelle Triangulation Francaise"));
assertTrue (datum.isHeuristicMatchForName("Nouvelle Triangulation Française (Paris)"));
assertTrue (datum.isHeuristicMatchForName("Nouvelle Triangulation Francaise (Paris)"));
assertFalse(datum.isHeuristicMatchForName("Nouvelle Triangulation Francaise (Greenwich)"));
}
/**
* Tests {@link DefaultGeodeticDatum#getPositionVectorTransformation(GeodeticDatum, Extent)}.
*/
@Test
@DependsOnMethod("testCreateAndSerialize")
public void testGetPositionVectorTransformation() {
final Map<String,Object> properties = new HashMap<>();
assertNull(properties.put(DefaultGeodeticDatum.NAME_KEY, "Invalid dummy datum"));
/*
* Associate two BursaWolfParameters, one valid only in a local area and the other one
* valid globaly. Note that we are building an invalid set of parameters, because the
* source datum are not the same in both case. But for this test we are not interrested
* in datum consistency - we only want any Bursa-Wolf parameters having different area
* of validity.
*/
final BursaWolfParameters local = BursaWolfParametersTest.createED87_to_WGS84(); // Local area (North Sea)
final BursaWolfParameters global = BursaWolfParametersTest.createWGS72_to_WGS84(); // Global area (World)
assertNull(properties.put(DefaultGeodeticDatum.BURSA_WOLF_KEY, new BursaWolfParameters[] {local, global}));
/*
* Build the datum using WGS 72 ellipsoid (so at least one of the BursaWolfParameters is real).
*/
final DefaultGeodeticDatum datum = new DefaultGeodeticDatum(properties,
GeodeticDatumMock.WGS72.getEllipsoid(),
GeodeticDatumMock.WGS72.getPrimeMeridian());
/*
* Search for BursaWolfParameters around the North Sea area.
*/
final DefaultGeographicBoundingBox areaOfInterest = new DefaultGeographicBoundingBox(-2, 8, 55, 60);
final DefaultExtent extent = new DefaultExtent("Around the North Sea", areaOfInterest, null, null);
Matrix matrix = datum.getPositionVectorTransformation(GeodeticDatumMock.NAD83, extent);
assertNull("No BursaWolfParameters for NAD83", matrix);
matrix = datum.getPositionVectorTransformation(GeodeticDatumMock.WGS84, extent);
assertNotNull("BursaWolfParameters for WGS84", matrix);
checkTransformationSignature(local, matrix, 0);
/*
* Expand the area of interest to something greater than North Sea, and test again.
*/
areaOfInterest.setWestBoundLongitude(-8);
matrix = datum.getPositionVectorTransformation(GeodeticDatumMock.WGS84, extent);
assertNotNull("BursaWolfParameters for WGS84", matrix);
checkTransformationSignature(global, matrix, 0);
/*
* Search in the reverse direction.
*/
final DefaultGeodeticDatum targetDatum = new DefaultGeodeticDatum(GeodeticDatumMock.WGS84);
matrix = targetDatum.getPositionVectorTransformation(datum, extent);
global.invert(); // Expected result is the inverse.
checkTransformationSignature(global, matrix, 1E-6);
}
/**
* Verifies if the given matrix is for the expected Position Vector transformation.
* The easiest way to verify that is to check the translation terms (last matrix column),
* which should have been copied verbatim from the {@code BursaWolfParameters} to the matrix.
* Other terms in the matrix are modified compared to the {@code BursaWolfParameters} ones.
*/
private static void checkTransformationSignature(final BursaWolfParameters expected, final Matrix actual,
final double tolerance)
{
assertEquals("tX", expected.tX, actual.getElement(0, 3), tolerance);
assertEquals("tY", expected.tY, actual.getElement(1, 3), tolerance);
assertEquals("tZ", expected.tZ, actual.getElement(2, 3), tolerance);
}
/**
* Tests {@link DefaultGeodeticDatum#toWKT()}.
*/
@Test
public void testToWKT() {
final DefaultGeodeticDatum datum = new DefaultGeodeticDatum(GeodeticDatumMock.WGS84);
assertWktEquals(Convention.WKT2,
"DATUM[“WGS84”,\n" +
" ELLIPSOID[“WGS84”, 6378137.0, 298.257223563, LENGTHUNIT[“metre”, 1]]]",
datum);
assertWktEquals(Convention.WKT2_SIMPLIFIED,
"GeodeticDatum[“WGS84”,\n" +
" Ellipsoid[“WGS84”, 6378137.0, 298.257223563]]",
datum);
}
/**
* Tests marshalling.
*
* @throws JAXBException if an error occurred during marshalling.
*/
@Test
public void testMarshalling() throws JAXBException {
assertXmlEquals(
"<gml:GeodeticDatum xmlns:gml=\"" + Namespaces.GML + "\">\n" +
" <gml:name codeSpace=\"test\">WGS84</gml:name>\n" +
" <gml:primeMeridian>\n" +
" <gml:PrimeMeridian>\n" +
" <gml:name codeSpace=\"test\">Greenwich</gml:name>\n" +
" <gml:greenwichLongitude uom=\"urn:ogc:def:uom:EPSG::9102\">0.0</gml:greenwichLongitude>\n" +
" </gml:PrimeMeridian>\n" +
" </gml:primeMeridian>\n" +
" <gml:ellipsoid>\n" +
" <gml:Ellipsoid>\n" +
" <gml:name codeSpace=\"test\">WGS84</gml:name>\n" +
" <gml:semiMajorAxis uom=\"urn:ogc:def:uom:EPSG::9001\">6378137.0</gml:semiMajorAxis>\n" +
" <gml:secondDefiningParameter>\n" +
" <gml:SecondDefiningParameter>\n" +
" <gml:inverseFlattening uom=\"urn:ogc:def:uom:EPSG::9201\">298.257223563</gml:inverseFlattening>\n" +
" </gml:SecondDefiningParameter>\n" +
" </gml:secondDefiningParameter>\n" +
" </gml:Ellipsoid>\n" +
" </gml:ellipsoid>\n" +
"</gml:GeodeticDatum>",
marshal(new DefaultGeodeticDatum(GeodeticDatumMock.WGS84)), "xmlns:*");
}
/**
* Tests unmarshalling.
*
* <p>This method is part of a chain.
* The next method is {@link #testUnmarshalledWKT()}.</p>
*
* @return the unmarshalled datum.
* @throws JAXBException if an error occurred during unmarshalling.
*/
@TestStep
public DefaultGeodeticDatum testUnmarshalling() throws JAXBException {
final DefaultGeodeticDatum datum = unmarshalFile(DefaultGeodeticDatum.class, XML_FILE);
assertIsWGS84(datum, true);
/*
* Values in the following tests are specific to our XML file.
* The actual texts in the EPSG database are more descriptive.
*/
assertEquals("remarks", "No distinction between the original and subsequent WGS 84 frames.",
datum.getRemarks().toString());
assertEquals("scope", "Satellite navigation.",
datum.getScope().toString());
assertEquals("anchorDefinition", "Station coordinates changed by a few centimetres in 1994, 1997, 2002 and 2012.",
datum.getAnchorPoint().toString());
assertEquals("realizationEpoch", xmlDate("1984-01-01 00:00:00"),
datum.getRealizationEpoch());
assertEquals("remarks", "Defining parameters cited in EPSG database.",
datum.getEllipsoid().getRemarks().toString());
return datum;
}
/**
* Tests the WKT formatting of the datum created by {@link #testUnmarshalling()}.
*
* @throws JAXBException if an error occurred during unmarshalling.
*/
@Test
@DependsOnMethod("testToWKT")
public void testUnmarshalledWKT() throws JAXBException {
final DefaultGeodeticDatum datum = testUnmarshalling();
assertWktEquals(Convention.WKT1,
"DATUM[“World Geodetic System 1984”,\n" +
" SPHEROID[“WGS 84”, 6378137.0, 298.257223563],\n" +
" AUTHORITY[“EPSG”, “6326”]]",
datum);
assertWktEquals(Convention.WKT2,
"DATUM[“World Geodetic System 1984”,\n" +
" ELLIPSOID[“WGS 84”, 6378137.0, 298.257223563, LENGTHUNIT[“metre”, 1]],\n" +
" ID[“EPSG”, 6326, URI[“urn:ogc:def:datum:EPSG::6326”]]]",
datum);
assertWktEquals(Convention.WKT2_SIMPLIFIED,
"GeodeticDatum[“World Geodetic System 1984”,\n" +
" Ellipsoid[“WGS 84”, 6378137.0, 298.257223563],\n" +
" Id[“EPSG”, 6326, URI[“urn:ogc:def:datum:EPSG::6326”]]]",
datum);
assertWktEquals(Convention.INTERNAL,
"GeodeticDatum[“World Geodetic System 1984”,\n" +
" Ellipsoid[“WGS 84”, 6378137.0, 298.257223563, Id[“EPSG”, 7030],\n" +
" Remark[“Defining parameters cited in EPSG database.”]],\n" +
" Anchor[“Station coordinates changed by a few centimetres in 1994, 1997, 2002 and 2012.”],\n" +
" Scope[“Satellite navigation.”],\n" +
" Area[“World.”],\n" +
" BBox[-90.00, -180.00, 90.00, 180.00],\n" +
" Id[“EPSG”, 6326],\n" +
" Remark[“No distinction between the original and subsequent WGS 84 frames.”]]",
datum);
}
}