/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2005-2008, Open Source Geospatial Foundation (OSGeo) * * 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.geotools.referencing.factory; // J2SE dependencies import java.util.Map; import java.util.Set; import java.util.logging.Level; // JUnit dependencies import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; // OpenGIS dependencies import org.opengis.referencing.IdentifiedObject; import org.opengis.referencing.FactoryException; import org.opengis.referencing.crs.SingleCRS; import org.opengis.referencing.crs.ProjectedCRS; import org.opengis.referencing.crs.CRSAuthorityFactory; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.cs.CoordinateSystem; import org.opengis.referencing.operation.CoordinateOperationFactory; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.Matrix; // Geotools dependencies import org.geotools.factory.Hints; import org.geotools.resources.Arguments; import org.geotools.referencing.CRS; import org.geotools.referencing.ReferencingFactoryFinder; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.geotools.referencing.operation.LinearTransform; import org.geotools.referencing.operation.matrix.GeneralMatrix; import org.geotools.referencing.cs.DefaultCoordinateSystemAxis; import org.geotools.referencing.factory.epsg.CartesianAuthorityFactory; import org.geotools.referencing.factory.epsg.LongitudeFirstFactory; /** * Tests the usage of {@link OrderedAxisAuthorityFactory} with the help of the * EPSG database. Any EPSG plugin should fit. However, this test live in the * {@code plugin/epsg-hsql} module since the HSQL plugin is the only one which * is garantee to work on any machine running Maven. * * * * @source $URL$ * @version $Id$ * @author Martin Desruisseaux (IRD) * @author Jody Garnett */ public class OrderedAxisAuthorityFactoryTest extends TestCase { /** * {@code true} if metadata (especially identifiers) should be erased, or {@code false} if * they should be kepts. The {@code true} value matches the pre GEOT-854 state, while the * {@code false} value mathes the post GEOT-854 state. * * @see http://jira.codehaus.org/browse/GEOT-854 */ private static final boolean METADATA_ERASED = false; /** * Small number for floating points comparaisons. */ private static final double EPS = 1E-8; /** * Run the suite from the command line. If {@code "-log"} flag is specified on the * command-line, then the logger will be set to {@link Level#CONFIG}. This is usefull * for tracking down which data source is actually used. */ public static void main(final String[] args) { final Arguments arguments = new Arguments(args); final boolean log = arguments.getFlag("-log"); arguments.getRemainingArguments(0); org.geotools.util.logging.Logging.GEOTOOLS.forceMonolineConsoleOutput(log ? Level.CONFIG : null); junit.textui.TestRunner.run(suite()); } /** * Returns the test suite. */ public static Test suite() { return new TestSuite(OrderedAxisAuthorityFactoryTest.class); } /** * Constructs a test case with the given name. */ public OrderedAxisAuthorityFactoryTest(final String name) { super(name); } @Override protected void setUp() throws Exception { super.setUp(); // this test does not work if there is more than one EPSG factory around Set factories = ReferencingFactoryFinder.getCRSAuthorityFactories(null); for (CRSAuthorityFactory factory : factories) { if(factory instanceof CartesianAuthorityFactory) { ReferencingFactoryFinder.removeAuthorityFactory(factory); } } } /** * Returns the ordered axis factory for the specified set of hints. */ private static OrderedAxisAuthorityFactory getFactory(final Hints hints) { CRSAuthorityFactory factory; factory = ReferencingFactoryFinder.getCRSAuthorityFactory("EPSG", hints); assertTrue(factory.getClass().toString(), factory instanceof LongitudeFirstFactory); final LongitudeFirstFactory asLongitudeFirst = (LongitudeFirstFactory) factory; final Map implementationHints = asLongitudeFirst.getImplementationHints(); factory = (CRSAuthorityFactory) implementationHints.get(Hints.CRS_AUTHORITY_FACTORY); assertTrue(factory.getClass().toString(), factory instanceof OrderedAxisAuthorityFactory); final OrderedAxisAuthorityFactory asOrdered = (OrderedAxisAuthorityFactory) factory; assertFalse(asOrdered.isCodeMethodOverriden()); return asOrdered; } /** * Returns a positive number if the specified coordinate system is right-handed, * or a negative number if it is left handed. */ private static double getAngle(final CoordinateReferenceSystem crs) { final CoordinateSystem cs = crs.getCoordinateSystem(); assertEquals(2, cs.getDimension()); return DefaultCoordinateSystemAxis.getAngle(cs.getAxis(0).getDirection(), cs.getAxis(1).getDirection()); } /** * Tests the registration of the various flavor of {@link OrderedAxisAuthorityFactoryTest} * for the EPSG authority factory. */ public void testRegistration() { final Hints hints = new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE); OrderedAxisAuthorityFactory factory; factory = getFactory(hints); assertFalse(factory.forceStandardDirections); assertFalse(factory.forceStandardUnits); hints.put(Hints.FORCE_STANDARD_AXIS_DIRECTIONS, Boolean.FALSE); assertSame(factory, getFactory(hints)); assertFalse(factory.forceStandardDirections); assertFalse(factory.forceStandardUnits); hints.put(Hints.FORCE_STANDARD_AXIS_UNITS, Boolean.FALSE); assertSame(factory, getFactory(hints)); assertFalse(factory.forceStandardDirections); assertFalse(factory.forceStandardUnits); hints.put(Hints.FORCE_STANDARD_AXIS_UNITS, Boolean.TRUE); assertNotSame(factory, factory = getFactory(hints)); assertFalse (factory.forceStandardDirections); assertTrue (factory.forceStandardUnits); hints.put(Hints.FORCE_STANDARD_AXIS_DIRECTIONS, Boolean.TRUE); assertNotSame(factory, factory = getFactory(hints)); assertTrue (factory.forceStandardDirections); assertTrue (factory.forceStandardUnits); hints.put(Hints.FORCE_STANDARD_AXIS_UNITS, Boolean.FALSE); assertNotSame(factory, factory = getFactory(hints)); assertTrue (factory.forceStandardDirections); assertFalse (factory.forceStandardUnits); } /** * Tests the axis reordering. */ public void testAxisReordering() throws FactoryException { /* * Tests the OrderedAxisAuthorityFactory creating using FactoryFinder. The following * conditions are not tested directly, but are required in order to get the test to * succeed: * * - EPSG factories must be provided for both "official" and "modified" axis order. * - The "official" axis order must have precedence over the modified one. * - The hints are correctly understood by FactoryFinder. */ final AbstractAuthorityFactory factory0, factory1; final Hints hints = new Hints(Hints.CRS_AUTHORITY_FACTORY, AbstractAuthorityFactory.class); factory0 = (AbstractAuthorityFactory) ReferencingFactoryFinder.getCRSAuthorityFactory("EPSG", hints); assertFalse(factory0 instanceof OrderedAxisAuthorityFactory); assertFalse(factory0 instanceof LongitudeFirstFactory); hints.put(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE); hints.put(Hints.FORCE_STANDARD_AXIS_DIRECTIONS, Boolean.TRUE); hints.put(Hints.FORCE_STANDARD_AXIS_UNITS, Boolean.TRUE); factory1 = (AbstractAuthorityFactory) ReferencingFactoryFinder.getCRSAuthorityFactory("EPSG", hints); assertTrue(factory1 instanceof LongitudeFirstFactory); /* * The local variables to be used for all remaining tests * (usefull to setup in the debugger). */ String code; CoordinateReferenceSystem crs0, crs1; CoordinateOperationFactory opFactory = ReferencingFactoryFinder.getCoordinateOperationFactory(null); MathTransform mt; Matrix matrix; /* * Tests a WGS84 geographic CRS (2D) with (NORTH, EAST) axis directions. * The factory should reorder the axis with no more operation than an axis swap. */ code = "4326"; crs0 = factory0.createCoordinateReferenceSystem(code); crs1 = factory1.createCoordinateReferenceSystem(code); final CoordinateReferenceSystem cacheTest = crs1; assertNotSame(crs0, crs1); assertNotSame(crs0.getCoordinateSystem(), crs1.getCoordinateSystem()); assertSame(((SingleCRS) crs0).getDatum(), ((SingleCRS) crs1).getDatum()); assertEquals("Expected a left-handed CS.", -90, getAngle(crs0), EPS); assertEquals("Expected a right-handed CS.", +90, getAngle(crs1), EPS); assertFalse(crs0.getIdentifiers().isEmpty()); if (METADATA_ERASED) { assertTrue(crs1.getIdentifiers().isEmpty()); } else { assertEquals(crs0.getIdentifiers(), crs1.getIdentifiers()); } mt = opFactory.createOperation(crs0, crs1).getMathTransform(); assertFalse(mt.isIdentity()); assertTrue(mt instanceof LinearTransform); matrix = ((LinearTransform) mt).getMatrix(); assertEquals(new GeneralMatrix(new double[][] { {0, 1, 0}, {1, 0, 0}, {0, 0, 1}}), new GeneralMatrix(matrix)); /* * Tests a WGS84 geographic CRS (3D) with (NORTH, EAST, UP) axis directions. * Because this CRS uses sexagesimal units, conversions are not supported and * will not be tested. */ code = "4329"; crs0 = factory0.createCoordinateReferenceSystem(code); crs1 = factory1.createCoordinateReferenceSystem(code); assertNotSame(crs0, crs1); assertNotSame(crs0.getCoordinateSystem(), crs1.getCoordinateSystem()); assertSame(((SingleCRS) crs0).getDatum(), ((SingleCRS) crs1).getDatum()); assertFalse(crs0.getIdentifiers().isEmpty()); if (METADATA_ERASED) { assertTrue(crs1.getIdentifiers().isEmpty()); } else { assertEquals(crs0.getIdentifiers(), crs1.getIdentifiers()); } /* * Tests a WGS84 geographic CRS (3D) with (NORTH, EAST, UP) axis directions. * The factory should reorder the axis with no more operation than an axis swap. */ code = "63266413"; crs0 = factory0.createCoordinateReferenceSystem(code); crs1 = factory1.createCoordinateReferenceSystem(code); assertNotSame(crs0, crs1); assertNotSame(crs0.getCoordinateSystem(), crs1.getCoordinateSystem()); assertSame(((SingleCRS) crs0).getDatum(), ((SingleCRS) crs1).getDatum()); assertFalse(crs0.getIdentifiers().isEmpty()); if (METADATA_ERASED) { assertTrue(crs1.getIdentifiers().isEmpty()); } else { assertEquals(crs0.getIdentifiers(), crs1.getIdentifiers()); } mt = opFactory.createOperation(crs0, crs1).getMathTransform(); assertFalse(mt.isIdentity()); assertTrue(mt instanceof LinearTransform); matrix = ((LinearTransform) mt).getMatrix(); assertEquals(new GeneralMatrix(new double[][] { {0, 1, 0, 0}, {1, 0, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}), new GeneralMatrix(matrix)); /* * Tests a projected CRS with (EAST, NORTH) axis orientation. No axis reordering is needed, * which means that their coordinate systems are identical and the math transform should be * the identity one. Note that while no axis swap is needed, the base GeographicCRS are not * the same since an axis reordering has been done there. */ code = "2027"; crs0 = factory0.createCoordinateReferenceSystem(code); crs1 = factory1.createCoordinateReferenceSystem(code); assertNotSame(crs0, crs1); assertSame(crs0.getCoordinateSystem(), crs1.getCoordinateSystem()); assertSame(((SingleCRS) crs0).getDatum(), ((SingleCRS) crs1).getDatum()); assertNotSame(((ProjectedCRS) crs0).getBaseCRS(), ((ProjectedCRS) crs1).getBaseCRS()); assertFalse(crs0.getIdentifiers().isEmpty()); if (METADATA_ERASED) { assertTrue(crs1.getIdentifiers().isEmpty()); } else { assertEquals(crs0.getIdentifiers(), crs1.getIdentifiers()); } mt = opFactory.createOperation(crs0, crs1).getMathTransform(); assertTrue(mt.isIdentity()); /* * Tests a projected CRS with (WEST, SOUTH) axis orientation. * The factory should arrange the axis with no more operation than a direction change. * While the end result is a matrix like the GeographicCRS case, the path that lead to * this result is much more complex. */ code = "22275"; crs0 = factory0.createCoordinateReferenceSystem(code); crs1 = factory1.createCoordinateReferenceSystem(code); assertNotSame(crs0, crs1); assertNotSame(crs0.getCoordinateSystem(), crs1.getCoordinateSystem()); assertSame(((SingleCRS) crs0).getDatum(), ((SingleCRS) crs1).getDatum()); assertFalse(crs0.getIdentifiers().isEmpty()); if (METADATA_ERASED) { assertTrue(crs1.getIdentifiers().isEmpty()); } else { assertEquals(crs0.getIdentifiers(), crs1.getIdentifiers()); } mt = opFactory.createOperation(crs0, crs1).getMathTransform(); assertFalse(mt.isIdentity()); assertTrue(mt instanceof LinearTransform); matrix = ((LinearTransform) mt).getMatrix(); assertEquals(new GeneralMatrix(new double[][] { {-1, 0, 0}, { 0, -1, 0}, { 0, 0, 1}}), new GeneralMatrix(matrix)); /* * Tests the cache. */ assertSame(cacheTest, factory1.createCoordinateReferenceSystem("4326")); } /** * Tests the creation of EPSG:4326 CRS with different axis order. */ public void testLongitudeFirst() throws FactoryException { final CoordinateReferenceSystem standard = CRS.decode("EPSG:4326", false); final CoordinateReferenceSystem modified = CRS.decode("EPSG:4326", true ); assertEquals("Expected a left-handed CS.", -90, getAngle(standard), EPS); assertEquals("Expected a right-handed CS.", +90, getAngle(modified), EPS); final MathTransform transform = CRS.findMathTransform(standard, modified); assertTrue(transform instanceof LinearTransform); final Matrix matrix = ((LinearTransform) transform).getMatrix(); assertEquals(new GeneralMatrix(new double[][] { { 0, 1, 0}, { 1, 0, 0}, { 0, 0, 1}}), new GeneralMatrix(matrix)); } /** * Tests the {@link IdentifiedObjectFinder#find} method with axis order forced. */ public void testFind() throws FactoryException { final CRSAuthorityFactory factory = ReferencingFactoryFinder.getCRSAuthorityFactory( "EPSG", new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE)); assertTrue(factory instanceof AbstractAuthorityFactory); AbstractAuthorityFactory findable = (AbstractAuthorityFactory) factory; final IdentifiedObjectFinder finder = findable.getIdentifiedObjectFinder(CoordinateReferenceSystem.class); /* * We tested in DefaultFactoryTest that WGS84 is not found when searching * directly in DefaultFactory. Now we perform the same search through the * ordered axis authority factory. */ finder.setFullScanAllowed(false); assertNull("Should not find the CRS without a scan.", finder.find(DefaultGeographicCRS.WGS84)); finder.setFullScanAllowed(true); IdentifiedObject find = finder.find(DefaultGeographicCRS.WGS84); assertNotNull("With scan allowed, should find the CRS.", find); assertTrue(CRS.equalsIgnoreMetadata(DefaultGeographicCRS.WGS84, find)); assertEquals("Expected a right-handed CS.", +90, getAngle((CoordinateReferenceSystem) find), EPS); /* * Search a CRS using (latitude,longitude) axis order. The IdentifiedObjectFinder * should be able to find it even if it is backed by LongitudeFirstAuthorityFactory, * because the later is itself backed by EPSG factory and IdentifiedObjectFinder * should queries CRS from both. */ final String wkt = "GEOGCS[\"WGS 84\",\n" + " DATUM[\"WGS84\",\n" + " SPHEROID[\"WGS 84\", 6378137.0, 298.257223563]],\n" + " PRIMEM[\"Greenwich\", 0.0],\n" + " UNIT[\"degree\", 0.017453292519943295],\n" + " AXIS[\"Geodetic latitude\", NORTH],\n" + " AXIS[\"Geodetic longitude\", EAST]]"; final CoordinateReferenceSystem search = CRS.parseWKT(wkt); final CoordinateReferenceSystem standard = CRS.decode("EPSG:4326", false); assertTrue(CRS.equalsIgnoreMetadata(search, standard)); assertFalse("Identifiers should not be the same.", search.equals(standard)); finder.setFullScanAllowed(false); assertNull("Should not find the CRS without a scan.", finder.find(search)); finder.setFullScanAllowed(true); find = finder.find(search); final CoordinateReferenceSystem crs = (CoordinateReferenceSystem) find; assertNotNull("Should find the CRS despite the different axis order.", find); assertEquals("Expected a left-handed CS.", -90, getAngle(crs), EPS); assertFalse(CRS.equalsIgnoreMetadata(find, DefaultGeographicCRS.WGS84)); assertTrue (CRS.equalsIgnoreMetadata(find, search)); assertTrue (CRS.equalsIgnoreMetadata(find, standard)); assertSame("Expected caching to work.", standard, find); } }