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; either
009: * version 2.1 of the License, or (at your option) any later version.
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.operation.projection;
017:
018: // JUnit dependencies
019: import junit.framework.AssertionFailedError;
020: import junit.framework.Test;
021: import junit.framework.TestCase;
022: import junit.framework.TestSuite;
023:
024: // OpenGIS dependencies
025: import org.opengis.parameter.ParameterDescriptorGroup;
026: import org.opengis.parameter.ParameterValueGroup;
027: import org.opengis.referencing.FactoryException;
028: import org.opengis.referencing.NoSuchIdentifierException;
029: import org.opengis.referencing.operation.MathTransform;
030: import org.opengis.referencing.operation.MathTransformFactory;
031: import org.opengis.referencing.operation.TransformException;
032: import org.opengis.geometry.DirectPosition;
033:
034: // Geotools dependencies
035: import org.geotools.geometry.DirectPosition2D;
036: import org.geotools.parameter.ParameterWriter;
037: import org.geotools.referencing.ReferencingFactoryFinder;
038: import org.geotools.referencing.AbstractIdentifiedObject;
039: import org.geotools.resources.Arguments;
040:
041: /**
042: * Tests projection equations as well as the integration with {@link MathTransformFactory}.
043: * Projections are tested through creation and testing of {@link MathTransform} objects;
044: * no {@link org.opengis.referencing.operation.Projection} are created here.
045: * <p>
046: * The spherical tests here tests real spheres (tests in {@code "Simple"} test scripts are
047: * not exactly spherical).
048: *
049: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/test/java/org/geotools/referencing/operation/projection/DirectCreationTest.java $
050: * @version $Id: DirectCreationTest.java 25778 2007-06-08 08:46:34Z desruisseaux $
051: * @author Rueben Schulz
052: */
053: public final class DirectCreationTest extends TestCase {
054: /**
055: * Set to {@code true} for printing some informations to standard output while
056: * performing tests. Consider this field as constants after the application launch.
057: */
058: private static boolean VERBOSE = false;
059:
060: /** Tolerance for test when units are degrees. */
061: private final static double[] TOL_DEG = { 1E-6, 1E-6 };
062:
063: /** Tolerance for test when units are metres. */
064: private final static double[] TOL_M = { 1E-2, 1E-2 };
065:
066: /** factory to use to create projection transforms*/
067: private MathTransformFactory mtFactory;
068:
069: /**
070: * Constructs a test with the given name.
071: */
072: public DirectCreationTest(final String name) {
073: super (name);
074: }
075:
076: /**
077: * Uses reflection to dynamically create a test suite containing all
078: * the {@code testXXX()} methods - from the JUnit FAQ.
079: */
080: public static Test suite() {
081: return new TestSuite(DirectCreationTest.class);
082: }
083:
084: /**
085: * Runs the tests with the textual test runner.
086: */
087: public static void main(final String args[]) {
088: final Arguments arguments = new Arguments(args);
089: VERBOSE = arguments.getFlag("-verbose");
090: arguments.getRemainingArguments(0);
091: junit.textui.TestRunner.run(suite());
092: }
093:
094: /**
095: * Set up common objects used by all tests.
096: */
097: protected void setUp() {
098: mtFactory = ReferencingFactoryFinder
099: .getMathTransformFactory(null);
100: }
101:
102: /**
103: * Release common objects used by all tests.
104: */
105: protected void tearDown() {
106: mtFactory = null;
107: }
108:
109: /**
110: * Check if two coordinate points are equals, in the limits of the specified
111: * tolerance vector.
112: *
113: * @param expected The expected coordinate point.
114: * @param actual The actual coordinate point.
115: * @param tolerance The tolerance vector. If this vector length is smaller than the number
116: * of dimension of <code>actual</code>, then the last tolerance value will
117: * be reused for all extra dimensions.
118: * @throws AssertionFailedError If the actual point is not equals to the expected point.
119: */
120: private static void assertEquals(final DirectPosition expected,
121: final DirectPosition actual, final double[] tolerance)
122: throws AssertionFailedError {
123: final int dimension = actual.getDimension();
124: final int lastToleranceIndex = tolerance.length - 1;
125: assertEquals(
126: "The coordinate point doesn't have the expected dimension",
127: expected.getDimension(), dimension);
128: for (int i = 0; i < dimension; i++) {
129: assertEquals("Mismatch for ordinate " + i
130: + " (zero-based):", expected.getOrdinate(i), actual
131: .getOrdinate(i), tolerance[Math.min(i,
132: lastToleranceIndex)]);
133: }
134: }
135:
136: /**
137: * Helper method to test transform from a source to a target point.
138: * Coordinate points are (x,y) or (long, lat)
139: */
140: private static void doTransform(DirectPosition source,
141: DirectPosition target, MathTransform transform)
142: throws TransformException {
143: doTransform(source, target, transform, TOL_M);
144: }
145:
146: /**
147: * Helper method to test transform from a source to a target point.
148: * Coordinate points are (x,y) or (long, lat)
149: */
150: private static void doTransform(DirectPosition source,
151: DirectPosition target, MathTransform transform,
152: final double[] tolerance) throws TransformException {
153: DirectPosition calculated;
154: calculated = transform.transform(source, null);
155: assertEquals(target, calculated, tolerance);
156:
157: //the inverse
158: target = source;
159: source = calculated;
160: calculated = transform.inverse().transform(source, null);
161: assertEquals(target, calculated, TOL_DEG);
162: }
163:
164: /**
165: * Print parameters for the specified projection.
166: * Used to see the if parameters for a transform are correct.
167: */
168: private void printParameters(final String proj)
169: throws NoSuchIdentifierException {
170: final ParameterValueGroup values = mtFactory
171: .getDefaultParameters(proj);
172: ParameterWriter.print((ParameterDescriptorGroup) values
173: .getDescriptor());
174: }
175:
176: /**
177: * Some tests for the Equidistant Cylindrical projection.
178: */
179: public void testEquidistantCylindrical() throws FactoryException,
180: TransformException {
181:
182: ///////////////////////////////////////
183: // Equidistant_Cylindrical tests //
184: ///////////////////////////////////////
185: if (VERBOSE) {
186: printParameters("Equidistant_Cylindrical");
187: }
188: MathTransform transform;
189: ParameterValueGroup params;
190:
191: // approx bristol UK
192: params = mtFactory
193: .getDefaultParameters("Equidistant_Cylindrical");
194: params.parameter("semi_major").setValue(6378137);
195: params.parameter("semi_minor").setValue(6378137);
196: params.parameter("central_meridian").setValue(0.000);
197: params.parameter("standard_parallel_1").setValue(0.000);
198: params.parameter("false_easting").setValue(0.0);
199: params.parameter("false_northing").setValue(0.0);
200: transform = mtFactory.createParameterizedTransform(params);
201: if (VERBOSE) {
202: System.out.println(transform);
203: }
204: doTransform(new DirectPosition2D(-2.5, 51.37),
205: new DirectPosition2D(-278298.73, 5718482.24), transform);
206: }
207:
208: /**
209: * Some tests for the Mercator Projection.
210: */
211: public void testMercator() throws FactoryException,
212: TransformException {
213:
214: ///////////////////////////////////////
215: // Mercator_1SP tests //
216: ///////////////////////////////////////
217: if (VERBOSE) {
218: printParameters("Mercator_1SP");
219: }
220: MathTransform transform;
221: ParameterValueGroup params;
222:
223: //epsg example (p. 26)
224: params = mtFactory.getDefaultParameters("Mercator_1SP");
225: params.parameter("semi_major").setValue(6377397.155);
226: params.parameter("semi_minor").setValue(6356078.963);
227: params.parameter("central_meridian").setValue(110.000);
228: params.parameter("scale_factor").setValue(0.997);
229: params.parameter("false_easting").setValue(3900000.0);
230: params.parameter("false_northing").setValue(900000.0);
231: transform = mtFactory.createParameterizedTransform(params);
232: if (VERBOSE) {
233: System.out.println(transform);
234: }
235: doTransform(new DirectPosition2D(120.0, -3.0),
236: new DirectPosition2D(5009726.58, 569150.82), transform);
237:
238: //spherical test (Snyder p. 266)
239: params.parameter("semi_major").setValue(1.0);
240: params.parameter("semi_minor").setValue(1.0);
241: params.parameter("central_meridian").setValue(-180.0);
242: params.parameter("scale_factor").setValue(1.0);
243: params.parameter("false_easting").setValue(0.0);
244: params.parameter("false_northing").setValue(0.0);
245: transform = mtFactory.createParameterizedTransform(params);
246: if (VERBOSE) {
247: System.out.println(transform);
248: }
249: doTransform(new DirectPosition2D(-75.0, 35.0),
250: new DirectPosition2D(1.8325957, 0.6528366), transform);
251:
252: //spherical test 2 (original units for target were feet)
253: params.parameter("semi_major").setValue(6370997.0);
254: params.parameter("semi_minor").setValue(6370997.0);
255: params.parameter("central_meridian").setValue(0.0);
256: params.parameter("scale_factor").setValue(1.0);
257: params.parameter("false_easting").setValue(0.0);
258: params.parameter("false_northing").setValue(0.0);
259: transform = mtFactory.createParameterizedTransform(params);
260: if (VERBOSE) {
261: System.out.println(transform);
262: }
263: doTransform(new DirectPosition2D(-123.1, 49.2166666666),
264: new DirectPosition2D(-13688089.02443480,
265: 6304639.84599441), transform);
266:
267: //ellipsoidal with latitude of origin not zero, (simone)
268: params.parameter("semi_major").setValue(6378137.0);
269: params.parameter("semi_minor").setValue(6356752.314245);
270: params.parameter("latitude_of_origin").setValue(38.0);
271: params.parameter("central_meridian").setValue(3.03);
272: params.parameter("scale_factor").setValue(1.0);
273: params.parameter("false_easting").setValue(0.0);
274: params.parameter("false_northing").setValue(0.0);
275: transform = mtFactory.createParameterizedTransform(params);
276: if (VERBOSE) {
277: System.out.println(transform);
278: }
279: doTransform(new DirectPosition2D(4.999999999999999,
280: 26.996561536844165), new DirectPosition2D(
281: 173029.94823812644, 2448819.342941506), transform);
282:
283: ///////////////////////////////////////
284: // Mercator_2SP tests //
285: ///////////////////////////////////////
286: if (VERBOSE) {
287: printParameters("Mercator_2SP");
288: }
289: //epsg p25. Note FE and FN are wrong in guide 7. Correct in epsg database v6.3.
290: params = mtFactory.getDefaultParameters("Mercator_2SP");
291: params.parameter("semi_major").setValue(6378245.000);
292: params.parameter("semi_minor").setValue(6356863.019);
293: params.parameter("central_meridian").setValue(51.0);
294: params.parameter("standard_parallel_1").setValue(42.0);
295: params.parameter("false_easting").setValue(0.0);
296: params.parameter("false_northing").setValue(0.0);
297: transform = mtFactory.createParameterizedTransform(params);
298: if (VERBOSE) {
299: System.out.println(transform);
300: }
301: doTransform(new DirectPosition2D(53.0, 53.0),
302: new DirectPosition2D(165704.29, 5171848.07), transform);
303:
304: //a spherical case (me)
305: params = mtFactory.getDefaultParameters("Mercator_2SP");
306: params.parameter("semi_major").setValue(6370997.0);
307: params.parameter("semi_minor").setValue(6370997.0);
308: params.parameter("central_meridian").setValue(180.0);
309: params.parameter("standard_parallel_1").setValue(60.0);
310: params.parameter("false_easting").setValue(-500000.0);
311: params.parameter("false_northing").setValue(-1000000.0);
312: transform = mtFactory.createParameterizedTransform(params);
313: if (VERBOSE) {
314: System.out.println(transform);
315: }
316: doTransform(new DirectPosition2D(-123.1, 49.2166666666),
317: new DirectPosition2D(2663494.1734, 2152319.9230),
318: transform);
319:
320: }
321:
322: /**
323: * Some tests for the Oblique Mercator Projection.
324: */
325: public void testObliqueMercator() throws FactoryException,
326: TransformException {
327: if (VERBOSE) {
328: printParameters("Oblique Mercator");
329: }
330: MathTransform transform;
331: ParameterValueGroup params;
332:
333: params = mtFactory.getDefaultParameters("Oblique Mercator");
334: setObliqueMercatorParameter(params);
335: transform = mtFactory.createParameterizedTransform(params);
336: assertEquals(transform.getClass(), ObliqueMercator.class);
337: assertEquals(transform, new ObliqueMercator(params));
338: ParameterDescriptorGroup descriptor = ((MapProjection) transform)
339: .getParameterDescriptors();
340: assertTrue(AbstractIdentifiedObject.nameMatches(descriptor,
341: "Oblique Mercator"));
342: assertFalse(AbstractIdentifiedObject.nameMatches(descriptor,
343: "Hotine Oblique Mercator"));
344: final MathTransform standard = transform;
345:
346: params = mtFactory
347: .getDefaultParameters("Hotine Oblique Mercator");
348: setObliqueMercatorParameter(params);
349: transform = mtFactory.createParameterizedTransform(params);
350: assertEquals(transform.getClass(), HotineObliqueMercator.class);
351: assertEquals(transform, new HotineObliqueMercator(params));
352: descriptor = ((MapProjection) transform)
353: .getParameterDescriptors();
354: assertFalse(AbstractIdentifiedObject.nameMatches(descriptor,
355: "Oblique Mercator"));
356: assertTrue(AbstractIdentifiedObject.nameMatches(descriptor,
357: "Hotine Oblique Mercator"));
358: assertFalse(transform.equals(standard));
359: }
360:
361: /**
362: * For {@link #testObliqueMercator} internal use only.
363: */
364: private static void setObliqueMercatorParameter(
365: ParameterValueGroup params) {
366: params.parameter("semi_major").setValue(6377397.155);
367: params.parameter("semi_minor").setValue(6356078.963);
368: params.parameter("longitude_of_center").setValue(
369: 7.439583333333333);
370: params.parameter("latitude_of_center").setValue(
371: 46.952405555555565);
372: params.parameter("azimuth").setValue(90.0);
373: params.parameter("scale_factor").setValue(1.0);
374: params.parameter("false_easting").setValue(600000.0);
375: params.parameter("false_northing").setValue(200000.0);
376: params.parameter("rectified_grid_angle").setValue(90.0);
377: }
378:
379: /**
380: * Some tests for the Lambert Conic Conformal Projection.
381: */
382: public void testLambert() throws FactoryException,
383: TransformException {
384:
385: ///////////////////////////////////////
386: // Lambert_Conformal_Conic_1SP tests //
387: ///////////////////////////////////////
388: if (VERBOSE) {
389: printParameters("Lambert_Conformal_Conic_1SP");
390: }
391: MathTransform transform;
392: ParameterValueGroup params;
393:
394: //EPGS p. 18
395: params = mtFactory
396: .getDefaultParameters("Lambert_Conformal_Conic_1SP");
397: params.parameter("semi_major").setValue(6378206.4);
398: params.parameter("semi_minor").setValue(6356583.8);
399: params.parameter("central_meridian").setValue(-77.0);
400: params.parameter("latitude_of_origin").setValue(18.0);
401: params.parameter("scale_factor").setValue(1.0);
402: params.parameter("false_easting").setValue(250000.0);
403: params.parameter("false_northing").setValue(150000.0);
404: transform = mtFactory.createParameterizedTransform(params);
405: if (VERBOSE) {
406: System.out.println(transform);
407: }
408: doTransform(new DirectPosition2D(-76.943683333, 17.932166666),
409: new DirectPosition2D(255966.58, 142493.51), transform);
410:
411: //Spherical (me)
412: params.parameter("semi_major").setValue(6370997.0);
413: params.parameter("semi_minor").setValue(6370997.0);
414: params.parameter("central_meridian").setValue(111.0);
415: params.parameter("latitude_of_origin").setValue(-55.0);
416: params.parameter("scale_factor").setValue(1.0);
417: params.parameter("false_easting").setValue(500000.0);
418: params.parameter("false_northing").setValue(1000000.0);
419: transform = mtFactory.createParameterizedTransform(params);
420: if (VERBOSE) {
421: System.out.println(transform.toString());
422: }
423: doTransform(new DirectPosition2D(151.283333333, -33.916666666),
424: new DirectPosition2D(4232963.1816, 2287639.9866),
425: transform);
426:
427: ///////////////////////////////////////
428: // Lambert_Conformal_Conic_2SP tests //
429: ///////////////////////////////////////
430: if (VERBOSE) {
431: printParameters("Lambert_Conformal_Conic_2SP");
432: }
433: //EPSG p. 17
434: params = mtFactory
435: .getDefaultParameters("Lambert_Conformal_Conic_2SP");
436: params.parameter("semi_major").setValue(6378206.4);
437: params.parameter("semi_minor").setValue(6356583.8);
438: params.parameter("central_meridian").setValue(-99.0);
439: params.parameter("latitude_of_origin").setValue(27.833333333);
440: params.parameter("standard_parallel_1").setValue(28.383333333);
441: params.parameter("standard_parallel_2").setValue(30.283333333);
442: params.parameter("false_easting").setValue(609601.218); //metres
443: params.parameter("false_northing").setValue(0.0);
444: transform = mtFactory.createParameterizedTransform(params);
445: if (VERBOSE) {
446: System.out.println(transform);
447: }
448: doTransform(new DirectPosition2D(-96.0, 28.5),
449: new DirectPosition2D(903277.7965, 77650.94219),
450: transform);
451:
452: //Spherical (me)
453: params.parameter("semi_major").setValue(6370997.0);
454: params.parameter("semi_minor").setValue(6370997.0);
455: params.parameter("central_meridian").setValue(-120.0);
456: params.parameter("latitude_of_origin").setValue(0.0);
457: params.parameter("standard_parallel_1").setValue(2.0);
458: params.parameter("standard_parallel_2").setValue(60.0);
459: params.parameter("false_easting").setValue(0.0);
460: params.parameter("false_northing").setValue(0.0);
461: transform = mtFactory.createParameterizedTransform(params);
462: if (VERBOSE) {
463: System.out.println(transform);
464: }
465: doTransform(new DirectPosition2D(139.733333333, 35.6833333333),
466: new DirectPosition2D(-6789805.6471, 7107623.6859),
467: transform);
468:
469: //1SP where SP != lat of origin (me)
470: params.parameter("semi_major").setValue(6378137.0);
471: params.parameter("semi_minor").setValue(6356752.31424518);
472: params.parameter("central_meridian").setValue(0.0);
473: params.parameter("latitude_of_origin").setValue(-50.0);
474: params.parameter("standard_parallel_1").setValue(-40.0);
475: params.parameter("standard_parallel_2").setValue(-40.0);
476: params.parameter("false_easting").setValue(100000.0);
477: params.parameter("false_northing").setValue(0.0);
478: transform = mtFactory.createParameterizedTransform(params);
479: if (VERBOSE) {
480: System.out.println(transform);
481: }
482: doTransform(new DirectPosition2D(18.45, -33.9166666666),
483: new DirectPosition2D(1803288.3324, 1616657.7846),
484: transform);
485:
486: ///////////////////////////////////////////////
487: // Lambert_Conformal_Conic_2SP_Belgium test //
488: ///////////////////////////////////////////////
489: if (VERBOSE) {
490: printParameters("Lambert_Conformal_Conic_2SP_Belgium");
491: }
492: //epsg p. 19
493: params = mtFactory
494: .getDefaultParameters("Lambert_Conformal_Conic_2SP_Belgium");
495: params.parameter("semi_major").setValue(6378388.0);
496: params.parameter("semi_minor").setValue(6356911.946);
497: params.parameter("central_meridian").setValue(4.356939722);
498: params.parameter("latitude_of_origin").setValue(90.0);
499: params.parameter("standard_parallel_1").setValue(49.833333333);
500: params.parameter("standard_parallel_2").setValue(51.166666666);
501: params.parameter("false_easting").setValue(150000.01);
502: params.parameter("false_northing").setValue(5400088.44);
503: transform = mtFactory.createParameterizedTransform(params);
504: if (VERBOSE) {
505: System.out.println(transform);
506: }
507: doTransform(new DirectPosition2D(5.807370277, 50.6795725),
508: new DirectPosition2D(251763.20, 153034.13), transform);
509: }
510:
511: /**
512: * Some tests for Krovak Projection.
513: */
514: public void testKrovak() throws FactoryException,
515: TransformException {
516:
517: ///////////////////////////////////////
518: // Krovak tests //
519: ///////////////////////////////////////
520: if (VERBOSE) {
521: printParameters("Krovak");
522: }
523: MathTransform transform;
524: ParameterValueGroup params;
525:
526: params = mtFactory.getDefaultParameters("Krovak");
527: params.parameter("semi_major").setValue(6377397.155);
528: params.parameter("semi_minor").setValue(6356078.963);
529: params.parameter("latitude_of_center").setValue(49.5);
530: params.parameter("longitude_of_center").setValue(
531: 42.5 - 17.66666666666667);
532: params.parameter("azimuth").setValue(30.28813972222222);
533: params.parameter("pseudo_standard_parallel_1").setValue(78.5);
534: params.parameter("scale_factor").setValue(0.9999);
535: transform = mtFactory.createParameterizedTransform(params);
536: if (VERBOSE) {
537: System.out.println(transform);
538: }
539: doTransform(new DirectPosition2D(14.370530947, 50.071153856),
540: new DirectPosition2D(-746742.6075, -1044389.4516),
541: transform);
542: }
543:
544: /**
545: * Some tests for Stereographic projection.
546: */
547: public void testStereographic() throws FactoryException,
548: TransformException {
549:
550: ///////////////////////////////////////
551: // Polar_Stereographic tests //
552: ///////////////////////////////////////
553: if (VERBOSE) {
554: printParameters("Polar_Stereographic");
555: }
556: MathTransform transform;
557: ParameterValueGroup params;
558:
559: //
560: // http://www.remotesensing.org/geotiff/proj_list/polar_stereographic.html
561: //
562: params = mtFactory
563: .getDefaultParameters("Stereographic_North_Pole");
564: params.parameter("semi_major").setValue(6378137.0);
565: params.parameter("semi_minor").setValue(6356752.31424518);
566: params.parameter("standard_parallel_1").setValue(71.0);
567: params.parameter("central_meridian").setValue(-96.0);
568: params.parameter("scale_factor").setValue(1.0);
569: params.parameter("false_easting").setValue(0);
570: params.parameter("false_northing").setValue(0);
571: transform = mtFactory.createParameterizedTransform(params);
572: if (VERBOSE) {
573: System.out.println(transform);
574: }
575: doTransform(new DirectPosition2D(-121.33955, 39.1012523), // 121°20'22.38"W 39°6'4.508"N
576: new DirectPosition2D(-2529570, -5341800), transform);
577:
578: //
579: // http://jira.codehaus.org/browse/GEOS-1037
580: //
581: params = mtFactory.getDefaultParameters("Polar_Stereographic");
582: params.parameter("semi_major").setValue(6378137.0);
583: params.parameter("semi_minor").setValue(6356752.31424518);
584: params.parameter("latitude_of_origin").setValue(-90);
585: params.parameter("central_meridian").setValue(0);
586: params.parameter("scale_factor").setValue(0.97276901289);
587: params.parameter("false_easting").setValue(0);
588: params.parameter("false_northing").setValue(0);
589: transform = mtFactory.createParameterizedTransform(params);
590: if (VERBOSE) {
591: System.out.println(transform);
592: }
593: final double[] tolerance = new double[] { 0.1, 0.1 };
594: doTransform(new DirectPosition2D(10, -85),
595: new DirectPosition2D(94393.99, 535334.89), transform);
596: doTransform(new DirectPosition2D(-75, -80),
597: new DirectPosition2D(-1052066.625, 281900.375),
598: transform, tolerance);
599: doTransform(new DirectPosition2D(-75, -70),
600: new DirectPosition2D(-2119718.750, 567976.875),
601: transform, tolerance);
602: doTransform(new DirectPosition2D(-75, -60),
603: new DirectPosition2D(-3219560.250, 862678.563),
604: transform, tolerance);
605: }
606: }
|