001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2005-2006, GeoTools Project Managment Committee (PMC)
005: * (C) 2005, Institut de Recherche pour le Développement
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation;
010: * version 2.1 of the License.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: */
017: package org.geotools.referencing.factory;
018:
019: // J2SE dependencies
020: import java.util.Map;
021: import java.util.logging.Level;
022:
023: // JUnit dependencies
024: import junit.framework.Test;
025: import junit.framework.TestCase;
026: import junit.framework.TestSuite;
027:
028: // OpenGIS dependencies
029: import org.opengis.referencing.IdentifiedObject;
030: import org.opengis.referencing.FactoryException;
031: import org.opengis.referencing.crs.SingleCRS;
032: import org.opengis.referencing.crs.ProjectedCRS;
033: import org.opengis.referencing.crs.CRSAuthorityFactory;
034: import org.opengis.referencing.crs.CoordinateReferenceSystem;
035: import org.opengis.referencing.cs.CoordinateSystem;
036: import org.opengis.referencing.operation.CoordinateOperationFactory;
037: import org.opengis.referencing.operation.MathTransform;
038: import org.opengis.referencing.operation.Matrix;
039:
040: // Geotools dependencies
041: import org.geotools.factory.Hints;
042: import org.geotools.resources.Arguments;
043: import org.geotools.referencing.CRS;
044: import org.geotools.referencing.ReferencingFactoryFinder;
045: import org.geotools.referencing.crs.DefaultGeographicCRS;
046: import org.geotools.referencing.operation.LinearTransform;
047: import org.geotools.referencing.operation.matrix.GeneralMatrix;
048: import org.geotools.referencing.cs.DefaultCoordinateSystemAxis;
049: import org.geotools.referencing.factory.epsg.LongitudeFirstFactory;
050:
051: /**
052: * Tests the usage of {@link OrderedAxisAuthorityFactory} with the help of the
053: * EPSG database. Any EPSG plugin should fit. However, this test live in the
054: * {@code plugin/epsg-hsql} module since the HSQL plugin is the only one which
055: * is garantee to work on any machine running Maven.
056: *
057: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/factory/OrderedAxisAuthorityFactoryTest.java $
058: * @version $Id: OrderedAxisAuthorityFactoryTest.java 27848 2007-11-12 13:10:32Z desruisseaux $
059: * @author Martin Desruisseaux
060: * @author Jody Garnett
061: */
062: public class OrderedAxisAuthorityFactoryTest extends TestCase {
063: /**
064: * {@code true} if metadata (especially identifiers) should be erased, or {@code false} if
065: * they should be kepts. The {@code true} value matches the pre GEOT-854 state, while the
066: * {@code false} value mathes the post GEOT-854 state.
067: *
068: * @see http://jira.codehaus.org/browse/GEOT-854
069: */
070: private static final boolean METADATA_ERASED = false;
071:
072: /**
073: * Small number for floating points comparaisons.
074: */
075: private static final double EPS = 1E-8;
076:
077: /**
078: * Run the suite from the command line. If {@code "-log"} flag is specified on the
079: * command-line, then the logger will be set to {@link Level#CONFIG}. This is usefull
080: * for tracking down which data source is actually used.
081: */
082: public static void main(final String[] args) {
083: final Arguments arguments = new Arguments(args);
084: final boolean log = arguments.getFlag("-log");
085: arguments.getRemainingArguments(0);
086: org.geotools.util.logging.Logging.GEOTOOLS
087: .forceMonolineConsoleOutput(log ? Level.CONFIG : null);
088: junit.textui.TestRunner.run(suite());
089: }
090:
091: /**
092: * Returns the test suite.
093: */
094: public static Test suite() {
095: return new TestSuite(OrderedAxisAuthorityFactoryTest.class);
096: }
097:
098: /**
099: * Constructs a test case with the given name.
100: */
101: public OrderedAxisAuthorityFactoryTest(final String name) {
102: super (name);
103: }
104:
105: /**
106: * Returns the ordered axis factory for the specified set of hints.
107: */
108: private static OrderedAxisAuthorityFactory getFactory(
109: final Hints hints) {
110: CRSAuthorityFactory factory;
111: factory = ReferencingFactoryFinder.getCRSAuthorityFactory(
112: "EPSG", hints);
113:
114: assertTrue(factory.getClass().toString(),
115: factory instanceof LongitudeFirstFactory);
116: final LongitudeFirstFactory asLongitudeFirst = (LongitudeFirstFactory) factory;
117: final Map implementationHints = asLongitudeFirst
118: .getImplementationHints();
119: factory = (CRSAuthorityFactory) implementationHints
120: .get(Hints.CRS_AUTHORITY_FACTORY);
121:
122: assertTrue(factory.getClass().toString(),
123: factory instanceof OrderedAxisAuthorityFactory);
124: final OrderedAxisAuthorityFactory asOrdered = (OrderedAxisAuthorityFactory) factory;
125: assertFalse(asOrdered.isCodeMethodOverriden());
126:
127: return asOrdered;
128: }
129:
130: /**
131: * Returns a positive number if the specified coordinate system is right-handed,
132: * or a negative number if it is left handed.
133: */
134: private static double getAngle(final CoordinateReferenceSystem crs) {
135: final CoordinateSystem cs = crs.getCoordinateSystem();
136: assertEquals(2, cs.getDimension());
137: return DefaultCoordinateSystemAxis.getAngle(cs.getAxis(0)
138: .getDirection(), cs.getAxis(1).getDirection());
139: }
140:
141: /**
142: * Tests the registration of the various flavor of {@link OrderedAxisAuthorityFactoryTest}
143: * for the EPSG authority factory.
144: */
145: public void testRegistration() {
146: final Hints hints = new Hints(
147: Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE);
148: OrderedAxisAuthorityFactory factory;
149: factory = getFactory(hints);
150: assertFalse(factory.forceStandardDirections);
151: assertFalse(factory.forceStandardUnits);
152:
153: hints.put(Hints.FORCE_STANDARD_AXIS_DIRECTIONS, Boolean.FALSE);
154: assertSame(factory, getFactory(hints));
155: assertFalse(factory.forceStandardDirections);
156: assertFalse(factory.forceStandardUnits);
157:
158: hints.put(Hints.FORCE_STANDARD_AXIS_UNITS, Boolean.FALSE);
159: assertSame(factory, getFactory(hints));
160: assertFalse(factory.forceStandardDirections);
161: assertFalse(factory.forceStandardUnits);
162:
163: hints.put(Hints.FORCE_STANDARD_AXIS_UNITS, Boolean.TRUE);
164: assertNotSame(factory, factory = getFactory(hints));
165: assertFalse(factory.forceStandardDirections);
166: assertTrue(factory.forceStandardUnits);
167:
168: hints.put(Hints.FORCE_STANDARD_AXIS_DIRECTIONS, Boolean.TRUE);
169: assertNotSame(factory, factory = getFactory(hints));
170: assertTrue(factory.forceStandardDirections);
171: assertTrue(factory.forceStandardUnits);
172:
173: hints.put(Hints.FORCE_STANDARD_AXIS_UNITS, Boolean.FALSE);
174: assertNotSame(factory, factory = getFactory(hints));
175: assertTrue(factory.forceStandardDirections);
176: assertFalse(factory.forceStandardUnits);
177: }
178:
179: /**
180: * Tests the axis reordering.
181: */
182: public void testAxisReordering() throws FactoryException {
183: /*
184: * Tests the OrderedAxisAuthorityFactory creating using FactoryFinder. The following
185: * conditions are not tested directly, but are required in order to get the test to
186: * succeed:
187: *
188: * - EPSG factories must be provided for both "official" and "modified" axis order.
189: * - The "official" axis order must have precedence over the modified one.
190: * - The hints are correctly understood by FactoryFinder.
191: */
192: final AbstractAuthorityFactory factory0, factory1;
193: final Hints hints = new Hints(Hints.CRS_AUTHORITY_FACTORY,
194: AbstractAuthorityFactory.class);
195: factory0 = (AbstractAuthorityFactory) ReferencingFactoryFinder
196: .getCRSAuthorityFactory("EPSG", hints);
197: assertFalse(factory0 instanceof OrderedAxisAuthorityFactory);
198: assertFalse(factory0 instanceof LongitudeFirstFactory);
199: hints.put(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE);
200: hints.put(Hints.FORCE_STANDARD_AXIS_DIRECTIONS, Boolean.TRUE);
201: hints.put(Hints.FORCE_STANDARD_AXIS_UNITS, Boolean.TRUE);
202: factory1 = (AbstractAuthorityFactory) ReferencingFactoryFinder
203: .getCRSAuthorityFactory("EPSG", hints);
204: assertTrue(factory1 instanceof LongitudeFirstFactory);
205: /*
206: * The local variables to be used for all remaining tests
207: * (usefull to setup in the debugger).
208: */
209: String code;
210: CoordinateReferenceSystem crs0, crs1;
211: CoordinateOperationFactory opFactory = ReferencingFactoryFinder
212: .getCoordinateOperationFactory(null);
213: MathTransform mt;
214: Matrix matrix;
215: /*
216: * Tests a WGS84 geographic CRS (2D) with (NORTH, EAST) axis directions.
217: * The factory should reorder the axis with no more operation than an axis swap.
218: */
219: code = "4326";
220: crs0 = factory0.createCoordinateReferenceSystem(code);
221: crs1 = factory1.createCoordinateReferenceSystem(code);
222: final CoordinateReferenceSystem cacheTest = crs1;
223: assertNotSame(crs0, crs1);
224: assertNotSame(crs0.getCoordinateSystem(), crs1
225: .getCoordinateSystem());
226: assertSame(((SingleCRS) crs0).getDatum(), ((SingleCRS) crs1)
227: .getDatum());
228: assertEquals("Expected a left-handed CS.", -90, getAngle(crs0),
229: EPS);
230: assertEquals("Expected a right-handed CS.", +90,
231: getAngle(crs1), EPS);
232: assertFalse(crs0.getIdentifiers().isEmpty());
233: if (METADATA_ERASED) {
234: assertTrue(crs1.getIdentifiers().isEmpty());
235: } else {
236: assertEquals(crs0.getIdentifiers(), crs1.getIdentifiers());
237: }
238: mt = opFactory.createOperation(crs0, crs1).getMathTransform();
239: assertFalse(mt.isIdentity());
240: assertTrue(mt instanceof LinearTransform);
241: matrix = ((LinearTransform) mt).getMatrix();
242: assertEquals(new GeneralMatrix(new double[][] { { 0, 1, 0 },
243: { 1, 0, 0 }, { 0, 0, 1 } }), new GeneralMatrix(matrix));
244: /*
245: * Tests a WGS84 geographic CRS (3D) with (NORTH, EAST, UP) axis directions.
246: * Because this CRS uses sexagesimal units, conversions are not supported and
247: * will not be tested.
248: */
249: code = "4329";
250: crs0 = factory0.createCoordinateReferenceSystem(code);
251: crs1 = factory1.createCoordinateReferenceSystem(code);
252: assertNotSame(crs0, crs1);
253: assertNotSame(crs0.getCoordinateSystem(), crs1
254: .getCoordinateSystem());
255: assertSame(((SingleCRS) crs0).getDatum(), ((SingleCRS) crs1)
256: .getDatum());
257: assertFalse(crs0.getIdentifiers().isEmpty());
258: if (METADATA_ERASED) {
259: assertTrue(crs1.getIdentifiers().isEmpty());
260: } else {
261: assertEquals(crs0.getIdentifiers(), crs1.getIdentifiers());
262: }
263: /*
264: * Tests a WGS84 geographic CRS (3D) with (NORTH, EAST, UP) axis directions.
265: * The factory should reorder the axis with no more operation than an axis swap.
266: */
267: code = "63266413";
268: crs0 = factory0.createCoordinateReferenceSystem(code);
269: crs1 = factory1.createCoordinateReferenceSystem(code);
270: assertNotSame(crs0, crs1);
271: assertNotSame(crs0.getCoordinateSystem(), crs1
272: .getCoordinateSystem());
273: assertSame(((SingleCRS) crs0).getDatum(), ((SingleCRS) crs1)
274: .getDatum());
275: assertFalse(crs0.getIdentifiers().isEmpty());
276: if (METADATA_ERASED) {
277: assertTrue(crs1.getIdentifiers().isEmpty());
278: } else {
279: assertEquals(crs0.getIdentifiers(), crs1.getIdentifiers());
280: }
281: mt = opFactory.createOperation(crs0, crs1).getMathTransform();
282: assertFalse(mt.isIdentity());
283: assertTrue(mt instanceof LinearTransform);
284: matrix = ((LinearTransform) mt).getMatrix();
285: assertEquals(new GeneralMatrix(new double[][] { { 0, 1, 0, 0 },
286: { 1, 0, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }),
287: new GeneralMatrix(matrix));
288: /*
289: * Tests a projected CRS with (EAST, NORTH) axis orientation. No axis reordering is needed,
290: * which means that their coordinate systems are identical and the math transform should be
291: * the identity one. Note that while no axis swap is needed, the base GeographicCRS are not
292: * the same since an axis reordering has been done there.
293: */
294: code = "2027";
295: crs0 = factory0.createCoordinateReferenceSystem(code);
296: crs1 = factory1.createCoordinateReferenceSystem(code);
297: assertNotSame(crs0, crs1);
298: assertSame(crs0.getCoordinateSystem(), crs1
299: .getCoordinateSystem());
300: assertSame(((SingleCRS) crs0).getDatum(), ((SingleCRS) crs1)
301: .getDatum());
302: assertNotSame(((ProjectedCRS) crs0).getBaseCRS(),
303: ((ProjectedCRS) crs1).getBaseCRS());
304: assertFalse(crs0.getIdentifiers().isEmpty());
305: if (METADATA_ERASED) {
306: assertTrue(crs1.getIdentifiers().isEmpty());
307: } else {
308: assertEquals(crs0.getIdentifiers(), crs1.getIdentifiers());
309: }
310: mt = opFactory.createOperation(crs0, crs1).getMathTransform();
311: assertTrue(mt.isIdentity());
312: /*
313: * Tests a projected CRS with (WEST, SOUTH) axis orientation.
314: * The factory should arrange the axis with no more operation than a direction change.
315: * While the end result is a matrix like the GeographicCRS case, the path that lead to
316: * this result is much more complex.
317: */
318: code = "22275";
319: crs0 = factory0.createCoordinateReferenceSystem(code);
320: crs1 = factory1.createCoordinateReferenceSystem(code);
321: assertNotSame(crs0, crs1);
322: assertNotSame(crs0.getCoordinateSystem(), crs1
323: .getCoordinateSystem());
324: assertSame(((SingleCRS) crs0).getDatum(), ((SingleCRS) crs1)
325: .getDatum());
326: assertFalse(crs0.getIdentifiers().isEmpty());
327: if (METADATA_ERASED) {
328: assertTrue(crs1.getIdentifiers().isEmpty());
329: } else {
330: assertEquals(crs0.getIdentifiers(), crs1.getIdentifiers());
331: }
332: mt = opFactory.createOperation(crs0, crs1).getMathTransform();
333: assertFalse(mt.isIdentity());
334: assertTrue(mt instanceof LinearTransform);
335: matrix = ((LinearTransform) mt).getMatrix();
336: assertEquals(new GeneralMatrix(new double[][] { { -1, 0, 0 },
337: { 0, -1, 0 }, { 0, 0, 1 } }), new GeneralMatrix(matrix));
338: /*
339: * Tests the cache.
340: */
341: assertSame(cacheTest, factory1
342: .createCoordinateReferenceSystem("4326"));
343: }
344:
345: /**
346: * Tests the creation of EPSG:4326 CRS with different axis order.
347: */
348: public void testLongitudeFirst() throws FactoryException {
349: final CoordinateReferenceSystem standard = CRS.decode(
350: "EPSG:4326", false);
351: final CoordinateReferenceSystem modified = CRS.decode(
352: "EPSG:4326", true);
353: assertEquals("Expected a left-handed CS.", -90,
354: getAngle(standard), EPS);
355: assertEquals("Expected a right-handed CS.", +90,
356: getAngle(modified), EPS);
357: final MathTransform transform = CRS.findMathTransform(standard,
358: modified);
359: assertTrue(transform instanceof LinearTransform);
360: final Matrix matrix = ((LinearTransform) transform).getMatrix();
361: assertEquals(new GeneralMatrix(new double[][] { { 0, 1, 0 },
362: { 1, 0, 0 }, { 0, 0, 1 } }), new GeneralMatrix(matrix));
363: }
364:
365: /**
366: * Tests the {@link IdentifiedObjectFinder#find} method with axis order forced.
367: */
368: public void testFind() throws FactoryException {
369: final CRSAuthorityFactory factory = ReferencingFactoryFinder
370: .getCRSAuthorityFactory("EPSG", new Hints(
371: Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER,
372: Boolean.TRUE));
373: assertTrue(factory instanceof AbstractAuthorityFactory);
374: final IdentifiedObjectFinder finder = ((AbstractAuthorityFactory) factory)
375: .getIdentifiedObjectFinder(CoordinateReferenceSystem.class);
376: /*
377: * We tested in DefaultFactoryTest that WGS84 is not found when searching
378: * directly in DefaultFactory. Now we perform the same search through the
379: * ordered axis authority factory.
380: */
381: finder.setFullScanAllowed(false);
382: assertNull("Should not find the CRS without a scan.", finder
383: .find(DefaultGeographicCRS.WGS84));
384:
385: finder.setFullScanAllowed(true);
386: IdentifiedObject find = finder.find(DefaultGeographicCRS.WGS84);
387: assertNotNull("With scan allowed, should find the CRS.", find);
388: assertTrue(CRS.equalsIgnoreMetadata(DefaultGeographicCRS.WGS84,
389: find));
390: assertEquals("Expected a right-handed CS.", +90,
391: getAngle((CoordinateReferenceSystem) find), EPS);
392: /*
393: * Search a CRS using (latitude,longitude) axis order. The IdentifiedObjectFinder
394: * should be able to find it even if it is backed by LongitudeFirstAuthorityFactory,
395: * because the later is itself backed by EPSG factory and IdentifiedObjectFinder
396: * should queries CRS from both.
397: */
398: final String wkt = "GEOGCS[\"WGS 84\",\n"
399: + " DATUM[\"WGS84\",\n"
400: + " SPHEROID[\"WGS 84\", 6378137.0, 298.257223563]],\n"
401: + " PRIMEM[\"Greenwich\", 0.0],\n"
402: + " UNIT[\"degree\", 0.017453292519943295],\n"
403: + " AXIS[\"Geodetic latitude\", NORTH],\n"
404: + " AXIS[\"Geodetic longitude\", EAST]]";
405: final CoordinateReferenceSystem search = CRS.parseWKT(wkt);
406: final CoordinateReferenceSystem standard = CRS.decode(
407: "EPSG:4326", false);
408: assertTrue(CRS.equalsIgnoreMetadata(search, standard));
409: assertFalse("Identifiers should not be the same.", search
410: .equals(standard));
411: finder.setFullScanAllowed(false);
412: assertNull("Should not find the CRS without a scan.", finder
413: .find(search));
414:
415: finder.setFullScanAllowed(true);
416: find = finder.find(search);
417: final CoordinateReferenceSystem crs = (CoordinateReferenceSystem) search;
418: assertNotNull(
419: "Should find the CRS despite the different axis order.",
420: find);
421: assertEquals("Expected a left-handed CS.", -90, getAngle(crs),
422: EPS);
423: assertFalse(CRS.equalsIgnoreMetadata(find,
424: DefaultGeographicCRS.WGS84));
425: assertTrue(CRS.equalsIgnoreMetadata(find, search));
426: assertTrue(CRS.equalsIgnoreMetadata(find, standard));
427: assertSame("Expected caching to work.", standard, find);
428: }
429: }
|