/* * Geotoolkit.org - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2007-2012, Open Source Geospatial Foundation (OSGeo) * (C) 2009-2012, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotoolkit.referencing; import java.util.Locale; import javax.measure.IncommensurableException; import org.opengis.metadata.citation.Citation; import org.opengis.referencing.datum.GeodeticDatum; import org.opengis.referencing.crs.ProjectedCRS; import org.opengis.referencing.crs.GeographicCRS; import org.opengis.referencing.cs.AxisDirection; import org.opengis.referencing.cs.CoordinateSystem; import org.opengis.referencing.cs.CoordinateSystemAxis; import org.opengis.referencing.crs.CRSAuthorityFactory; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.OperationNotFoundException; import org.opengis.util.FactoryException; import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox; import org.geotoolkit.factory.Hints; import org.geotoolkit.factory.AuthorityFactoryFinder; import org.apache.sis.referencing.CRS; import org.apache.sis.referencing.CommonCRS; import org.apache.sis.referencing.crs.DefaultCompoundCRS; import org.apache.sis.referencing.datum.BursaWolfParameters; import org.apache.sis.referencing.datum.DefaultGeodeticDatum; import org.apache.sis.referencing.IdentifiedObjects; import org.apache.sis.test.DependsOn; import org.geotoolkit.test.TestBase; import org.apache.sis.referencing.crs.AbstractCRS; import org.apache.sis.referencing.cs.AxesConvention; import org.junit.*; import static org.junit.Assume.assumeTrue; import static org.geotoolkit.referencing.Assert.*; import static org.geotoolkit.test.Commons.*; import static org.opengis.referencing.IdentifiedObject.NAME_KEY; import static java.util.Collections.singletonMap; /** * Tests if the CRS utility class is functioning correctly when using EPSG database. * * @author Jody Garnett (Refractions) * @author Martin Desruisseaux (IRD, Geomatys) * @author Andrea Aime (TOPP) * @version 3.16 * * @since 2.4 */ @DependsOn(CRS_Test.class) public final strictfp class CRS_WithEpsgTest extends TestBase { /** * Ensures that the EPSG database is available. If no EPSG database is installed, * then the tests will be skipped. We do not cause a test failure because the EPSG * database is not expected to be installed when Geotk is built for the first time * on a new machine. */ @Before public void ensureEpsgAvailable() { assumeTrue(false /*isEpsgFactoryAvailable()*/); } /** * Tests the (latitude, longitude) axis order for EPSG:4326. * * @throws FactoryException Should not happen. */ @Test public void testCorrectAxisOrder() throws FactoryException { final CoordinateReferenceSystem crs = CommonCRS.WGS84.geographic(); assertEquals("EPSG:4326", IdentifiedObjects.getIdentifierOrName(crs)); final CoordinateSystem cs = crs.getCoordinateSystem(); assertEquals(2, cs.getDimension()); CoordinateSystemAxis axis0 = cs.getAxis(0); assertEquals("Lat", axis0.getAbbreviation()); CoordinateSystemAxis axis1 = cs.getAxis(1); assertEquals("Long", axis1.getAbbreviation()); } /** * Tests the (longitude, latitude) axis order for EPSG:4326. * * @throws FactoryException Should not happen. */ @Test public void testForcedAxisOrder() throws FactoryException { final CoordinateReferenceSystem crs = AbstractCRS.castOrCopy(CommonCRS.WGS84.geographic()).forConvention(AxesConvention.RIGHT_HANDED); assertEquals("EPSG:4326", IdentifiedObjects.getIdentifierOrName(crs)); final CoordinateSystem cs = crs.getCoordinateSystem(); assertEquals(2, cs.getDimension()); CoordinateSystemAxis axis0 = cs.getAxis(0); assertEquals("Long", axis0.getAbbreviation()); CoordinateSystemAxis axis1 = cs.getAxis(1); assertEquals("Lat", axis1.getAbbreviation()); assertNotDeepEquals(crs, CommonCRS.WGS84.geographic()); // Should not be (lon,lat) axis order. } /** * Tests again EPSG:4326, but forced to (longitude, latitude) axis order. * * @throws FactoryException Should not happen. */ @Test public void testSystemPropertyToForceXY() throws FactoryException { assertNull(Hints.getSystemDefault(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER)); assertNull(Hints.putSystemDefault(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE)); final CoordinateReferenceSystem crs; try { crs = CommonCRS.WGS84.geographic(); final CoordinateSystem cs = crs.getCoordinateSystem(); assertEquals(2, cs.getDimension()); final CoordinateSystemAxis axis0 = cs.getAxis(0); assertEquals("forceXY did not work", "Long", axis0.getAbbreviation()); final CoordinateSystemAxis axis1 = cs.getAxis(1); assertEquals("forceXY did not work", "Lat", axis1.getAbbreviation()); } catch (AssertionError failure) { // A debugging help in case of test failure. System.err.println(">>> INFORMATION ON TEST FAILURE"); throw failure; } finally { assertEquals(Boolean.TRUE, Hints.removeSystemDefault(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER)); } } /** * Tests {@link IdentifiedObjects#lookupIdentifier}. * * @throws FactoryException Should not happen. */ @Test @Ignore public void testLookupIdentifier() throws FactoryException { CoordinateReferenceSystem crs = getED50("ED50"); assertEquals("Should find without scan thanks to the name.", "EPSG:4230", org.geotoolkit.referencing.IdentifiedObjects.lookupIdentifier(crs, false)); assertEquals(Integer.valueOf(4230), org.geotoolkit.referencing.IdentifiedObjects.lookupEpsgCode(crs, false)); crs = getED50("ED50 with unknown name"); assertNull("Should not find the CRS without a scan.", org.geotoolkit.referencing.IdentifiedObjects.lookupIdentifier(crs, false)); assertEquals(null, org.geotoolkit.referencing.IdentifiedObjects.lookupEpsgCode(crs, false)); assertEquals("With scan allowed, should find the CRS.", "EPSG:4230", org.geotoolkit.referencing.IdentifiedObjects.lookupIdentifier(crs, true)); assertEquals(Integer.valueOf(4230), org.geotoolkit.referencing.IdentifiedObjects.lookupEpsgCode(crs, true)); } /** * Returns a ED50 CRS with the specified name. */ private static CoordinateReferenceSystem getED50(final String name) throws FactoryException { final String wkt = "GEOGCS[\"" + name + "\",\n" + " DATUM[\"European Datum 1950\",\n" + " SPHEROID[\"International 1924\", 6378388.0, 297.0]],\n" + "PRIMEM[\"Greenwich\", 0.0],\n" + "UNIT[\"degree\", 0.017453292519943295]]"; return CRS.fromWKT(wkt); } /** * Tests the {@link CRS#parseWKT} method. * * @throws FactoryException Should not happen. */ @Test public void testWKT() throws FactoryException { String wkt = "GEOGCS[\"WGS 84\",\n" + " DATUM[\"WGS_1984\",\n" + " SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],\n" + " TOWGS84[0,0,0,0,0,0,0], AUTHORITY[\"EPSG\",\"6326\"]],\n" + " PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],\n" + " UNIT[\"DMSH\",0.0174532925199433],\n" + " AXIS[\"Lat\",NORTH], AXIS[\"Long\",EAST],\n" + " AUTHORITY[\"EPSG\",\"4326\"]]"; CoordinateReferenceSystem crs = CRS.fromWKT(wkt); assertNotNull(crs); } /** * Makes sure that the transform between two EPSG:4326 is the identity transform. * * @throws FactoryException Should not happen. */ @Test public void testFindMathTransformIdentity() throws FactoryException { CoordinateReferenceSystem crs1default = CommonCRS.WGS84.geographic(); CoordinateReferenceSystem crs2default = CommonCRS.WGS84.geographic(); MathTransform tDefault = CRS.findOperation(crs1default, crs2default, null).getMathTransform(); assertTrue("WSG84 transformed to WSG84 should be Identity", tDefault.isIdentity()); CoordinateReferenceSystem crs1force = AbstractCRS.castOrCopy(CommonCRS.WGS84.geographic()).forConvention(AxesConvention.RIGHT_HANDED); CoordinateReferenceSystem crs2force = AbstractCRS.castOrCopy(CommonCRS.WGS84.geographic()).forConvention(AxesConvention.RIGHT_HANDED); MathTransform tForce = CRS.findOperation(crs1force, crs2force, null).getMathTransform(); assertTrue("WSG84 transformed to WSG84 should be Identity", tForce.isIdentity()); } /** * Makes sure that the authority factory has the proper name. */ @Test public void testAuthority() { CRSAuthorityFactory factory; Citation authority; // Tests the official factory. factory = AuthorityFactoryFinder.getCRSAuthorityFactory("EPSG", null); authority = factory.getAuthority(); assertNotNull(authority); assertEquals("EPSG Geodetic Parameter Dataset", authority.getTitle().toString(Locale.US)); assertTrue(org.apache.sis.metadata.iso.citation.Citations.identifierMatches(authority, "EPSG")); } /** * Tests "NAD83 / Massachusetts Mainland". * * @throws FactoryException Should not happen. */ @Test public void test26986() throws FactoryException { CoordinateReferenceSystem crs = CRS.forCode("epsg:26986"); assertTrue(crs instanceof ProjectedCRS); assertEquals("EPSG:26986", IdentifiedObjects.getIdentifierOrName(crs)); } /** * Tests "AD27 / California zone II". * WFS requires this to work. * * @throws FactoryException Should not happen. */ @Test public void test26742() throws FactoryException { CoordinateReferenceSystem crs = CRS.forCode("epsg:26742"); assertTrue(crs instanceof ProjectedCRS); assertEquals("EPSG:26742", IdentifiedObjects.getIdentifierOrName(crs)); } /** * Tests "Popular Visualisation CRS / Mercator". * * @throws FactoryException Should not happen. * * @since 3.15 * * @deprecated This is the legacy pseudo-Mercator, no longer in EPSG database. */ @Test public void test3785() throws FactoryException { CoordinateReferenceSystem crs = CRS.forCode("epsg:3785"); assertTrue(crs instanceof ProjectedCRS); assertEquals("EPSG:3785", IdentifiedObjects.getIdentifierOrName(crs)); } /** * Tests "WGS 84 / Pseudo-Mercator". * This is the "Google projection". * * @throws FactoryException Should not happen. * * @since 3.15 */ @Test public void test3857() throws FactoryException { CoordinateReferenceSystem crs = CRS.forCode("epsg:3857"); assertTrue(crs instanceof ProjectedCRS); assertEquals("EPSG:3857", IdentifiedObjects.getIdentifierOrName(crs)); } /** * Tests {@link CRS#getHorizontalCRS} from a compound CRS. * * @throws FactoryException Should not happen. */ @Test public void testHorizontalFromCompound() throws FactoryException { // retrives "NTF (Paris) / France II + NGF Lallemand" CoordinateReferenceSystem compound = CRS.forCode("EPSG:7401"); CoordinateReferenceSystem horizontal = CRS.getHorizontalComponent(compound); // compares with "NTF (Paris) / France II" assertEquals(CRS.forCode("EPSG:27582"), horizontal); } /** * Tests {@link CRS#getHorizontalCRS} from a Geographic 3D CR. * * @throws FactoryException Should not happen. */ @Test public void testHorizontalFromGeodetic() throws FactoryException { // retrives "WGS 84 (geographic 3D)" CoordinateReferenceSystem compound = CRS.forCode("EPSG:4327"); CoordinateReferenceSystem horizontal = CRS.getHorizontalComponent(compound); // the horizonal version is basically 4326, but it won't compare positively with 4326, // not even using Utilities.equalsIgnoreMetadata(), so we check the axis directly. CoordinateSystem cs = horizontal.getCoordinateSystem(); assertEquals(2, cs.getDimension()); assertEquals(AxisDirection.NORTH, cs.getAxis(0).getDirection()); assertEquals(AxisDirection.EAST, cs.getAxis(1).getDirection()); } /** * Tests the creation of a math transform from 4D to 3D CRS. * * @throws FactoryException Should not happen. * * @see <a href="http://jira.geotoolkit.org/browse/GEOTK-81">GEOTK-81</a> */ @Test @Ignore public void testProjected4D() throws FactoryException { CoordinateReferenceSystem targetCRS = CRS.forCode("EPSG:3395"); CoordinateReferenceSystem sourceCRS = CRS.forCode("EPSG:27572"); sourceCRS = new DefaultCompoundCRS(singletonMap(NAME_KEY, "3D"), sourceCRS, CommonCRS.Vertical.ELLIPSOIDAL.crs()); sourceCRS = new DefaultCompoundCRS(singletonMap(NAME_KEY, "4D"), sourceCRS, CommonCRS.Temporal.JULIAN.crs()); final MathTransform tr = CRS.findOperation(sourceCRS, targetCRS, null).getMathTransform(); assertEquals(4, tr.getSourceDimensions()); assertEquals(2, tr.getTargetDimensions()); } /** * Tests the conversion from {@code EPSG:4979} to {@code EPSG:4326}. * Note that {@code EPSG:4979} is the replacement of {@code EPSG:4327} * with degrees units instead of DMS. * * @throws FactoryException Should never happen. * * @see <a href="http://jira.geotoolkit.org/browse/GEOTK-65">GEOTK-65</a> */ @Test public void testGeographic3D_to_2D() throws FactoryException { CoordinateReferenceSystem sourceCRS = CRS.forCode("EPSG:4327"); CoordinateReferenceSystem targetCRS = CommonCRS.WGS84.geographic(); MathTransform tr; try { CRS.findOperation(sourceCRS, targetCRS, null).getMathTransform(); fail("No conversion from EPSG:4327 to EPSG:4326 should be allowed because the units " + "conversion from DMS to degrees is not linear. Note that this exception may be " + "removed in a future version if we implement non-linear unit conversions."); } catch (OperationNotFoundException e) { assertTrue("The operation should have failed because of a unit conversion error.", e.getCause() instanceof IncommensurableException); } sourceCRS = CommonCRS.WGS84.geographic3D(); tr = CRS.findOperation(sourceCRS, targetCRS, null).getMathTransform(); assertEquals(3, tr.getSourceDimensions()); assertEquals(2, tr.getTargetDimensions()); assertDiagonalMatrix(tr, true, 1, 1, 0); } /** * Tests the conversion from {@code CompoundCRS[EPSG:3035 + Sigma-level]} to {@code EPSG:4326}. * The interesting part in this test is that the height is not a standard height, and the * referencing module is not supposed to known how to build a 3D Geographic CRS (needed as * an intermediate step for the datum shift) with that height. * * @throws FactoryException Should never happen. * * @see <a href="http://jira.geotoolkit.org/browse/GEOTK-71">GEOTK-71</a> */ @Test @Ignore("JSR-275 does not accept unit named 'level'.") public void testProjected3D_to_2D() throws FactoryException { CoordinateReferenceSystem targetCRS = CommonCRS.WGS84.geographic(); CoordinateReferenceSystem sourceCRS = CRS.forCode("EPSG:3035"); GeodeticDatum targetDatum = ((GeographicCRS) targetCRS).getDatum(); GeodeticDatum sourceDatum = ((ProjectedCRS) sourceCRS).getDatum(); final BursaWolfParameters[] params = ((DefaultGeodeticDatum) sourceDatum).getBursaWolfParameters(); assertEquals("This test requires that an explicit BursaWolf parameter exists.", 1, params.length); assertEquals("targetDatum", targetDatum, params[0].getTargetDatum()); assertTrue("This test requires that the BursaWolf parameter is set to identity.", params[0].isIdentity()); CoordinateReferenceSystem vertCRS = CRS.fromWKT( "VERT_CS[\"Sigma Level\",VERT_DATUM[\"Sigma Level\",2000],UNIT[\"level\",1.0],AXIS[\"Sigma Level\",DOWN]]"); sourceCRS = new DefaultCompoundCRS(singletonMap(NAME_KEY, "ETRS89 + Sigma level"), sourceCRS, vertCRS); final MathTransform tr = CRS.findOperation(sourceCRS, targetCRS, null).getMathTransform(); assertSame(tr, CRS.findOperation(sourceCRS, targetCRS, null).getMathTransform()); assertSame(tr, CRS.findOperation(sourceCRS, targetCRS, null).getMathTransform()); assertEquals(3, tr.getSourceDimensions()); assertEquals(2, tr.getTargetDimensions()); } /** * Tests {@link CRS#findMathTransform(CoordinateReferenceSystem, CoordinateReferenceSystem, * GeographicBoundingBox, boolean)}. * * @throws FactoryException Should never happen. * * @see <a href="http://jira.geotoolkit.org/browse/GEOTK-80">GEOTK-80</a> */ @Test @Ignore public void testCRSWithGeographicArea() throws FactoryException { final CoordinateReferenceSystem sourceCRS = CRS.forCode("EPSG:4267"); // NAD27 final CoordinateReferenceSystem targetCRS = CommonCRS.WGS84.geographic(); // WGS84 final DefaultGeographicBoundingBox box = new DefaultGeographicBoundingBox(-91.64, -88.09, 30.02, 35.00); // Mississipi (EPSG:1393) final MathTransform mt = CRS.findOperation(sourceCRS, targetCRS, box).getMathTransform(); /* * We expect "NAD27 to WGS 84 (56)" (EPSG:8609). Since the CoordinateOperation is lost at this stagen * we can not test the identifier code. So we will test the MathTransform WKT. In particular, we look * for the "mshpgn.las" and "mshpgn.los" parameter value as an indication of Mississipi data. */ assertMultilinesEquals(decodeQuotes( "CONCAT_MT[PARAM_MT[“Affine”, \n" + " PARAMETER[“num_row”, 3], \n" + " PARAMETER[“num_col”, 3], \n" + " PARAMETER[“elt_0_0”, 0.0], \n" + " PARAMETER[“elt_0_1”, 1.0], \n" + " PARAMETER[“elt_1_0”, 1.0], \n" + " PARAMETER[“elt_1_1”, 0.0]], \n" + " PARAM_MT[“NADCON”, \n" + " PARAMETER[“Latitude difference file”, “conus.las”], \n" + " PARAMETER[“Longitude difference file”, “conus.los”]], \n" + " PARAM_MT[“NADCON”, \n" + " PARAMETER[“Latitude difference file”, “mshpgn.las”], \n" + " PARAMETER[“Longitude difference file”, “mshpgn.los”]], \n" + " PARAM_MT[“Affine”, \n" + " PARAMETER[“num_row”, 3], \n" + " PARAMETER[“num_col”, 3], \n" + " PARAMETER[“elt_0_0”, 0.0], \n" + " PARAMETER[“elt_0_1”, 1.0], \n" + " PARAMETER[“elt_1_0”, 1.0], \n" + " PARAMETER[“elt_1_1”, 0.0]]]"), mt.toWKT()); } }