001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2003-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.referencing.factory.epsg;
017:
018: // J2SE dependencies and extensions
019: import java.io.*;
020: import java.util.*;
021: import java.util.logging.Level;
022: import java.sql.SQLException;
023: import java.awt.geom.AffineTransform;
024: import javax.units.Unit;
025:
026: // JUnit dependencies
027: import junit.framework.Test;
028: import junit.framework.TestCase;
029: import junit.framework.TestSuite;
030:
031: // OpenGIS dependencies
032: import org.opengis.referencing.*;
033: import org.opengis.referencing.cs.*;
034: import org.opengis.referencing.crs.*;
035: import org.opengis.referencing.datum.*;
036: import org.opengis.referencing.operation.*;
037: import org.opengis.metadata.Identifier;
038: import org.opengis.metadata.extent.GeographicBoundingBox;
039: import org.opengis.parameter.ParameterValueGroup;
040: import org.opengis.geometry.Envelope;
041:
042: // Geotools dependencies
043: import org.geotools.TestData;
044: import org.geotools.factory.Hints;
045: import org.geotools.referencing.CRS;
046: import org.geotools.referencing.ReferencingFactoryFinder;
047: import org.geotools.referencing.AbstractIdentifiedObject;
048: import org.geotools.referencing.crs.DefaultGeographicCRS;
049: import org.geotools.referencing.datum.DefaultGeodeticDatum;
050: import org.geotools.referencing.operation.AbstractCoordinateOperation;
051: import org.geotools.referencing.operation.transform.AbstractMathTransform;
052: import org.geotools.referencing.operation.transform.ConcatenatedTransform;
053: import org.geotools.referencing.factory.IdentifiedObjectFinder;
054: import org.geotools.referencing.factory.AbstractAuthorityFactory;
055: import org.geotools.metadata.iso.extent.GeographicBoundingBoxImpl;
056: import org.geotools.resources.Arguments;
057:
058: /**
059: * Tests transformations from CRS and/or operations created from the EPSG factory, using
060: * the default plugin. If the MS-Access database is installed and the {@code epsg-access}
061: * plugin is in the classpath, then the default plugin will be the factory backed by the
062: * MS-Access database. Otherwise, the default will probably be the one backed by the HSQL
063: * database, since this test live in the {@code epsg-hsql} module.
064: *
065: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/factory/epsg/DefaultFactoryTest.java $
066: * @version $Id: DefaultFactoryTest.java 27848 2007-11-12 13:10:32Z desruisseaux $
067: * @author Martin Desruisseaux
068: * @author Vadim Semenov
069: */
070: public class DefaultFactoryTest extends TestCase {
071: /**
072: * Set to {@code true} for verbose tests.
073: */
074: private static boolean verbose = false;
075:
076: /**
077: * Set to {@code true} for more extensive tests.
078: */
079: private static boolean extensive = false;
080:
081: /**
082: * Small value for parameter value comparaisons.
083: */
084: private static final double EPS = 1E-6;
085:
086: /**
087: * The EPSG factory to test. Will be setup only when first needed.
088: */
089: private DefaultFactory factory;
090:
091: /**
092: * Run the suite from the command line. Optional command-line arguments:
093: * <ul>
094: * <li>{@code -log}: set the logger lever to {@link Level#CONFIG}.
095: * This is usefull for tracking down which data source is actually used.</li>
096: * <li>{@code -verbose}: Prints some messages to the standard output stream.</li>
097: * </ul>
098: */
099: public static void main(final String[] args) {
100: final Arguments arguments = new Arguments(args);
101: final boolean log = arguments.getFlag("-log");
102: verbose = arguments.getFlag("-verbose");
103: extensive = true;
104: arguments.getRemainingArguments(0);
105: org.geotools.util.logging.Logging.GEOTOOLS
106: .forceMonolineConsoleOutput(log ? Level.CONFIG : null);
107: junit.textui.TestRunner.run(suite());
108: }
109:
110: /**
111: * Returns the test suite.
112: */
113: public static Test suite() {
114: return new TestSuite(DefaultFactoryTest.class);
115: }
116:
117: /**
118: * Constructs a test case with the given name.
119: */
120: public DefaultFactoryTest(final String name) {
121: super (name);
122: }
123:
124: /**
125: * Sets up the authority factory.
126: */
127: protected void setUp() throws SQLException {
128: if (factory == null) {
129: factory = (DefaultFactory) ReferencingFactoryFinder
130: .getCRSAuthorityFactory("EPSG", new Hints(
131: Hints.CRS_AUTHORITY_FACTORY,
132: DefaultFactory.class));
133: extensive |= TestData.isExtensiveTest();
134: if (verbose) {
135: System.out.print("Database version: ");
136: System.out.println(factory.getImplementationHints()
137: .get(Hints.VERSION));
138: }
139: }
140: // No 'tearDown()' method: we rely on the DefaultFactory shutdown hook.
141: }
142:
143: /**
144: * Make sure that the factory extracted from the registry in the {@link #setUp} method
145: * is a singleton. It may not be the case when there is a bug in {@code FactoryRegistry}.
146: */
147: public void testRegistry() {
148: final Object candidate = ReferencingFactoryFinder
149: .getCRSAuthorityFactory("EPSG", null);
150: if (candidate instanceof DefaultFactory) {
151: assertSame(factory, candidate);
152: }
153: }
154:
155: /**
156: * Returns the first identifier for the specified object.
157: */
158: private static String getIdentifier(final IdentifiedObject object) {
159: return ((Identifier) object.getIdentifiers().iterator().next())
160: .getCode();
161: }
162:
163: /**
164: * Tests creations of CRS objects.
165: */
166: public void testCreation() throws FactoryException {
167: final CoordinateOperationFactory opf = ReferencingFactoryFinder
168: .getCoordinateOperationFactory(null);
169: CoordinateReferenceSystem sourceCRS, targetCRS;
170: CoordinateOperation operation;
171: ParameterValueGroup parameters;
172:
173: sourceCRS = factory.createCoordinateReferenceSystem("4274");
174: assertEquals("4274", getIdentifier(sourceCRS));
175: assertTrue(sourceCRS instanceof GeographicCRS);
176: assertEquals(2, sourceCRS.getCoordinateSystem().getDimension());
177:
178: sourceCRS = factory
179: .createCoordinateReferenceSystem("EPSG:4140");
180: assertEquals("4140", getIdentifier(sourceCRS));
181: assertTrue(sourceCRS instanceof GeographicCRS);
182: assertEquals(2, sourceCRS.getCoordinateSystem().getDimension());
183:
184: sourceCRS = factory.createCoordinateReferenceSystem("2027");
185: assertEquals("2027", getIdentifier(sourceCRS));
186: assertTrue(sourceCRS instanceof ProjectedCRS);
187: assertEquals(2, sourceCRS.getCoordinateSystem().getDimension());
188: parameters = ((ProjectedCRS) sourceCRS).getConversionFromBase()
189: .getParameterValues();
190: assertEquals(-93, parameters.parameter("central_meridian")
191: .doubleValue(), EPS);
192: assertEquals(0, parameters.parameter("latitude_of_origin")
193: .doubleValue(), EPS);
194: assertEquals(0.9996, parameters.parameter("scale_factor")
195: .doubleValue(), EPS);
196: assertEquals(500000, parameters.parameter("false_easting")
197: .doubleValue(), EPS);
198: assertEquals(0, parameters.parameter("false_northing")
199: .doubleValue(), EPS);
200:
201: sourceCRS = factory
202: .createCoordinateReferenceSystem(" EPSG : 2442 ");
203: assertEquals("2442", getIdentifier(sourceCRS));
204: assertTrue(sourceCRS instanceof ProjectedCRS);
205: assertEquals(2, sourceCRS.getCoordinateSystem().getDimension());
206: parameters = ((ProjectedCRS) sourceCRS).getConversionFromBase()
207: .getParameterValues();
208: assertEquals(135, parameters.parameter("central_meridian")
209: .doubleValue(), EPS);
210: assertEquals(0, parameters.parameter("latitude_of_origin")
211: .doubleValue(), EPS);
212: assertEquals(1, parameters.parameter("scale_factor")
213: .doubleValue(), EPS);
214: assertEquals(500000, parameters.parameter("false_easting")
215: .doubleValue(), EPS);
216: assertEquals(0, parameters.parameter("false_northing")
217: .doubleValue(), EPS);
218:
219: sourceCRS = factory
220: .createCoordinateReferenceSystem("EPSG:4915");
221: assertEquals("4915", getIdentifier(sourceCRS));
222: assertTrue(sourceCRS instanceof GeocentricCRS);
223: assertEquals(3, sourceCRS.getCoordinateSystem().getDimension());
224:
225: sourceCRS = factory
226: .createCoordinateReferenceSystem("EPSG:4993");
227: assertEquals("4993", getIdentifier(sourceCRS));
228: assertTrue(sourceCRS instanceof GeographicCRS);
229: assertEquals(3, sourceCRS.getCoordinateSystem().getDimension());
230:
231: sourceCRS = factory
232: .createCoordinateReferenceSystem("EPSG:5735");
233: assertEquals("5735", getIdentifier(sourceCRS));
234: assertTrue(sourceCRS instanceof VerticalCRS);
235: assertEquals(1, sourceCRS.getCoordinateSystem().getDimension());
236:
237: sourceCRS = factory
238: .createCoordinateReferenceSystem("EPSG:5801");
239: assertEquals("5801", getIdentifier(sourceCRS));
240: assertTrue(sourceCRS instanceof EngineeringCRS);
241: assertEquals(2, sourceCRS.getCoordinateSystem().getDimension());
242:
243: sourceCRS = factory
244: .createCoordinateReferenceSystem("EPSG:7400");
245: assertEquals("7400", getIdentifier(sourceCRS));
246: assertTrue(sourceCRS instanceof CompoundCRS);
247: assertEquals(3, sourceCRS.getCoordinateSystem().getDimension());
248:
249: // GeographicCRS without datum
250: sourceCRS = factory.createCoordinateReferenceSystem("63266405");
251: assertTrue(sourceCRS instanceof GeographicCRS);
252: assertEquals("WGS 84 (deg)", sourceCRS.getName().getCode());
253: assertEquals(2, sourceCRS.getCoordinateSystem().getDimension());
254:
255: // Operations
256: sourceCRS = factory.createCoordinateReferenceSystem("4273");
257: targetCRS = factory.createCoordinateReferenceSystem("4979");
258: operation = opf.createOperation(sourceCRS, targetCRS);
259: assertNotSame(sourceCRS, targetCRS);
260: assertFalse(operation.getMathTransform().isIdentity());
261:
262: assertSame(sourceCRS, factory
263: .createCoordinateReferenceSystem("EPSG:4273"));
264: assertSame(targetCRS, factory
265: .createCoordinateReferenceSystem("EPSG:4979"));
266:
267: assertSame(sourceCRS, factory
268: .createCoordinateReferenceSystem(" EPSG : 4273 "));
269: assertSame(targetCRS, factory
270: .createCoordinateReferenceSystem(" EPSG : 4979 "));
271:
272: // CRS with "South along 180 deg" and "South along 90 deg East" axis
273: sourceCRS = factory
274: .createCoordinateReferenceSystem("EPSG:32661");
275: targetCRS = factory.createCoordinateReferenceSystem("4326");
276: operation = opf.createOperation(sourceCRS, targetCRS);
277: final MathTransform transform = operation.getMathTransform();
278: final CoordinateSystem sourceCS = sourceCRS
279: .getCoordinateSystem();
280: final CoordinateSystemAxis axis0 = sourceCS.getAxis(0);
281: final CoordinateSystemAxis axis1 = sourceCS.getAxis(1);
282: assertEquals("Northing", axis0.getName().getCode());
283: assertEquals("Easting", axis1.getName().getCode());
284: assertEquals("South along 180 deg", axis0.getDirection().name());
285: assertEquals("South along 90 deg East", axis1.getDirection()
286: .name());
287: assertFalse(transform.isIdentity());
288: assertTrue(transform instanceof ConcatenatedTransform);
289: ConcatenatedTransform ct = (ConcatenatedTransform) transform;
290: // An affine transform for swapping axis should be
291: // performed before and after the map projection.
292: final int mask = AffineTransform.TYPE_FLIP
293: | AffineTransform.TYPE_QUADRANT_ROTATION
294: | AffineTransform.TYPE_UNIFORM_SCALE;
295: assertTrue(ct.transform1 instanceof AffineTransform);
296: assertEquals(mask, ((AffineTransform) ct.transform1).getType());
297: assertTrue(ct.transform2 instanceof ConcatenatedTransform);
298: ct = (ConcatenatedTransform) ct.transform2;
299: assertTrue(ct.transform1 instanceof AbstractMathTransform);
300: assertTrue(ct.transform2 instanceof AffineTransform);
301: assertEquals(mask, ((AffineTransform) ct.transform2).getType());
302: }
303:
304: /**
305: * Tests closing the factory after the timeout. <strong>IMPORTANT:</strong> This test must
306: * be run after {@link #testCreation} and before any call to {@code getAuthorityCodes()}.
307: */
308: public void testTimeout() throws FactoryException {
309: System.gc(); // If there is any object holding a connection to the EPSG
310: System.runFinalization(); // database, running finalizers may help to close them.
311: factory.setTimeout(200);
312: // Fetch this CRS first in order to prevent garbage collection.
313: CoordinateReferenceSystem crs = factory
314: .createCoordinateReferenceSystem("4273");
315: assertEquals("4273", getIdentifier(crs));
316: try {
317: assertTrue(factory.isConnected());
318: Thread.currentThread().sleep(800);
319: System.gc();
320: System.runFinalization();
321: assertFalse(factory.isConnected());
322: } catch (InterruptedException e) {
323: fail(e.getLocalizedMessage());
324: }
325: assertFalse(factory.isConnected());
326: // Should be in the cache.
327: assertSame(crs, factory.createCoordinateReferenceSystem("4273"));
328: assertFalse(factory.isConnected());
329: // Was not in the cache
330: assertEquals("4275", getIdentifier(factory
331: .createCoordinateReferenceSystem("4275")));
332: assertTrue(factory.isConnected());
333: factory.setTimeout(30 * 60 * 1000L);
334: }
335:
336: /**
337: * Tests the creation of CRS using name instead of primary keys. Note that this test
338: * contains a call to {@code getDescriptionText(...)}, and concequently must be run
339: * after {@link #testTimeout}. See {@link #testDescriptionText}.
340: */
341: public void testNameUsage() throws FactoryException {
342: /*
343: * Tests unit
344: */
345: assertSame(factory.createUnit("9002"), factory
346: .createUnit("foot"));
347: assertNotSame(factory.createUnit("9001"), factory
348: .createUnit("foot"));
349: /*
350: * Tests CRS
351: */
352: final CoordinateReferenceSystem primary, byName;
353: primary = factory.createCoordinateReferenceSystem("27581");
354: assertEquals("27581", getIdentifier(primary));
355: assertTrue(primary instanceof ProjectedCRS);
356: assertEquals(2, primary.getCoordinateSystem().getDimension());
357: /*
358: * Gets the CRS by name. It should be the same.
359: */
360: byName = factory
361: .createCoordinateReferenceSystem("NTF (Paris) / France I");
362: assertEquals(primary, byName);
363: /*
364: * Gets the CRS using 'createObject'. It will requires ony more
365: * SQL statement internally in order to determines the object type.
366: */
367: factory.dispose(); // Clear the cache. This is not a real disposal.
368: assertEquals(primary, factory.createObject("27581"));
369: assertEquals(byName, factory
370: .createObject("NTF (Paris) / France I"));
371: /*
372: * Tests descriptions.
373: */
374: assertEquals("NTF (Paris) / France I", factory
375: .getDescriptionText("27581").toString());
376: /*
377: * Tests fetching an object with name containing semi-colon.
378: */
379: final IdentifiedObject cs = factory
380: .createCoordinateSystem("Ellipsoidal 2D CS. Axes: latitude, longitude. Orientations: north, east. UoM: DMS");
381: assertEquals("6411", getIdentifier(cs));
382: /*
383: * Tests with a unknown name. The exception should be NoSuchAuthorityCodeException
384: * (some previous version wrongly threw a SQLException when using HSQL database).
385: */
386: try {
387: factory.createGeographicCRS("WGS84");
388: fail();
389: } catch (NoSuchAuthorityCodeException e) {
390: // This is the expected exception.
391: assertEquals("WGS84", e.getAuthorityCode());
392: }
393: }
394:
395: /**
396: * Tests the {@link AuthorityFactory#getDescriptionText} method. Note that the default
397: * implementation of {@code getDescriptionText(...)} invokes {@code getAuthorityCodes()},
398: * and concequently this test must be run after {@link #testTimeout}.
399: */
400: public void testDescriptionText() throws FactoryException {
401: assertEquals("World Geodetic System 1984", factory
402: .getDescriptionText("6326").toString(Locale.ENGLISH));
403: assertEquals("Mean Sea Level", factory.getDescriptionText(
404: "5100").toString(Locale.ENGLISH));
405: assertEquals("NTF (Paris) / Nord France", factory
406: .getDescriptionText("27591").toString(Locale.ENGLISH));
407: assertEquals("Ellipsoidal height", factory.getDescriptionText(
408: "84").toString(Locale.ENGLISH));
409: }
410:
411: /**
412: * Tests the {@code getAuthorityCodes()} method.
413: */
414: public void testAuthorityCodes() throws FactoryException {
415: final Set crs = factory
416: .getAuthorityCodes(CoordinateReferenceSystem.class);
417: assertFalse(crs.isEmpty());
418: assertEquals("Check size() consistency", crs.size(), crs.size());
419: assertTrue(crs.size() > 0); // Must be after the 'assertEquals' above.
420:
421: final Set geographicCRS = factory
422: .getAuthorityCodes(GeographicCRS.class);
423: assertTrue(geographicCRS instanceof AuthorityCodes);
424: assertFalse(geographicCRS.isEmpty());
425: assertTrue(geographicCRS.size() > 0);
426: assertTrue(geographicCRS.size() < crs.size());
427: assertFalse(geographicCRS.containsAll(crs));
428: assertTrue(crs.containsAll(geographicCRS));
429:
430: final Set projectedCRS = factory
431: .getAuthorityCodes(ProjectedCRS.class);
432: assertTrue(projectedCRS instanceof AuthorityCodes);
433: assertFalse(projectedCRS.isEmpty());
434: assertTrue(projectedCRS.size() > 0);
435: assertTrue(projectedCRS.size() < crs.size());
436: assertFalse(projectedCRS.containsAll(crs));
437: assertTrue(crs.containsAll(projectedCRS));
438: // assertTrue(Collections.disjoint(geographicCRS, projectedCRS));
439: // TODO: uncomment when we will be allowed to compile for J2SE 1.5.
440:
441: final Set datum = factory.getAuthorityCodes(Datum.class);
442: assertTrue(datum instanceof AuthorityCodes);
443: assertFalse(datum.isEmpty());
444: assertTrue(datum.size() > 0);
445: // assertTrue(Collections.disjoint(datum, crs));
446: // TODO: uncomment when we will be allowed to compile for J2SE 1.5.
447:
448: final Set geodeticDatum = factory
449: .getAuthorityCodes(GeodeticDatum.class);
450: assertTrue(geodeticDatum instanceof AuthorityCodes);
451: assertFalse(geodeticDatum.isEmpty());
452: assertTrue(geodeticDatum.size() > 0);
453: assertFalse(geodeticDatum.containsAll(datum));
454: assertTrue(datum.containsAll(geodeticDatum));
455:
456: // Ensures that the factory keept the set in its cache.
457: assertSame(crs, factory
458: .getAuthorityCodes(CoordinateReferenceSystem.class));
459: assertSame(geographicCRS, factory
460: .getAuthorityCodes(GeographicCRS.class));
461: assertSame(projectedCRS, factory
462: .getAuthorityCodes(ProjectedCRS.class));
463: assertSame(datum, factory.getAuthorityCodes(Datum.class));
464: assertSame(geodeticDatum, factory
465: .getAuthorityCodes(GeodeticDatum.class));
466: assertSame(geodeticDatum, factory
467: .getAuthorityCodes(DefaultGeodeticDatum.class));
468:
469: // Try a dummy type.
470: assertTrue("Dummy type", factory
471: .getAuthorityCodes(String.class).isEmpty());
472:
473: // Tests projections, which are handle in a special way.
474: final Set operations = factory
475: .getAuthorityCodes(Operation.class);
476: final Set conversions = factory
477: .getAuthorityCodes(Conversion.class);
478: final Set projections = factory
479: .getAuthorityCodes(Projection.class);
480: final Set transformations = factory
481: .getAuthorityCodes(Transformation.class);
482:
483: assertTrue(operations instanceof AuthorityCodes);
484: assertTrue(conversions instanceof AuthorityCodes);
485: assertTrue(projections instanceof AuthorityCodes);
486: assertTrue(transformations instanceof AuthorityCodes);
487:
488: assertTrue(conversions.size() < operations.size());
489: assertTrue(projections.size() < operations.size());
490: assertTrue(transformations.size() < operations.size());
491: assertTrue(projections.size() < conversions.size());
492:
493: assertFalse(projections.containsAll(conversions));
494: assertTrue(conversions.containsAll(projections));
495: assertTrue(operations.containsAll(conversions));
496: assertTrue(operations.containsAll(transformations));
497:
498: // TODO: uncomment when we will be allowed to compile for J2SE 1.5.
499: // assertTrue (Collections.disjoint(conversions, transformations));
500: // assertFalse(Collections.disjoint(conversions, projections));
501:
502: assertFalse(operations.isEmpty());
503: assertFalse(conversions.isEmpty());
504: assertFalse(projections.isEmpty());
505: assertFalse(transformations.isEmpty());
506:
507: assertTrue(conversions.contains("101"));
508: assertFalse(projections.contains("101"));
509: assertTrue(projections.contains("16001"));
510:
511: final Set units = factory.getAuthorityCodes(Unit.class);
512: assertTrue(units instanceof AuthorityCodes);
513: assertFalse(units.isEmpty());
514: assertTrue(units.size() > 0);
515:
516: // Tests the fusion of all types
517: final Set all = factory
518: .getAuthorityCodes(IdentifiedObject.class);
519: assertFalse(all instanceof AuthorityCodes); // Usually a HashSet.
520: assertTrue(all.containsAll(crs));
521: assertTrue(all.containsAll(datum));
522: assertTrue(all.containsAll(operations));
523: assertFalse(all.containsAll(units)); // They are not IdentifiedObjects.
524: }
525:
526: /**
527: * Tests {@link CRS#getEnvelope} and {@link CRS#getGeographicBoundingBox}.
528: */
529: public void testValidArea() throws FactoryException,
530: TransformException {
531: final CoordinateReferenceSystem crs = factory
532: .createCoordinateReferenceSystem("7400");
533: final GeographicBoundingBox bbox = CRS
534: .getGeographicBoundingBox(crs);
535: assertNotNull(
536: "No bounding box. Maybe an older EPSG database is running? "
537: + "Try to clear the tmp/Geotools directory.",
538: bbox);
539: assertEquals(42.25, bbox.getSouthBoundLatitude(), EPS);
540: assertEquals(51.10, bbox.getNorthBoundLatitude(), EPS);
541: assertEquals(-5.20, bbox.getWestBoundLongitude(), EPS);
542: assertEquals(8.23, bbox.getEastBoundLongitude(), EPS);
543: final Envelope envelope = CRS.getEnvelope(crs);
544: assertEquals(46.948, envelope.getMinimum(0), 1E-3);
545: assertEquals(56.781, envelope.getMaximum(0), 1E-3);
546: assertEquals(-8.375, envelope.getMinimum(1), 1E-3);
547: assertEquals(6.548, envelope.getMaximum(1), 1E-3);
548: assertNull(CRS.getEnvelope(null));
549: final GeographicBoundingBox rep = new GeographicBoundingBoxImpl(
550: envelope);
551: assertEquals(42.25, rep.getSouthBoundLatitude(), 1E-3);
552: assertEquals(51.10, rep.getNorthBoundLatitude(), 1E-3);
553: assertEquals(-5.20, rep.getWestBoundLongitude(), 1E-3);
554: assertEquals(8.23, rep.getEastBoundLongitude(), 1E-3);
555: }
556:
557: /**
558: * Tests the serialization of many {@link CoordinateOperation} objects.
559: */
560: public void testSerialization() throws FactoryException,
561: IOException, ClassNotFoundException {
562: CoordinateReferenceSystem crs1 = factory
563: .createCoordinateReferenceSystem("4326");
564: CoordinateReferenceSystem crs2 = factory
565: .createCoordinateReferenceSystem("4322");
566: CoordinateOperationFactory opf = ReferencingFactoryFinder
567: .getCoordinateOperationFactory(null);
568: CoordinateOperation cop = opf.createOperation(crs1, crs2);
569: serialize(cop);
570:
571: crs1 = crs2 = null;
572: final String crs1_name = "4326";
573: final int crs2_ranges[] = { 4326, 4326,
574: /* [ 2] */4322, 4322,
575: /* [ 4] */4269, 4269,
576: /* [ 6] */4267, 4267,
577: /* [ 8] */4230, 4230,
578: /* [10] */32601, 32660,
579: /* [12] */32701, 32760,
580: /* [14] */2759, 2930 };
581:
582: for (int irange = 0; irange < crs2_ranges.length; irange += 2) {
583: int range_start = crs2_ranges[irange];
584: int range_end = crs2_ranges[irange + 1];
585: for (int isystem2 = range_start; isystem2 <= range_end; isystem2++) {
586: if (crs1 == null) {
587: crs1 = factory
588: .createCoordinateReferenceSystem(crs1_name);
589: }
590: String crs2_name = Integer.toString(isystem2);
591: crs2 = factory
592: .createCoordinateReferenceSystem(crs2_name);
593: cop = opf.createOperation(crs1, crs2);
594: serialize(cop);
595: if (!extensive) {
596: // If we are not running in extensive test mode,
597: // tests only the first CRS from each range.
598: break;
599: }
600: }
601: }
602: }
603:
604: /**
605: * Tests the serialization of the specified object.
606: */
607: private static void serialize(final Object object)
608: throws IOException, ClassNotFoundException {
609: final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
610: final ObjectOutputStream out = new ObjectOutputStream(buffer);
611: out.writeObject(object);
612: out.close();
613: final ObjectInputStream in = new ObjectInputStream(
614: new ByteArrayInputStream(buffer.toByteArray()));
615: final Object read = in.readObject();
616: in.close();
617: assertEquals(object, read);
618: assertEquals(object.hashCode(), read.hashCode());
619: }
620:
621: /**
622: * Tests the creation of {@link Conversion} objects.
623: */
624: public void testConversions() throws FactoryException {
625: /*
626: * UTM zone 10N
627: */
628: final CoordinateOperation operation = factory
629: .createCoordinateOperation("16010");
630: assertEquals("16010", getIdentifier(operation));
631: assertTrue(operation instanceof Conversion);
632: assertNull(operation.getSourceCRS());
633: assertNull(operation.getTargetCRS());
634: assertNull(operation.getMathTransform());
635: /*
636: * WGS 72 / UTM zone 10N
637: */
638: final ProjectedCRS crs = factory.createProjectedCRS("32210");
639: final CoordinateOperation projection = crs
640: .getConversionFromBase();
641: assertEquals("32210", getIdentifier(crs));
642: assertEquals("16010", getIdentifier(projection));
643: assertTrue(projection instanceof Projection);
644: assertNotNull(projection.getSourceCRS());
645: assertNotNull(projection.getTargetCRS());
646: assertNotNull(projection.getMathTransform());
647: assertNotSame(projection, operation);
648: assertSame(((Conversion) operation).getMethod(),
649: ((Conversion) projection).getMethod());
650: /*
651: * WGS 72BE / UTM zone 10N
652: */
653: assertFalse(CRS.equalsIgnoreMetadata(crs, factory
654: .createProjectedCRS("32410")));
655: /*
656: * Creates a projected CRS from base and projected CRS codes.
657: */
658: final Set all = factory
659: .createFromCoordinateReferenceSystemCodes("4322",
660: "32210");
661: assertEquals(1, all.size());
662: assertTrue(all.contains(projection));
663: }
664:
665: /**
666: * Tests the creation of {@link Transformation} objects.
667: */
668: public void testTransformations() throws FactoryException {
669: /*
670: * Longitude rotation
671: */
672: assertTrue(factory.createCoordinateOperation("1764") instanceof Transformation);
673: /*
674: * ED50 (4230) --> WGS 84 (4326) using
675: * Geocentric translations (9603).
676: * Accuracy = 999
677: */
678: final CoordinateOperation operation1 = factory
679: .createCoordinateOperation("1087");
680: final CoordinateReferenceSystem sourceCRS = operation1
681: .getSourceCRS();
682: final CoordinateReferenceSystem targetCRS = operation1
683: .getTargetCRS();
684: final MathTransform transform = operation1.getMathTransform();
685: assertEquals("1087", getIdentifier(operation1));
686: assertEquals("4230", getIdentifier(sourceCRS));
687: assertEquals("4326", getIdentifier(targetCRS));
688: assertTrue(operation1 instanceof Transformation);
689: assertNotSame(sourceCRS, targetCRS);
690: assertFalse(operation1.getMathTransform().isIdentity());
691: assertEquals(999, AbstractCoordinateOperation
692: .getAccuracy(operation1), 1E-6);
693: /*
694: * ED50 (4230) --> WGS 84 (4326) using
695: * Position Vector 7-param. transformation (9606).
696: * Accuracy = 1.5
697: */
698: final CoordinateOperation operation2 = factory
699: .createCoordinateOperation("1631");
700: assertEquals("1631", getIdentifier(operation2));
701: assertTrue(operation2 instanceof Transformation);
702: assertSame(sourceCRS, operation2.getSourceCRS());
703: assertSame(targetCRS, operation2.getTargetCRS());
704: assertFalse(operation2.getMathTransform().isIdentity());
705: assertFalse(transform.equals(operation2.getMathTransform()));
706: assertEquals(1.5, AbstractCoordinateOperation
707: .getAccuracy(operation2), 1E-6);
708: /*
709: * ED50 (4230) --> WGS 84 (4326) using
710: * Coordinate Frame rotation (9607).
711: * Accuracy = 1.0
712: */
713: final CoordinateOperation operation3 = factory
714: .createCoordinateOperation("1989");
715: assertEquals("1989", getIdentifier(operation3));
716: assertTrue(operation3 instanceof Transformation);
717: assertSame(sourceCRS, operation3.getSourceCRS());
718: assertSame(targetCRS, operation3.getTargetCRS());
719: assertFalse(operation3.getMathTransform().isIdentity());
720: assertFalse(transform.equals(operation3.getMathTransform()));
721: assertEquals(1.0, AbstractCoordinateOperation
722: .getAccuracy(operation3), 1E-6);
723: if (false) {
724: System.out.println(operation3);
725: System.out.println(operation3.getSourceCRS());
726: System.out.println(operation3.getTargetCRS());
727: System.out.println(operation3.getMathTransform());
728: }
729: /*
730: * Tests "BD72 to WGS 84 (1)" (EPSG:1609) creation. This one has an unusual unit for the
731: * "Scale difference" parameter (EPSG:8611). The value is 0.999999 and the unit is "unity"
732: * (EPSG:9201) instead of the usual "parts per million" (EPSG:9202). It was used to thrown
733: * an exception in older EPSG factory implementations.
734: */
735: assertEquals(1.0,
736: AbstractCoordinateOperation.getAccuracy(factory
737: .createCoordinateOperation("1609")), 1E-6);
738: /*
739: * Creates from CRS codes. There is 40 such operations in EPSG version 6.7.
740: * The preferred one (according the "supersession" table) is EPSG:1612.
741: *
742: * Note: the above assertion fails on PostgreSQL because its "ORDER BY" clause put null
743: * values last, while Access and HSQL put them first. The PostgreSQL behavior is better
744: * for what we want (operations with unknow accuracy last). Unfortunatly, I don't know
745: * yet how to instructs Access to put null values last using standard SQL ("IIF" is not
746: * standard, and Access doesn't seem to understand "CASE ... THEN" clauses).
747: */
748: final Set all = factory
749: .createFromCoordinateReferenceSystemCodes("4230",
750: "4326");
751: assertTrue(all.size() >= 3);
752: assertTrue(all.contains(operation1));
753: assertTrue(all.contains(operation2));
754: assertTrue(all.contains(operation3));
755: int count = 0;
756: for (final Iterator it = all.iterator(); it.hasNext();) {
757: final CoordinateOperation check = (CoordinateOperation) it
758: .next();
759: assertSame(sourceCRS, check.getSourceCRS());
760: assertSame(targetCRS, check.getTargetCRS());
761: if (count++ == 0) {
762: assertEquals("1612", getIdentifier(check)); // see comment above.
763: }
764: }
765: assertEquals(all.size(), count);
766: }
767:
768: /**
769: * Fetchs the accuracy declared in all coordinate operations found in the database.
770: */
771: public void testAccuracy() throws FactoryException {
772: final Set identifiers = factory
773: .getAuthorityCodes(CoordinateOperation.class);
774: double min = Double.POSITIVE_INFINITY;
775: double max = Double.NEGATIVE_INFINITY;
776: double sum = 0;
777: int count = 0; // Number of coordinate operations (minus the skipped ones).
778: int created = 0; // Number of coordinate operations recognized by the factory.
779: int valid = 0; // Number of non-NaN accuracies.
780: for (final Iterator it = identifiers.iterator(); it.hasNext();) {
781: final CoordinateOperation operation;
782: final String code = (String) it.next();
783: final int n = Integer.parseInt(code);
784: if (n >= 10087 && n <= 10088) {
785: // Valid, but log a warning. Will avoid just in order to keep the output clean.
786: continue;
787: }
788: ++count;
789: if (!extensive && (count % 20) != 0) {
790: // If the tests are not executed in "extensive" mode, tests only 5% of cases.
791: continue;
792: }
793: try {
794: operation = factory.createCoordinateOperation(code);
795: } catch (FactoryException exception) {
796: // Skip unsupported coordinate operations, except if the cause is a SQL exception.
797: if (exception.getCause() instanceof SQLException) {
798: throw exception;
799: }
800: continue;
801: }
802: created++;
803: assertNotNull(operation);
804: final double accuracy = AbstractCoordinateOperation
805: .getAccuracy(operation);
806: assertFalse(accuracy < 0);
807: if (!Double.isNaN(accuracy)) {
808: if (accuracy < min)
809: min = accuracy;
810: if (accuracy > max)
811: max = accuracy;
812: sum += accuracy;
813: valid++;
814: }
815: }
816: if (verbose) {
817: System.out.print("Number of coordinate operations: ");
818: System.out.println(identifiers.size());
819: System.out.print("Number of tested operations: ");
820: System.out.println(count);
821: System.out.print("Number of recognized operations: ");
822: System.out.println(created);
823: System.out.print("Number of operations with accuracy: ");
824: System.out.println(valid);
825: System.out.print("Minimal accuracy value (meters): ");
826: System.out.println(min);
827: System.out.print("Maximal accuracy value (meters): ");
828: System.out.println(max);
829: System.out.print("Average accuracy value (meters): ");
830: System.out.println(sum / valid);
831: }
832: }
833:
834: /**
835: * Compares a WKT found in the field with the EPSG equivalent.
836: *
837: * @see http://jira.codehaus.org/browse/GEOT-1268
838: */
839: public void testEquivalent() throws FactoryException {
840: final String wkt = "PROJCS[\"NAD_1983_StatePlane_Massachusetts_Mainland_FIPS_2001\", "
841: + "GEOGCS[\"GCS_North_American_1983\", "
842: + "DATUM[\"D_North_American_1983\", "
843: + "SPHEROID[\"GRS_1980\", 6378137.0, 298.257222101]], "
844: + "PRIMEM[\"Greenwich\", 0.0], "
845: + "UNIT[\"degree\", 0.017453292519943295], "
846: + "AXIS[\"Longitude\", EAST], "
847: + "AXIS[\"Latitude\", NORTH]], "
848: + "PROJECTION[\"Lambert_Conformal_Conic\"], "
849: + "PARAMETER[\"central_meridian\", -71.5], "
850: + "PARAMETER[\"latitude_of_origin\", 41.0], "
851: + "PARAMETER[\"standard_parallel_1\", 41.71666666666667], "
852: + "PARAMETER[\"scale_factor\", 1.0], "
853: + "PARAMETER[\"false_easting\", 200000.0], "
854: + "PARAMETER[\"false_northing\", 750000.0], "
855: + "PARAMETER[\"standard_parallel_2\", 42.68333333333334], "
856: + "UNIT[\"m\", 1.0], "
857: + "AXIS[\"x\", EAST], "
858: + "AXIS[\"y\", NORTH]]";
859:
860: final CoordinateReferenceSystem crs1 = CRS.parseWKT(wkt);
861: final CoordinateReferenceSystem crs2 = CRS.decode("EPSG:26986");
862:
863: // This is the current state of Geotools, but it is wrong. The CRS should be equivalent.
864: // We will change to 'assertTrue' if a MapProjection.equivalent(MapProjection) method is
865: // implemented in some future Geotools version.
866: assertFalse(CRS.equalsIgnoreMetadata(crs1, crs2));
867: }
868:
869: /**
870: * Tests {@link DefaultFactory#find} method.
871: */
872: public void testFind() throws FactoryException {
873: final IdentifiedObjectFinder finder = factory
874: .getIdentifiedObjectFinder(CoordinateReferenceSystem.class);
875: assertTrue("Full scan should be enabled by default.", finder
876: .isFullScanAllowed());
877: assertNull(
878: "Should not find WGS84 because the axis order is not the same.",
879: finder.find(DefaultGeographicCRS.WGS84));
880:
881: String wkt;
882: wkt = "GEOGCS[\"WGS 84\",\n"
883: + " DATUM[\"World Geodetic System 1984\",\n"
884: + " SPHEROID[\"WGS 84\", 6378137.0, 298.257223563]],\n"
885: + " PRIMEM[\"Greenwich\", 0.0],\n"
886: + " UNIT[\"degree\", 0.017453292519943295],\n"
887: + " AXIS[\"Geodetic latitude\", NORTH],\n"
888: + " AXIS[\"Geodetic longitude\", EAST]]";
889: CoordinateReferenceSystem crs = CRS.parseWKT(wkt);
890: finder.setFullScanAllowed(false);
891: assertNull(
892: "Should not find without a full scan, because the WKT contains no identifier "
893: + "and the CRS name is ambiguous (more than one EPSG object have this name).",
894: finder.find(crs));
895:
896: finder.setFullScanAllowed(true);
897: IdentifiedObject find = finder.find(crs);
898: assertNotNull(
899: "With full scan allowed, the CRS should be found.",
900: find);
901: assertTrue(
902: "Should found an object equals (ignoring metadata) to the requested one.",
903: CRS.equalsIgnoreMetadata(crs, find));
904: assertEquals("4326", AbstractIdentifiedObject.getIdentifier(
905: find, factory.getAuthority()).getCode());
906: finder.setFullScanAllowed(false);
907: assertEquals("The CRS should still in the cache.", "EPSG:4326",
908: finder.findIdentifier(crs));
909: /*
910: * The PROJCS below intentionnaly uses a name different from the one found in the
911: * EPSG database, in order to force a full scan (otherwise the EPSG database would
912: * find it by name, but we want to test the scan).
913: */
914: wkt = "PROJCS[\"Beijing 1954\",\n"
915: + " GEOGCS[\"Beijing 1954\",\n"
916: + " DATUM[\"Beijing 1954\",\n"
917: + " SPHEROID[\"Krassowsky 1940\", 6378245.0, 298.3]],\n"
918: + " PRIMEM[\"Greenwich\", 0.0],\n"
919: + " UNIT[\"degree\", 0.017453292519943295],\n"
920: + " AXIS[\"Geodetic latitude\", NORTH],\n"
921: + " AXIS[\"Geodetic longitude\", EAST]],\n"
922: + " PROJECTION[\"Transverse Mercator\"],\n"
923: + " PARAMETER[\"central_meridian\", 135.0],\n"
924: + " PARAMETER[\"latitude_of_origin\", 0.0],\n"
925: + " PARAMETER[\"scale_factor\", 1.0],\n"
926: + " PARAMETER[\"false_easting\", 500000.0],\n"
927: + " PARAMETER[\"false_northing\", 0.0],\n"
928: + " UNIT[\"m\", 1.0],\n"
929: + " AXIS[\"Northing\", NORTH],\n"
930: + " AXIS[\"Easting\", EAST]]";
931: crs = CRS.parseWKT(wkt);
932: finder.setFullScanAllowed(false);
933: assertNull("Should not find the CRS without a full scan.",
934: finder.find(crs));
935: finder.setFullScanAllowed(true);
936: find = finder.find(crs);
937: assertNotNull(
938: "With full scan allowed, the CRS should be found.",
939: find);
940: assertTrue(
941: "Should found an object equals (ignoring metadata) to the requested one.",
942: CRS.equalsIgnoreMetadata(crs, find));
943: assertEquals("2442", AbstractIdentifiedObject.getIdentifier(
944: find, factory.getAuthority()).getCode());
945: finder.setFullScanAllowed(false);
946: assertEquals("The CRS should still in the cache.", "EPSG:2442",
947: finder.findIdentifier(crs));
948: }
949: }
|