001/* 002 * GeoAPI - Java interfaces for OGC/ISO standards 003 * http://www.geoapi.org 004 * 005 * Copyright (C) 2011-2019 Open Geospatial Consortium, Inc. 006 * All Rights Reserved. http://www.opengeospatial.org/ogc/legal 007 * 008 * Permission to use, copy, and modify this software and its documentation, with 009 * or without modification, for any purpose and without fee or royalty is hereby 010 * granted, provided that you include the following on ALL copies of the software 011 * and documentation or portions thereof, including modifications, that you make: 012 * 013 * 1. The full text of this NOTICE in a location viewable to users of the 014 * redistributed or derivative work. 015 * 2. Notice of any changes or modifications to the OGC files, including the 016 * date changes were made. 017 * 018 * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE 019 * NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 020 * TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT 021 * THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY 022 * PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. 023 * 024 * COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR 025 * CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENTATION. 026 * 027 * The name and trademarks of copyright holders may NOT be used in advertising or 028 * publicity pertaining to the software without specific, written prior permission. 029 * Title to copyright in this software and any associated documentation will at all 030 * times remain with copyright holders. 031 */ 032package org.opengis.test.referencing; 033 034import java.util.List; 035import java.util.Arrays; 036import java.util.EnumSet; 037import java.util.Collections; 038import java.util.Random; 039import java.awt.geom.Rectangle2D; 040 041import org.opengis.util.Factory; 042import org.opengis.util.FactoryException; 043import org.opengis.util.NoSuchIdentifierException; 044import org.opengis.geometry.DirectPosition; 045import org.opengis.parameter.ParameterValueGroup; 046import org.opengis.parameter.ParameterDescriptorGroup; 047import org.opengis.referencing.crs.ProjectedCRS; 048import org.opengis.referencing.operation.Matrix; 049import org.opengis.referencing.operation.MathTransform; 050import org.opengis.referencing.operation.MathTransform2D; 051import org.opengis.referencing.operation.TransformException; 052import org.opengis.referencing.operation.MathTransformFactory; 053import org.opengis.referencing.operation.Projection; 054import org.opengis.referencing.operation.Transformation; 055import org.opengis.referencing.operation.SingleOperation; 056import org.opengis.test.ToleranceModifiers; 057import org.opengis.test.ToleranceModifier; 058import org.opengis.test.CalculationType; 059import org.opengis.test.Configuration; 060 061import org.junit.Test; 062import org.junit.runner.RunWith; 063import org.junit.runners.Parameterized; 064 065import static java.lang.StrictMath.*; 066import static org.junit.Assert.*; 067import static org.junit.Assume.*; 068import static org.opengis.test.ToleranceModifiers.NAUTICAL_MILE; 069 070 071/** 072 * Tests {@linkplain MathTransformFactory#createParameterizedTransform(ParameterValueGroup) 073 * parameterized math transforms} from the {@code org.opengis.referencing.operation} package. 074 * Math transform instances are created using the factory given at construction time. 075 * 076 * <p><b>Skipping tests for unsupported operations:</b><br> 077 * If the tested factory throws a {@link NoSuchIdentifierException} during the invocation 078 * of one of the following methods: 079 * 080 * <ul> 081 * <li>{@link MathTransformFactory#getDefaultParameters(String)}</li> 082 * <li>{@link MathTransformFactory#createParameterizedTransform(ParameterValueGroup)}</li> 083 * </ul> 084 * 085 * then the tests is skipped. If any other kind of exception is thrown, or if {@code NoSuchIdentifierException} 086 * is thrown under other circumstances than the invocation of above methods, then the test fails. 087 * 088 * <p><b>Tests and accuracy:</b><br> 089 * By default, every tests expect an accuracy of 1 centimetre. This accuracy matches the precision 090 * of most example points given in the EPSG guidance notice. Implementors can modify the kind of 091 * tests being executed and the tolerance threshold in different ways:</p> 092 * 093 * <ul> 094 * <li>Set some <code>is<<var>Operation</var>>Supported</code> fields to {@code false}.</li> 095 * <li>Override some of the {@code testFoo()} method and set the {@link #tolerance tolerance} field 096 * before to invoke {@code super.testFoo()}.</li> 097 * <li>Override {@link #normalize(DirectPosition, DirectPosition, CalculationType) 098 * normalize(DirectPosition, DirectPosition, CalculationType)}.</li> 099 * <li>Override {@link #assertMatrixEquals(String, Matrix, Matrix, Matrix)}.</li> 100 * </ul> 101 * 102 * <div class="note"><b>Usage example:</b> 103 * in order to specify their factories and run the tests in a JUnit framework, implementors can define 104 * a subclass in their own test suite as in the example below. That example shows also how implementors 105 * can alter some tests (here the tolerance value for the <cite>Lambert Azimuthal Equal Area</cite> projection) 106 * and add more checks to be executed after every tests (here ensuring that the {@linkplain #transform transform} 107 * implements the {@link MathTransform2D} interface): 108 * 109 * <blockquote><pre>import org.junit.*; 110 *import org.junit.runner.RunWith; 111 *import org.junit.runners.JUnit4; 112 *import org.opengis.test.referencing.ParameterizedTransformTest; 113 *import static org.junit.Assert.*; 114 * 115 *@RunWith(JUnit4.class) 116 *public class MyTest extends ParameterizedTransformTest { 117 * public MyTest() { 118 * super(new MyMathTransformFactory()); 119 * } 120 * 121 * @Test 122 * @Override 123 * public void testLambertAzimuthalEqualArea() throws FactoryException, TransformException { 124 * tolerance = 0.1; // Increase the tolerance value to 10 cm. 125 * super.testLambertAzimuthalEqualArea(); 126 * // If more tests specific to this projection are wanted, do them here. 127 * // In this example, we replace the ellipsoid by a sphere and test again. 128 * // Note that spherical formulas can have an error up to 30 km compared 129 * // to ellipsoidal formulas, so we have to relax again the tolerance threshold. 130 * parameters.parameter("semi_minor").setValue(parameters.parameter("semi_major").doubleValue()); 131 * tolerance = 30000; // Increase the tolerance value to 30 km. 132 * super.testLambertAzimuthalEqualArea(); 133 * } 134 * 135 * @After 136 * public void ensureAllTransformAreMath2D() { 137 * assertTrue(transform instanceof MathTransform2D); 138 * } 139 *}</pre></blockquote> 140 * </div> 141 * 142 * @see AffineTransformTest 143 * @see AuthorityFactoryTest 144 * @see org.opengis.test.TestSuite 145 * 146 * @author Martin Desruisseaux (Geomatys) 147 * @version 3.1 148 * @since 3.1 149 */ 150@RunWith(Parameterized.class) 151public strictfp class ParameterizedTransformTest extends TransformTestCase { 152 /** 153 * The default tolerance threshold for comparing the results of direct transforms. 154 * This is set to the precision of coordinate point givens in the EPSG and IGNF 155 * documentation. 156 */ 157 private static final double TRANSFORM_TOLERANCE = 0.01; 158 159 /** 160 * The tolerance threshold for comparing the derivative coefficients. In each column of the 161 * derivative matrix of a map projection, there is typically one value greater than 100000 162 * (100 km - same order of magnitude than the transformed coordinate values) and all other 163 * values are close to zero. However we can not use the {@link #TRANSFORM_TOLERANCE} value 164 * in every cases because the expected derivative coefficients are computed using a numerical 165 * approximation. Some empirical tests have show that the difference between <cite>forward 166 * difference</cite> and <cite>backward difference</cite> can be close to 0.25, so we must 167 * be prepared to increase this tolerance threshold. 168 */ 169 private static final double DERIVATIVE_TOLERANCE = 0.01; 170 171 /** 172 * The delta value to use for computing an approximation of the derivative by finite 173 * difference, in metres. The conversion from metres to degrees is performed using 174 * the standard length of a nautical mile. 175 * 176 * <p>The 100 metres value has been determined empirically as a good compromise for map 177 * projections. Experience suggests that smaller values often <em>decrease</em> the 178 * precision, because of floating point errors when subtracting big numbers that are 179 * close in magnitude.</p> 180 */ 181 private static final double DERIVATIVE_DELTA = 100; 182 183 /** 184 * The factory for creating {@link MathTransform} objects, or {@code null} if none. 185 */ 186 protected final MathTransformFactory mtFactory; 187 188 /** 189 * The parameters of the math transform being tested. This field is set, together with the 190 * {@link #transform transform} field, after the execution of every {@code testFoo()} method 191 * in this class. 192 * 193 * <p>If this field is non-null before a test is run, then those parameters will be used 194 * directly. This allow implementors to alter the parameters before to run the test one 195 * more time.</p> 196 */ 197 protected ParameterValueGroup parameters; 198 199 /** 200 * A description of the test being run. This field is provided only for information purpose 201 * (typically for producing logging or error messages); it is not actually used by the tests. 202 * The value can be: 203 * 204 * <ul> 205 * <li>The name of the target {@link ProjectedCRS} when the {@linkplain #transform transform} 206 * being tested is a map projection</li> 207 * <li>The transformation name when the {@linkplain #transform transform} being tested is a 208 * datum shift operation.</li> 209 * </ul> 210 */ 211 protected String description; 212 213 /** 214 * Returns a default set of factories to use for running the tests. Those factories are given 215 * in arguments to the constructor when this test class is instantiated directly by JUnit (for 216 * example as a {@linkplain org.junit.runners.Suite.SuiteClasses suite} element), instead than 217 * subclassed by the implementor. The factories are fetched as documented in the 218 * {@link #factories(Class[])} javadoc. 219 * 220 * @return the default set of arguments to be given to the {@code ParameterizedTransformTest} constructor. 221 */ 222 @Parameterized.Parameters 223 @SuppressWarnings("unchecked") 224 public static List<Factory[]> factories() { 225 return factories(MathTransformFactory.class); 226 } 227 228 /** 229 * Creates a new test without factory and with the given {@code isFooSupported} flags. 230 * The given array must be the result of a call to {@link #getEnabledKeys(int)}. 231 */ 232 ParameterizedTransformTest(final boolean[] isEnabled) { 233 super(isEnabled); 234 mtFactory = null; 235 } 236 237 /** 238 * Creates a new test using the given factory. If the given factory is {@code null}, 239 * then the tests will be skipped. 240 * 241 * @param factory factory for creating {@link MathTransform} instances. 242 */ 243 public ParameterizedTransformTest(final MathTransformFactory factory) { 244 super(factory); 245 this.mtFactory = factory; 246 } 247 248 /** 249 * Returns information about the configuration of the test which has been run. 250 * This method returns a map containing: 251 * 252 * <ul> 253 * <li>All the entries defined in the {@linkplain TransformTestCase#configuration() parent class}.</li> 254 * <li>All the following values associated to the {@link org.opengis.test.Configuration.Key} of the same name: 255 * <ul> 256 * <li>{@link #mtFactory}</li> 257 * </ul> 258 * </li> 259 * </ul> 260 * 261 * @return {@inheritDoc} 262 */ 263 @Override 264 public Configuration configuration() { 265 final Configuration op = super.configuration(); 266 assertNull(op.put(Configuration.Key.mtFactory, mtFactory)); 267 return op; 268 } 269 270 /** 271 * Invoked for preparing the header of a test failure message. 272 * 273 * @param buffer the buffer in which to append the header. 274 * @param message user-supplied message to append, or {@code null}. 275 */ 276 @Override 277 final void appendErrorHeader(final StringBuilder buffer, final String message) { 278 if (description != null) { 279 buffer.append("Error in “").append(description).append("”: "); 280 } 281 super.appendErrorHeader(buffer, message); 282 } 283 284 /** 285 * Returns the error message for an unsupported operation method. 286 */ 287 private static String unsupportedMethod(final String name) { 288 return "The “" + name + "” operation method is not supported by the tested implementation."; 289 } 290 291 /** 292 * Initialized the {@link #parameters} field to the default values for the given operation method. 293 * If the tested implementation does not support the specified operation method, then the test will 294 * be skipped. 295 */ 296 private void createParameters(final String method) { 297 assumeNotNull(mtFactory); 298 try { 299 parameters = mtFactory.getDefaultParameters(method); 300 } catch (NoSuchIdentifierException e) { 301 assumeNoException(unsupportedMethod(method), e); // Will mark the test as "ignored". 302 } 303 } 304 305 /** 306 * Creates a math transform for the {@linkplain SingleOperation coordinate operation} identified by 307 * {@link SamplePoints#operation} and stores the result in the {@link #transform} field. 308 * The set of allowed codes is documented in second column of the 309 * {@link PseudoEpsgFactory#createParameters(int)} method. 310 * 311 * <p>This method shall also set the {@linkplain TransformTestCase#tolerance tolerance} threshold 312 * in units of the target CRS (typically <var>metres</var> for map projections), and the 313 * {@linkplain #derivativeDeltas derivative deltas} in units of the source CRS (typically 314 * <var>degrees</var> for map projections). The current implementation sets the following values:</p> 315 * 316 * <ul> 317 * <li><p>{@link #tolerance} is sets to {@link #TRANSFORM_TOLERANCE}, unless a greater 318 * tolerance threshold is already set in which case the existing value is left 319 * unchanged.</p></li> 320 * <li><p>{@link #derivativeDeltas} is set to a value in degrees corresponding to 321 * approximately 1 metre on Earth (calculated using the standard nautical mile length). 322 * A finer value can lead to more accurate derivative approximation by the 323 * {@link #verifyDerivative(double[]) verifyDerivative(double...)} method, 324 * at the expense of more sensitivity to the accuracy of the 325 * {@link MathTransform#transform MathTransform.transform(…)} method being tested.</p></li> 326 * </ul> 327 * 328 * @param type either {@code Projection.class} or {@code Transformation.class}. 329 * @throws FactoryException if the math transform can not be created. 330 */ 331 private void createMathTransform(final Class<? extends SingleOperation> type, final SamplePoints sample) 332 throws FactoryException 333 { 334 try { 335 if (parameters == null) { 336 assumeNotNull(mtFactory); 337 parameters = PseudoEpsgFactory.createParameters(mtFactory, sample.operation); 338 validators.validate(parameters); 339 } 340 if (transform == null) { 341 assumeNotNull(mtFactory); 342 transform = mtFactory.createParameterizedTransform(parameters); 343 assertNotNull(description, transform); 344 validators.validate(transform); 345 } 346 } catch (NoSuchIdentifierException e) { 347 /* 348 * If a code was not found, ensure that the factory does not declare that it was 349 * a supported code. If the code was unsupported, then the test will be ignored. 350 */ 351 final String message; 352 if (parameters != null) { 353 final ParameterDescriptorGroup descriptor = parameters.getDescriptor(); 354 if (!Collections.disjoint(Utilities.getNameAndAliases(descriptor), 355 Utilities.getNameAndAliases(mtFactory.getAvailableMethods(type)))) 356 { 357 throw e; // Will mark the test as "failed". 358 } 359 message = unsupportedMethod(Utilities.getName(descriptor)); 360 } else { 361 message = "The “EPSG:" + sample.operation + "” coordinate operation uses the “" + e.getIdentifierCode() 362 + "” method, which is not supported by the tested implementation."; 363 } 364 assumeNoException(message, e); // Will mark the test as "ignored". 365 } 366 /* 367 * Set the tolerance after we have set the transform, 368 * because we need to know the number of dimensions. 369 */ 370 if (type == Projection.class) { 371 setTolerance(ToleranceModifier.PROJECTION); 372 } else if (type == Transformation.class) { 373 setTolerance(ToleranceModifier.GEOGRAPHIC); 374 } else { 375 throw new IllegalArgumentException("Illegal type: " + type); 376 } 377 } 378 379 /** 380 * Initializes the tolerance thresholds to their default values if the users did not 381 * specified his own thresholds. 382 */ 383 final void setTolerance(final ToleranceModifier modifier) { 384 if (toleranceModifier == null) { 385 toleranceModifier = modifier; 386 } 387 if (!(tolerance >= TRANSFORM_TOLERANCE)) { // !(a >= b) instead than (a < b) in order to catch NaN. 388 tolerance = TRANSFORM_TOLERANCE; 389 } 390 if (derivativeDeltas == null) { 391 derivativeDeltas = new double[transform.getSourceDimensions()]; 392 Arrays.fill(derivativeDeltas, DERIVATIVE_DELTA / (60 * NAUTICAL_MILE)); 393 } 394 } 395 396 /** 397 * Applies a unit conversion on the given coordinate values. This method is invoked by 398 * {@link AuthorityFactoryTest} before to test a {@link ProjectedCRS} using different 399 * units than the standard one. In addition to scale the units, this method scales also 400 * the tolerance factor by the same factor. 401 * 402 * @param mode {@link CalculationType#DIRECT_TRANSFORM} for scaling the output units (from 403 * metres to an other linear unit), or {@link CalculationType#INVERSE_TRANSFORM} for 404 * scaling the input units (from degrees to an other angular unit). 405 * @param coordinates the source or expected target points to scale. 406 * @param scale the scale factor, from standard units to the CRS units. 407 */ 408 final void applyUnitConversion(final CalculationType mode, final double[] coordinates, final double scale) { 409 for (int i=coordinates.length; --i>=0;) { 410 coordinates[i] *= scale; 411 } 412 toleranceModifier = ToleranceModifiers.concatenate(toleranceModifier, 413 ToleranceModifiers.scale(EnumSet.of(mode), scale, scale)); 414 } 415 416 /** 417 * Tests the transform consistency using many random points inside the area of validity. 418 * 419 * @throws TransformException if a point can not be transformed. 420 */ 421 final void verifyInDomainOfValidity(final Rectangle2D areaOfValidity) throws TransformException { 422 verifyInDomain(new double[] { 423 areaOfValidity.getMinX(), 424 areaOfValidity.getMinY() 425 }, new double[] { 426 areaOfValidity.getMaxX(), 427 areaOfValidity.getMaxY() 428 }, new int[] { 429 20, 20 430 }, new Random()); 431 } 432 433 /** 434 * Tests the <cite>"Mercator (variant A)"</cite> (EPSG:9804) projection method. 435 * First, this method transforms the point given in the <cite>Example</cite> section of the 436 * EPSG guidance note and compares the {@link MathTransform} result with the expected result. 437 * Next, this method transforms a random set of points in the projection area of validity 438 * and ensures that the {@linkplain MathTransform#inverse() inverse transform} and the 439 * {@linkplain MathTransform#derivative derivatives} are coherent. 440 * 441 * <p>The math transform parameters and the sample coordinates are:</p> 442 * 443 * <table cellspacing="15" summary="Test data"> 444 * <tr valign="top"><td><table class="ogc"> 445 * <caption>CRS characteristics</caption> 446 * <tr><th>Parameter</th> <th>Value</th></tr> 447 * <tr><td>semi-major axis</td> <td>6377397.155 m</td></tr> 448 * <tr><td>semi-minor axis</td> <td>6356078.962818189 m</td></tr> 449 * <tr><td>Latitude of natural origin</td> <td>0.0°</td></tr> 450 * <tr><td>Longitude of natural origin</td> <td>110.0°</td></tr> 451 * <tr><td>Scale factor at natural origin</td> <td>0.997</td></tr> 452 * <tr><td>False easting</td> <td>3900000.0 m</td></tr> 453 * <tr><td>False northing</td> <td>900000.0 m</td></tr> 454 * </table></td><td> 455 * <table class="ogc"> 456 * <caption>Test points</caption> 457 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 458 * <tr align="right"><td>110°E<br>0°N</td> <td>3900000.00 m<br>900000.00 m</td></tr> 459 * <tr align="right"><td>120°E<br>3°S</td> <td>5009726.58 m<br>569150.82 m</td></tr> 460 * </table></td></tr></table> 461 * 462 * @throws FactoryException if the math transform can not be created. 463 * @throws TransformException if the example point can not be transformed. 464 * 465 * @see AuthorityFactoryTest#testEPSG_3002() 466 */ 467 @Test 468 public void testMercator1SP() throws FactoryException, TransformException { 469 description = "Makassar / NEIEZ"; 470 final SamplePoints sample = SamplePoints.forCRS(3002); 471 createMathTransform(Projection.class, sample); 472 verifyTransform(sample.sourcePoints, sample.targetPoints); 473 verifyInDomainOfValidity(sample.areaOfValidity); 474 } 475 476 /** 477 * Tests the <cite>"Mercator (variant B)"</cite> (EPSG:9805) projection method. 478 * First, this method transforms the point given in the <cite>Example</cite> section of the 479 * EPSG guidance note and compares the {@link MathTransform} result with the expected result. 480 * Next, this method transforms a random set of points in the projection area of validity 481 * and ensures that the {@linkplain MathTransform#inverse() inverse transform} and the 482 * {@linkplain MathTransform#derivative derivatives} are coherent. 483 * 484 * <p>The math transform parameters and the sample coordinates are:</p> 485 * 486 * <table cellspacing="15" summary="Test data"> 487 * <tr valign="top"><td><table class="ogc"> 488 * <caption>CRS characteristics</caption> 489 * <tr><th>Parameter</th> <th>Value</th></tr> 490 * <tr><td>semi-major axis</td> <td>6378245.0 m</td></tr> 491 * <tr><td>semi-minor axis</td> <td>6356863.018773047 m</td></tr> 492 * <tr><td>Latitude of 1st standard parallel</td> <td>42.0°</td></tr> 493 * <tr><td>Longitude of natural origin</td> <td>51.0°</td></tr> 494 * <tr><td>False easting</td> <td>0.0 m</td></tr> 495 * <tr><td>False northing</td> <td>0.0 m</td></tr> 496 * </table></td><td> 497 * <table class="ogc"> 498 * <caption>Test points</caption> 499 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 500 * <tr align="right"><td>51°E<br>0°N</td> <td>0.00 m<br>0.00 m</td></tr> 501 * <tr align="right"><td>53°E<br>53°N</td> <td>165704.29 m<br>5171848.07 m</td></tr> 502 * </table></td></tr></table> 503 * 504 * @throws FactoryException if the math transform can not be created. 505 * @throws TransformException if the example point can not be transformed. 506 * 507 * @see AuthorityFactoryTest#testEPSG_3388() 508 */ 509 @Test 510 public void testMercator2SP() throws FactoryException, TransformException { 511 description = "Pulkovo 1942 / Caspian Sea Mercator"; 512 final SamplePoints sample = SamplePoints.forCRS(3388); 513 createMathTransform(Projection.class, sample); 514 verifyTransform(sample.sourcePoints, sample.targetPoints); 515 verifyInDomainOfValidity(sample.areaOfValidity); 516 } 517 518 /** 519 * Tests the <cite>"Mercator (variant C)"</cite> (EPSG:1044) projection method. 520 * First, this method transforms the point given in the <cite>Example</cite> section of the 521 * EPSG guidance note and compares the {@link MathTransform} result with the expected result. 522 * Next, this method transforms a random set of points in the projection area of validity 523 * and ensures that the {@linkplain MathTransform#inverse() inverse transform} and the 524 * {@linkplain MathTransform#derivative derivatives} are coherent. 525 * 526 * <p>The math transform parameters and the sample coordinates are below. 527 * Note that this is similar to {@link #testMercator2SP()}, except that the 528 * <cite>"latitude of false origin"</cite> parameter is set to 42°N.</p> 529 * 530 * <table cellspacing="15" summary="Test data"> 531 * <tr valign="top"><td><table class="ogc"> 532 * <caption>CRS characteristics</caption> 533 * <tr><th>Parameter</th> <th>Value</th></tr> 534 * <tr><td>semi-major axis</td> <td>6378245.0 m</td></tr> 535 * <tr><td>semi-minor axis</td> <td>6356863.018773047 m</td></tr> 536 * <tr><td>Latitude of 1st standard parallel</td> <td>42.0°</td></tr> 537 * <tr><td>Longitude of natural origin</td> <td>51.0°</td></tr> 538 * <tr><td>Latitude of false origin</td> <td>42.0°</td></tr> 539 * <tr><td>Easting at false origin</td> <td>0.0 m</td></tr> 540 * <tr><td>Northing at false origin</td> <td>0.0 m</td></tr> 541 * </table></td><td> 542 * <table class="ogc"> 543 * <caption>Test points</caption> 544 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 545 * <tr align="right"><td>51°E<br>42°N</td> <td>0.00 m<br>0.00 m</td></tr> 546 * <tr align="right"><td>53°E<br>53°N</td> <td>165704.29 m<br>1351950.22 m</td></tr> 547 * </table></td></tr></table> 548 * 549 * @throws FactoryException if the math transform can not be created. 550 * @throws TransformException if the example point can not be transformed. 551 */ 552 @Test 553 public void testMercatorVariantC() throws FactoryException, TransformException { 554 description = "Pulkovo 1942 / Caspian Sea Mercator"; 555 final SamplePoints sample = SamplePoints.forCRS(3388); 556 sample.sourcePoints[1] = 42; // New latitude where we expect a northing of 0 m. 557 sample.targetPoints[3] = 1351950.22; // New Northing value for 53°N. 558 /* 559 * Following is basically a copy-and-paste of PseudoEpsgFactory.createParameters(mtFactory, 3388) 560 * with a different projection ("variant C" instead of "variant B") and one more parameter value 561 * (the "Latitude of false origin"). 562 */ 563 createParameters("Mercator (variant C)"); 564 parameters.parameter("semi_major").setValue(6378245.0); // Krassowski 1940 565 parameters.parameter("semi_minor").setValue(6378245.0 * (1 - 1/298.3)); 566 parameters.parameter("Latitude of 1st standard parallel").setValue(42.0); 567 parameters.parameter("Longitude of natural origin") .setValue(51.0); 568 parameters.parameter("Latitude of false origin") .setValue(42.0); 569 validators.validate(parameters); 570 /* 571 * Following is common to all tests in this class. 572 */ 573 createMathTransform(Projection.class, sample); 574 verifyTransform(sample.sourcePoints, sample.targetPoints); 575 verifyInDomainOfValidity(sample.areaOfValidity); 576 } 577 578 /** 579 * Tests the <cite>"Mercator (Spherical)"</cite> (EPSG:1026) projection method. 580 * First, this method transforms the point given in the <cite>Example</cite> section of the 581 * EPSG guidance note and compares the {@link MathTransform} result with the expected result. 582 * Next, this method transforms a random set of points in the projection area of validity 583 * and ensures that the {@linkplain MathTransform#inverse() inverse transform} and the 584 * {@linkplain MathTransform#derivative derivatives} are coherent. 585 * 586 * <p>The math transform parameters and the sample coordinates are below. 587 * Note that the sample point is the same than for {@link #testPseudoMercator()}, 588 * but with a different result in projected coordinates.</p> 589 * 590 * <table cellspacing="15" summary="Test data"> 591 * <tr valign="top"><td><table class="ogc"> 592 * <caption>CRS characteristics</caption> 593 * <tr><th>Parameter</th> <th>Value</th></tr> 594 * <tr><td>semi-major axis</td> <td>6371007.0 m</td></tr> 595 * <tr><td>semi-minor axis</td> <td>6371007.0 m</td></tr> 596 * <tr><td>Longitude of natural origin</td> <td>0.0°</td></tr> 597 * <tr><td>False easting</td> <td>0.0 m</td></tr> 598 * <tr><td>False northing</td> <td>0.0 m</td></tr> 599 * </table></td><td> 600 * <table class="ogc"> 601 * <caption>Test points</caption> 602 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 603 * <tr align="right"><td>0°E<br>0°N</td> <td>0.00 m<br>0.00 m</td></tr> 604 * <tr align="right"><td>100°20'00.000"W<br>24°22'54.433"N</td> 605 * <td>-11156569.90 m<br>2796869.94 m</td></tr> 606 * </table></td></tr></table> 607 * 608 * @throws FactoryException if the math transform can not be created. 609 * @throws TransformException if the example point can not be transformed. 610 */ 611 @Test 612 public void testMercatorSpherical() throws FactoryException, TransformException { 613 description = "World Spherical Mercator"; 614 final SamplePoints sample = SamplePoints.forCRS(3857); 615 sample.targetPoints[2] = -11156569.90; // New Easting value. 616 sample.targetPoints[3] = 2796869.94; // New Northing value. 617 createParameters("Mercator (Spherical)"); 618 parameters.parameter("semi_major").setValue(6371007.0); 619 parameters.parameter("semi_minor").setValue(6371007.0); 620 validators.validate(parameters); 621 createMathTransform(Projection.class, sample); 622 verifyTransform(sample.sourcePoints, sample.targetPoints); 623 verifyInDomainOfValidity(sample.areaOfValidity); 624 } 625 626 /** 627 * Tests the <cite>"Mercator Popular Visualisation Pseudo Mercator"</cite> (EPSG:1024) projection 628 * method. First, this method transforms the point given in the <cite>Example</cite> section of the 629 * EPSG guidance note and compares the {@link MathTransform} result with the expected result. 630 * Next, this method transforms a random set of points in the projection area of validity 631 * and ensures that the {@linkplain MathTransform#inverse() inverse transform} and the 632 * {@linkplain MathTransform#derivative derivatives} are coherent. 633 * 634 * <p>The math transform parameters and the sample coordinates are:</p> 635 * 636 * <table cellspacing="15" summary="Test data"> 637 * <tr valign="top"><td><table class="ogc"> 638 * <caption>CRS characteristics</caption> 639 * <tr><th>Parameter</th> <th>Value</th></tr> 640 * <tr><td>semi-major axis</td> <td>6378137.0 m</td></tr> 641 * <tr><td>semi-minor axis</td> <td>6356752.314247833 m</td></tr> 642 * <tr><td>Latitude of natural origin</td> <td>0.0°</td></tr> 643 * <tr><td>Longitude of natural origin</td> <td>0.0°</td></tr> 644 * <tr><td>False easting</td> <td>0.0 m</td></tr> 645 * <tr><td>False northing</td> <td>0.0 m</td></tr> 646 * </table></td><td> 647 * <table class="ogc"> 648 * <caption>Test points</caption> 649 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 650 * <tr align="right"><td>0°E<br>0°N</td> <td>0.00 m<br>0.00 m</td></tr> 651 * <tr align="right"><td>100°20'00.000"W<br>24°22'54.433"N</td> 652 * <td>-11169055.58 m<br>2800000.00 m</td></tr> 653 * </table></td></tr></table> 654 * 655 * @throws FactoryException if the math transform can not be created. 656 * @throws TransformException if the example point can not be transformed. 657 * 658 * @see AuthorityFactoryTest#testEPSG_3857() 659 */ 660 @Test 661 public void testPseudoMercator() throws FactoryException, TransformException { 662 description = "WGS 84 / Pseudo-Mercator"; 663 final SamplePoints sample = SamplePoints.forCRS(3857); 664 createMathTransform(Projection.class, sample); 665 verifyTransform(sample.sourcePoints, sample.targetPoints); 666 verifyInDomainOfValidity(sample.areaOfValidity); 667 } 668 669 /** 670 * Tests the <cite>"IGNF:MILLER"</cite> projection. 671 * First, this method transforms the point given below 672 * and compares the {@link MathTransform} result with the expected result. Next, this method 673 * transforms a random set of points in the projection area of validity and ensures that the 674 * {@linkplain MathTransform#inverse() inverse transform} and the 675 * {@linkplain MathTransform#derivative derivatives} are coherent. 676 * 677 * <p>The math transform parameters and the sample coordinates are:</p> 678 * 679 * <table cellspacing="15" summary="Test data"> 680 * <tr valign="top"><td><table class="ogc"> 681 * <caption>CRS characteristics</caption> 682 * <tr><th>Parameter</th> <th>Value</th></tr> 683 * <tr><td>semi_major</td> <td>6378137.0 m</td></tr> 684 * <tr><td>semi_minor</td> <td>6378137.0 m</td></tr> 685 * <tr><td>central_meridian</td> <td>0.0°</td></tr> 686 * <tr><td>false_easting</td> <td>0.0 m</td></tr> 687 * <tr><td>false_northing</td> <td>0.0 m</td></tr> 688 * </table></td><td> 689 * <table class="ogc"> 690 * <caption>Test points</caption> 691 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 692 * <tr align="right"><td>0°E<br>0°N</td> <td>0.00 m<br>0.00 m</td></tr> 693 * <tr align="right"><td>2.478917°E<br>48.805639°N</td> <td>275951.78 m<br>5910061.78 m</td></tr> 694 * </table></td></tr></table> 695 * 696 * @throws FactoryException if the math transform can not be created. 697 * @throws TransformException if the example point can not be transformed. 698 * 699 * @see AuthorityFactoryTest#testIGNF_MILLER() 700 */ 701 @Test 702 public void testMiller() throws FactoryException, TransformException { 703 description = "IGNF:MILLER"; 704 final SamplePoints sample = SamplePoints.forCRS(310642901); 705 createMathTransform(Projection.class, sample); 706 verifyTransform(sample.sourcePoints, sample.targetPoints); 707 verifyInDomainOfValidity(sample.areaOfValidity); 708 } 709 710 /** 711 * Tests the <cite>"Hotine Oblique Mercator (variant B)"</cite> (EPSG:9815) projection method. 712 * First, this method transforms the point given in the <cite>Example</cite> section of the 713 * EPSG guidance note and compares the {@link MathTransform} result with the expected result. 714 * Next, this method transforms a random set of points in the projection area of validity 715 * and ensures that the {@linkplain MathTransform#inverse() inverse transform} and the 716 * {@linkplain MathTransform#derivative derivatives} are coherent. 717 * 718 * <p>The math transform parameters and the sample coordinates are:</p> 719 * 720 * <table cellspacing="15" summary="Test data"> 721 * <tr valign="top"><td><table class="ogc"> 722 * <caption>CRS characteristics</caption> 723 * <tr><th>Parameter</th> <th>Value</th></tr> 724 * <tr><td>semi-major axis</td> <td>6377298.556 m</td></tr> 725 * <tr><td>semi-minor axis</td> <td>6356097.550300896 m</td></tr> 726 * <tr><td>Latitude of projection centre</td> <td>4.0°</td></tr> 727 * <tr><td>Longitude of projection centre</td> <td>109.6855202029758°</td></tr> 728 * <tr><td>Azimuth of initial line</td> <td>53.31582047222222°</td></tr> 729 * <tr><td>Angle from Rectified to Skew Grid</td> <td>53.13010236111111°</td></tr> 730 * <tr><td>Scale factor on initial line</td> <td>0.99984</td></tr> 731 * <tr><td>Easting at projection centre</td> <td>590476.87 m</td></tr> 732 * <tr><td>Northing at projection centre</td> <td>442857.65 m</td></tr> 733 * </table></td><td> 734 * <table class="ogc"> 735 * <caption>Test points</caption> 736 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 737 * <tr align="right"><td>115°E<br>4°N</td> <td>590476.87 m<br>442857.65 m</td></tr> 738 * <tr align="right"><td>115°48'19.8196"E<br>5°23'14.1129"N</td> 739 * <td>679245.73 m<br>596562.78 m</td></tr> 740 * </table></td></tr></table> 741 * 742 * @throws FactoryException if the math transform can not be created. 743 * @throws TransformException if the example point can not be transformed. 744 * 745 * @see AuthorityFactoryTest#testEPSG_29873() 746 */ 747 @Test 748 public void testHotineObliqueMercator() throws FactoryException, TransformException { 749 description = "Timbalai 1948 / RSO Borneo (m)"; 750 final SamplePoints sample = SamplePoints.forCRS(29873); 751 createMathTransform(Projection.class, sample); 752 verifyTransform(sample.sourcePoints, sample.targetPoints); 753 verifyInDomainOfValidity(sample.areaOfValidity); 754 } 755 756 /** 757 * Tests the <cite>"Transverse Mercator"</cite> (EPSG:9807) projection method. 758 * First, this method transforms the point given in the <cite>Example</cite> section of the 759 * EPSG guidance note and compares the {@link MathTransform} result with the expected result. 760 * Next, this method transforms a random set of points in the projection area of validity 761 * and ensures that the {@linkplain MathTransform#inverse() inverse transform} and the 762 * {@linkplain MathTransform#derivative derivatives} are coherent. 763 * 764 * <p>The math transform parameters and the sample coordinates are:</p> 765 * 766 * <table cellspacing="15" summary="Test data"> 767 * <tr valign="top"><td><table class="ogc"> 768 * <caption>CRS characteristics</caption> 769 * <tr><th>Parameter</th> <th>Value</th></tr> 770 * <tr><td>semi-major axis</td> <td>6377563.396 m</td></tr> 771 * <tr><td>semi-minor axis</td> <td>6356256.908909849 m</td></tr> 772 * <tr><td>Latitude of natural origin</td> <td>49.0°</td></tr> 773 * <tr><td>Longitude of natural origin</td> <td>-2.0°</td></tr> 774 * <tr><td>Scale factor at natural origin</td> <td>0.9996012717</td></tr> 775 * <tr><td>False easting</td> <td>400000.0 m</td></tr> 776 * <tr><td>False northing</td> <td>-100000.0 m</td></tr> 777 * </table></td><td> 778 * <table class="ogc"> 779 * <caption>Test points</caption> 780 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 781 * <tr align="right"><td>2°W<br>49°N</td> <td>400000.00 m<br>-100000.00 m</td></tr> 782 * <tr align="right"><td>00°30'E<br>50°30'N</td> <td>577274.98 m<br>69740.49 m</td></tr> 783 * </table></td></tr></table> 784 * 785 * @throws FactoryException if the math transform can not be created. 786 * @throws TransformException if the example point can not be transformed. 787 * 788 * @see AuthorityFactoryTest#testEPSG_27700() 789 */ 790 @Test 791 public void testTransverseMercator() throws FactoryException, TransformException { 792 description = "OSGB 1936 / British National Grid"; 793 final SamplePoints sample = SamplePoints.forCRS(27700); 794 createMathTransform(Projection.class, sample); 795 verifyTransform(sample.sourcePoints, sample.targetPoints); 796 verifyInDomainOfValidity(sample.areaOfValidity); 797 } 798 799 /** 800 * Tests the <cite>Transverse Mercator (South Orientated)</cite> (EPSG:9808) projection method. 801 * First, this method transforms the point given in the <cite>Example</cite> section of the 802 * EPSG guidance note and compares the {@link MathTransform} result with the expected result. 803 * Next, this method transforms a random set of points in the projection area of validity 804 * and ensures that the {@linkplain MathTransform#inverse() inverse transform} and the 805 * {@linkplain MathTransform#derivative derivatives} are coherent. 806 * 807 * <p>The math transform parameters and the sample coordinates are:</p> 808 * 809 * <table cellspacing="15" summary="Test data"> 810 * <tr valign="top"><td><table class="ogc"> 811 * <caption>CRS characteristics</caption> 812 * <tr><th>Parameter</th> <th>Value</th></tr> 813 * <tr><td>semi-major axis</td> <td>6378137.0 m</td></tr> 814 * <tr><td>semi-minor axis</td> <td>6356752.314247833 m</td></tr> 815 * <tr><td>Latitude of natural origin</td> <td>0°</td></tr> 816 * <tr><td>Longitude of natural origin</td> <td>29°</td></tr> 817 * <tr><td>Scale factor at natural origin</td> <td>1</td></tr> 818 * <tr><td>False easting</td> <td>0 m</td></tr> 819 * <tr><td>False northing</td> <td>0 m</td></tr> 820 * </table></td><td> 821 * <table class="ogc"> 822 * <caption>Test points</caption> 823 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 824 * <tr align="right"><td>20°E<br>0°S</td> <td>0 m<br>0 m</td></tr> 825 * <tr align="right"><td>28°16'57.479"E<br>25°43'55.302"S</td> <td>71984.48 m<br>2847342.74 m</td></tr> 826 * </table></td></tr></table> 827 * 828 * @throws FactoryException if the math transform can not be created. 829 * @throws TransformException if the example point can not be transformed. 830 */ 831 @Test 832 public void testTransverseMercatorSouthOrientated() throws FactoryException, TransformException { 833 description = "Hartebeesthoek94 / Lo29"; 834 final SamplePoints sample = SamplePoints.forCRS(2053); 835 createMathTransform(Projection.class, sample); 836 /* 837 * In this particular case we have a conflict between the change of axis direction performed by the 838 * "Transverse Mercator (South Orientated)" operation method and the (east, north) axis directions 839 * documented in the MathTransformFactory.createParameterizedTransform(…) method. We do not mandate 840 * any particular behavior at this time, so we have to determine what the implementor choose to do, 841 * by projecting a point in the south hemisphere and checking the sign of the result. 842 */ 843 double[] expected = sample.targetPoints; 844 final double[] check = new double[] {-0.5, -0.5}; 845 transform.transform(check, 0, check, 0, 1); 846 if (check[1] < 0) { 847 /* 848 * Point in the South hemisphere have negative y values. In other words, the implementor chooses to 849 * keep (east,north) directions instead of (west,south). Reverse the sign of all expected coordinates. 850 */ 851 expected = expected.clone(); 852 for (int i=0; i<expected.length; i++) { 853 expected[i] = -expected[i]; 854 } 855 } 856 verifyTransform(sample.sourcePoints, expected); 857 verifyInDomainOfValidity(sample.areaOfValidity); 858 } 859 860 /** 861 * Tests the <cite>"Cassini-Soldner"</cite> (EPSG:9806) projection method. 862 * First, this method transforms the point given in the <cite>Example</cite> section of the 863 * EPSG guidance note and compares the {@link MathTransform} result with the expected result. 864 * Next, this method transforms a random set of points in the projection area of validity 865 * and ensures that the {@linkplain MathTransform#inverse() inverse transform} and the 866 * {@linkplain MathTransform#derivative derivatives} are coherent. 867 * 868 * <p>The math transform parameters and the sample coordinates are:</p> 869 * 870 * <table cellspacing="15" summary="Test data"> 871 * <tr valign="top"><td><table class="ogc"> 872 * <caption>CRS characteristics</caption> 873 * <tr><th>Parameter</th> <th>Value</th></tr> 874 * <tr><td>semi-major axis</td> <td>6378350.8704 m</td></tr> 875 * <tr><td>semi-minor axis</td> <td>6356675.0184 m</td></tr> 876 * <tr><td>Latitude of natural origin</td> <td>10.441666666666666°</td></tr> 877 * <tr><td>Longitude of natural origin</td> <td>-61.33333333333333°</td></tr> 878 * <tr><td>False easting</td> <td>86501.46392052001 m</td></tr> 879 * <tr><td>False northing</td> <td>65379.0134283 m</td></tr> 880 * </table></td><td> 881 * <table class="ogc"> 882 * <caption>Test points</caption> 883 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 884 * <tr align="right"><td>61°20'00"W<br>10°26'30"N</td> <td>430000.00 links<br>325000.00 links</td></tr> 885 * <tr align="right"><td>60°00'00"W<br>10°00'00"N</td> <td>66644.94 links<br>82536.22 links</td></tr> 886 * </table> 887 * <p align="right">1 link = 0.66 feet<br>1 feet = 0.3048 metre</p> 888 * </td></tr></table> 889 * 890 * @throws FactoryException if the math transform can not be created. 891 * @throws TransformException if the example point can not be transformed. 892 * 893 * @see AuthorityFactoryTest#testEPSG_2314() 894 */ 895 @Test 896 public void testCassiniSoldner() throws FactoryException, TransformException { 897 description = "Trinidad 1903 / Trinidad Grid"; 898 final SamplePoints sample = SamplePoints.forCRS(2314); 899 createMathTransform(Projection.class, sample); 900 verifyTransform(sample.sourcePoints, sample.targetPoints); 901 verifyInDomainOfValidity(sample.areaOfValidity); 902 } 903 904 /** 905 * Tests the <cite>"Lambert Conic Conformal (1SP)"</cite> (EPSG:9801) projection method. 906 * First, this method transforms the point given in the <cite>Example</cite> section of the 907 * EPSG guidance note and compares the {@link MathTransform} result with the expected result. 908 * Next, this method transforms a random set of points in the projection area of validity 909 * and ensures that the {@linkplain MathTransform#inverse() inverse transform} and the 910 * {@linkplain MathTransform#derivative derivatives} are coherent. 911 * 912 * <p>The math transform parameters and the sample coordinates are:</p> 913 * 914 * <table cellspacing="15" summary="Test data"> 915 * <tr valign="top"><td><table class="ogc"> 916 * <caption>CRS characteristics</caption> 917 * <tr><th>Parameter</th> <th>Value</th></tr> 918 * <tr><td>semi-major axis</td> <td>6378206.4 m</td></tr> 919 * <tr><td>semi-minor axis</td> <td>6356583.8 m</td></tr> 920 * <tr><td>Latitude of natural origin</td> <td>18.0°</td></tr> 921 * <tr><td>Longitude of natural origin</td> <td>-77.0°</td></tr> 922 * <tr><td>Scale factor at natural origin</td> <td>1.0</td></tr> 923 * <tr><td>False easting</td> <td>250000.0 m</td></tr> 924 * <tr><td>False northing</td> <td>150000.0 m</td></tr> 925 * </table></td><td> 926 * <table class="ogc"> 927 * <caption>Test points</caption> 928 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 929 * <tr align="right"><td>77°W<br>18°N</td> <td>250000.00 m<br>150000.00 m</td></tr> 930 * <tr align="right"><td>76°56'37.26"W<br>17°55'55.80"N</td> 931 * <td>255966.58 m<br>142493.51 m</td></tr> 932 * </table></td></tr></table> 933 * 934 * @throws FactoryException if the math transform can not be created. 935 * @throws TransformException if the example point can not be transformed. 936 * 937 * @see AuthorityFactoryTest#testEPSG_24200() 938 */ 939 @Test 940 public void testLambertConicConformal1SP() throws FactoryException, TransformException { 941 description = "JAD69 / Jamaica National Grid"; 942 final SamplePoints sample = SamplePoints.forCRS(24200); 943 createMathTransform(Projection.class, sample); 944 verifyTransform(sample.sourcePoints, sample.targetPoints); 945 verifyInDomainOfValidity(sample.areaOfValidity); 946 } 947 948 /** 949 * Tests the <cite>"Lambert Conic Conformal (2SP)"</cite> (EPSG:9802) projection method. 950 * First, this method transforms the point given in the <cite>Example</cite> section of the 951 * EPSG guidance note and compares the {@link MathTransform} result with the expected result. 952 * Next, this method transforms a random set of points in the projection area of validity 953 * and ensures that the {@linkplain MathTransform#inverse() inverse transform} and the 954 * {@linkplain MathTransform#derivative derivatives} are coherent. 955 * 956 * <p>The math transform parameters and the sample coordinates are:</p> 957 * 958 * <table cellspacing="15" summary="Test data"> 959 * <tr valign="top"><td><table class="ogc"> 960 * <caption>CRS characteristics</caption> 961 * <tr><th>Parameter</th> <th>Value</th></tr> 962 * <tr><td>semi-major axis</td> <td>6378206.4 m</td></tr> 963 * <tr><td>semi-minor axis</td> <td>6356583.8 m</td></tr> 964 * <tr><td>Latitude of false origin</td> <td>27.833333333333333°</td></tr> 965 * <tr><td>Longitude of false origin</td> <td>-99.0°</td></tr> 966 * <tr><td>Latitude of 1st standard parallel</td> <td>28.383333333333333°</td></tr> 967 * <tr><td>Latitude of 2nd standard parallel</td> <td>30.283333333333333°</td></tr> 968 * <tr><td>Easting at false origin</td> <td>609601.2192024385 m</td></tr> 969 * <tr><td>Northing at false origin</td> <td>0.0 m</td></tr> 970 * </table></td><td> 971 * <table class="ogc"> 972 * <caption>Test points</caption> 973 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 974 * <tr align="right"><td>99°00'W<br>27°30'N</td> <td>2000000.00 US feet<br>0 US feet</td></tr> 975 * <tr align="right"><td>96°00'W<br>28°30'N</td> <td>2963503.91 US feet<br>254759.80 US feet</td></tr> 976 * </table> 977 * <p align="right">1 metre = 3.2808333… US feet</p> 978 * </td></tr></table> 979 * 980 * @throws FactoryException if the math transform can not be created. 981 * @throws TransformException if the example point can not be transformed. 982 * 983 * @see AuthorityFactoryTest#testEPSG_32040() 984 */ 985 @Test 986 public void testLambertConicConformal2SP() throws FactoryException, TransformException { 987 description = "NAD27 / Texas South Central"; 988 final SamplePoints sample = SamplePoints.forCRS(32040); 989 createMathTransform(Projection.class, sample); 990 verifyTransform(sample.sourcePoints, sample.targetPoints); 991 verifyInDomainOfValidity(sample.areaOfValidity); 992 } 993 994 /** 995 * Tests the <cite>"Lambert Conic Conformal (2SP Belgium)"</cite> (EPSG:9803) projection method. 996 * First, this method transforms the point given in the <cite>Example</cite> section of the 997 * EPSG guidance note and compares the {@link MathTransform} result with the expected result. 998 * Next, this method transforms a random set of points in the projection area of validity 999 * and ensures that the {@linkplain MathTransform#inverse() inverse transform} and the 1000 * {@linkplain MathTransform#derivative derivatives} are coherent. 1001 * 1002 * <p>The math transform parameters and the sample coordinates are:</p> 1003 * 1004 * <table cellspacing="15" summary="Test data"> 1005 * <tr valign="top"><td><table class="ogc"> 1006 * <caption>CRS characteristics</caption> 1007 * <tr><th>Parameter</th> <th>Value</th></tr> 1008 * <tr><td>semi-major axis</td> <td>6378388.0 m</td></tr> 1009 * <tr><td>semi-minor axis</td> <td>6356911.9461279465 m</td></tr> 1010 * <tr><td>Latitude of false origin</td> <td>90.0°</td></tr> 1011 * <tr><td>Longitude of false origin</td> <td>4.356939722222222°</td></tr> 1012 * <tr><td>Latitude of 1st standard parallel</td> <td>49.83333333333333°</td></tr> 1013 * <tr><td>Latitude of 2nd standard parallel</td> <td>51.16666666666667°</td></tr> 1014 * <tr><td>Easting at false origin</td> <td>150000.01256 m</td></tr> 1015 * <tr><td>Northing at false origin</td> <td>5400088.4378 m</td></tr> 1016 * </table></td><td> 1017 * <table class="ogc"> 1018 * <caption>Test points</caption> 1019 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 1020 * <tr align="right"><td>4°21'24.983"E<br>90°00'00.000"N</td> <td>150000.01 m<br>5400088.44 m</td></tr> 1021 * <tr align="right"><td>5°48'26.533"E<br>50°40'46.461"N</td> <td>251763.20 m<br>153034.13 m</td></tr> 1022 * </table></td></tr></table> 1023 * 1024 * @throws FactoryException if the math transform can not be created. 1025 * @throws TransformException if the example point can not be transformed. 1026 * 1027 * @see AuthorityFactoryTest#testEPSG_31300() 1028 */ 1029 @Test 1030 public void testLambertConicConformalBelgium() throws FactoryException, TransformException { 1031 description = "Belge 1972 / Belge Lambert 72"; 1032 final SamplePoints sample = SamplePoints.forCRS(31300); 1033 createMathTransform(Projection.class, sample); 1034 verifyTransform(sample.sourcePoints, sample.targetPoints); 1035 verifyInDomainOfValidity(sample.areaOfValidity); 1036 } 1037 1038 /** 1039 * Tests the <cite>"Lambert Conic Conformal (2SP Michigan)"</cite> (EPSG:1051) projection method. 1040 * First, this method transforms the point given in the <cite>Example</cite> section of the 1041 * EPSG guidance note and compares the {@link MathTransform} result with the expected result. 1042 * Next, this method transforms a random set of points in the projection area of validity 1043 * and ensures that the {@linkplain MathTransform#inverse() inverse transform} and the 1044 * {@linkplain MathTransform#derivative derivatives} are coherent. 1045 * 1046 * <p>The math transform parameters and the sample coordinates are:</p> 1047 * 1048 * <table cellspacing="15" summary="Test data"> 1049 * <tr valign="top"><td><table class="ogc"> 1050 * <caption>CRS characteristics</caption> 1051 * <tr><th>Parameter</th> <th>Value</th></tr> 1052 * <tr><td>semi-major axis</td> <td>6378206.4 m</td></tr> 1053 * <tr><td>semi-minor axis</td> <td>6356583.8 m</td></tr> 1054 * <tr><td>Latitude of false origin</td> <td>43.316666666666667°</td></tr> 1055 * <tr><td>Longitude of false origin</td> <td>-84.333333333333333°</td></tr> 1056 * <tr><td>Latitude of 1st standard parallel</td> <td>44.183333333333333°</td></tr> 1057 * <tr><td>Latitude of 2nd standard parallel</td> <td>45.7°</td></tr> 1058 * <tr><td>Easting at false origin</td> <td>609601.2192024385 m</td></tr> 1059 * <tr><td>Northing at false origin</td> <td>0.0 m</td></tr> 1060 * </table></td><td> 1061 * <table class="ogc"> 1062 * <caption>Test points</caption> 1063 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 1064 * <tr align="right"><td>84°20'W<br>43°19'N</td> <td>2000000.00 US feet<br>0 US feet</td></tr> 1065 * <tr align="right"><td>83°10"W<br>43°45'N</td> <td>2308335.75 US feet<br>160210.48 US feet</td></tr> 1066 * </table> 1067 * <p align="right">1 metre = 3.2808333… US feet</p> 1068 * </td></tr></table> 1069 * 1070 * @throws FactoryException if the math transform can not be created. 1071 * @throws TransformException if the example point can not be transformed. 1072 */ 1073 @Test 1074 public void testLambertConicConformalMichigan() throws FactoryException, TransformException { 1075 description = "NAD27 / Michigan Central"; 1076 final SamplePoints sample = SamplePoints.forCRS(6201); 1077 createMathTransform(Projection.class, sample); 1078 verifyTransform(sample.sourcePoints, sample.targetPoints); 1079 verifyInDomainOfValidity(sample.areaOfValidity); 1080 } 1081 1082 /** 1083 * Tests the <cite>"Lambert Azimuthal Equal Area"</cite> (EPSG:9820) projection method. 1084 * First, this method transforms the point given in the <cite>Example</cite> section of the 1085 * EPSG guidance note and compares the {@link MathTransform} result with the expected result. 1086 * Next, this method transforms a random set of points in the projection area of validity 1087 * and ensures that the {@linkplain MathTransform#inverse() inverse transform} and the 1088 * {@linkplain MathTransform#derivative derivatives} are coherent. 1089 * 1090 * <p>The math transform parameters and the sample coordinates are:</p> 1091 * 1092 * <table cellspacing="15" summary="Test data"> 1093 * <tr valign="top"><td><table class="ogc"> 1094 * <caption>CRS characteristics</caption> 1095 * <tr><th>Parameter</th> <th>Value</th></tr> 1096 * <tr><td>semi-major axis</td> <td>6378137.0 m</td></tr> 1097 * <tr><td>semi-minor axis</td> <td>6356752.314140284 m</td></tr> 1098 * <tr><td>Latitude of natural origin</td> <td>52.0°</td></tr> 1099 * <tr><td>Longitude of natural origin</td> <td>10.0°</td></tr> 1100 * <tr><td>False easting</td> <td>4321000.0 m</td></tr> 1101 * <tr><td>False northing</td> <td>3210000.0 m</td></tr> 1102 * </table></td><td> 1103 * <table class="ogc"> 1104 * <caption>Test points</caption> 1105 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 1106 * <tr align="right"><td>10°E<br>52°N</td> <td>4321000.00 m<br>3210000.00 m</td></tr> 1107 * <tr align="right"><td>5°E<br>50°N</td> <td>3962799.45 m<br>2999718.85 m</td></tr> 1108 * </table></td></tr></table> 1109 * 1110 * @throws FactoryException if the math transform can not be created. 1111 * @throws TransformException if the example point can not be transformed. 1112 * 1113 * @see AuthorityFactoryTest#testEPSG_3035() 1114 */ 1115 @Test 1116 public void testLambertAzimuthalEqualArea() throws FactoryException, TransformException { 1117 description = "ETRS89 / LAEA Europe"; 1118 final SamplePoints sample = SamplePoints.forCRS(3035); 1119 createMathTransform(Projection.class, sample); 1120 verifyTransform(sample.sourcePoints, sample.targetPoints); 1121 verifyInDomainOfValidity(sample.areaOfValidity); 1122 } 1123 1124 /** 1125 * Tests the <cite>"Polar Stereographic (variant A)"</cite> (EPSG:9810) projection method. 1126 * First, this method transforms the point given in the <cite>Example</cite> section of the 1127 * EPSG guidance note and compares the {@link MathTransform} result with the expected result. 1128 * Next, this method transforms a random set of points in the projection area of validity 1129 * and ensures that the {@linkplain MathTransform#inverse() inverse transform} and the 1130 * {@linkplain MathTransform#derivative derivatives} are coherent. 1131 * 1132 * <p>The math transform parameters and the sample coordinates are:</p> 1133 * 1134 * <table cellspacing="15" summary="Test data"> 1135 * <tr valign="top"><td><table class="ogc"> 1136 * <caption>CRS characteristics</caption> 1137 * <tr><th>Parameter</th> <th>Value</th></tr> 1138 * <tr><td>semi-major axis</td> <td>6378137.0 m</td></tr> 1139 * <tr><td>semi-minor axis</td> <td>6356752.314247833 m</td></tr> 1140 * <tr><td>Latitude of natural origin</td> <td>90.0°</td></tr> 1141 * <tr><td>Longitude of natural origin</td> <td>0.0°</td></tr> 1142 * <tr><td>Scale factor at natural origin</td> <td>0.994</td></tr> 1143 * <tr><td>False easting</td> <td>2000000.0 m</td></tr> 1144 * <tr><td>False northing</td> <td>2000000.0 m</td></tr> 1145 * </table></td><td> 1146 * <table class="ogc"> 1147 * <caption>Test points</caption> 1148 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 1149 * <tr align="right"><td>0°E<br>90°N</td> <td>2000000.00 m<br>2000000.00 m</td></tr> 1150 * <tr align="right"><td>44°E<br>73°N</td> <td>3320416.75 m<br>632668.43 m</td></tr> 1151 * </table></td></tr></table> 1152 * 1153 * @throws FactoryException if the math transform can not be created. 1154 * @throws TransformException if the example point can not be transformed. 1155 * 1156 * @see AuthorityFactoryTest#testEPSG_5041() 1157 * @see AuthorityFactoryTest#testEPSG_32661() 1158 */ 1159 @Test 1160 public void testPolarStereographicA() throws FactoryException, TransformException { 1161 description = "WGS 84 / UPS North (E,N)"; 1162 final SamplePoints sample = SamplePoints.forCRS(5041); 1163 createMathTransform(Projection.class, sample); 1164 verifyTransform(sample.sourcePoints, sample.targetPoints); 1165 verifyInDomainOfValidity(sample.areaOfValidity); 1166 } 1167 1168 /** 1169 * Tests the <cite>"Polar Stereographic (variant B)"</cite> (EPSG:9829) projection method. 1170 * First, this method transforms the point given in the <cite>Example</cite> section of the 1171 * EPSG guidance note and compares the {@link MathTransform} result with the expected result. 1172 * Next, this method transforms a random set of points in the projection area of validity 1173 * and ensures that the {@linkplain MathTransform#inverse() inverse transform} and the 1174 * {@linkplain MathTransform#derivative derivatives} are coherent. 1175 * 1176 * <p>The math transform parameters and the sample coordinates are:</p> 1177 * 1178 * <table cellspacing="15" summary="Test data"> 1179 * <tr valign="top"><td><table class="ogc"> 1180 * <caption>CRS characteristics</caption> 1181 * <tr><th>Parameter</th> <th>Value</th></tr> 1182 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 1183 * <tr><td>semi-major axis</td> <td>6378137.0 m</td></tr> 1184 * <tr><td>semi-minor axis</td> <td>6356752.314247833 m</td></tr> 1185 * <tr><td>Latitude of standard parallel</td> <td>-71.0°</td></tr> 1186 * <tr><td>Longitude of origin</td> <td>70.0°</td></tr> 1187 * <tr><td>False easting</td> <td>6000000.0 m</td></tr> 1188 * <tr><td>False northing</td> <td>6000000.0 m</td></tr> 1189 * </table></td><td> 1190 * <table class="ogc"> 1191 * <caption>Test points</caption> 1192 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 1193 * <tr align="right"><td>70°E<br>90°S</td> <td>6000000.00 m<br>6000000.00 m</td></tr> 1194 * <tr align="right"><td>120°E<br>75°S</td> <td>7255380.79 m<br>7053389.56 m</td></tr> 1195 * </table></td></tr></table> 1196 * 1197 * @throws FactoryException if the math transform can not be created. 1198 * @throws TransformException if the example point can not be transformed. 1199 * 1200 * @see AuthorityFactoryTest#testEPSG_3032() 1201 */ 1202 @Test 1203 public void testPolarStereographicB() throws FactoryException, TransformException { 1204 description = "Australian Antarctic Polar Stereographic"; 1205 final SamplePoints sample = SamplePoints.forCRS(3032); 1206 createMathTransform(Projection.class, sample); 1207 verifyTransform(sample.sourcePoints, sample.targetPoints); 1208 verifyInDomainOfValidity(sample.areaOfValidity); 1209 } 1210 1211 /** 1212 * Tests the <cite>"Polar Stereographic (variant C)"</cite> (EPSG:9830) projection method. 1213 * First, this method transforms the point given in the <cite>Example</cite> section of the 1214 * EPSG guidance note and compares the {@link MathTransform} result with the expected result. 1215 * Next, this method transforms a random set of points in the projection area of validity 1216 * and ensures that the {@linkplain MathTransform#inverse() inverse transform} and the 1217 * {@linkplain MathTransform#derivative derivatives} are coherent. 1218 * 1219 * <p>The math transform parameters and the sample coordinates are:</p> 1220 * 1221 * <table cellspacing="15" summary="Test data"> 1222 * <tr valign="top"><td><table class="ogc"> 1223 * <caption>CRS characteristics</caption> 1224 * <tr><th>Parameter</th> <th>Value</th></tr> 1225 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 1226 * <tr><td>semi-major axis</td> <td>6378388.0 m</td></tr> 1227 * <tr><td>semi-minor axis</td> <td>6356911.9461279465 m</td></tr> 1228 * <tr><td>Latitude of standard parallel</td> <td>-67°</td></tr> 1229 * <tr><td>Longitude of origin</td> <td>140°</td></tr> 1230 * <tr><td>False easting</td> <td>300000 m</td></tr> 1231 * <tr><td>False northing</td> <td>200000 m</td></tr> 1232 * </table></td><td> 1233 * <table class="ogc"> 1234 * <caption>Test points</caption> 1235 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 1236 * <tr align="right"><td>67°E<br>90°S</td> <td>300000.00 m<br>200000.00 m</td></tr> 1237 * <tr align="right"><td>140°04'17.040"E<br>66°36'18.820"S</td> <td>303169.52 m<br>244055.72 m</td></tr> 1238 * </table></td></tr></table> 1239 * 1240 * @throws FactoryException if the math transform can not be created. 1241 * @throws TransformException if the example point can not be transformed. 1242 * 1243 * @see AuthorityFactoryTest#testEPSG_3032() 1244 */ 1245 @Test 1246 public void testPolarStereographicC() throws FactoryException, TransformException { 1247 description = "Petrels 1972 / Terre Adelie Polar Stereographic"; 1248 final SamplePoints sample = SamplePoints.forCRS(2985); 1249 createMathTransform(Projection.class, sample); 1250 verifyTransform(sample.sourcePoints, sample.targetPoints); 1251 verifyInDomainOfValidity(sample.areaOfValidity); 1252 } 1253 1254 /** 1255 * Tests the <cite>"Oblique Stereographic"</cite> (EPSG:9809) projection method. 1256 * First, this method transforms the point given in the <cite>Example</cite> section of the 1257 * EPSG guidance note and compares the {@link MathTransform} result with the expected result. 1258 * Next, this method transforms a random set of points in the projection area of validity 1259 * and ensures that the {@linkplain MathTransform#inverse() inverse transform} and the 1260 * {@linkplain MathTransform#derivative derivatives} are coherent. 1261 * 1262 * <p>The math transform parameters and the sample coordinates are:</p> 1263 * 1264 * <table cellspacing="15" summary="Test data"> 1265 * <tr valign="top"><td><table class="ogc"> 1266 * <caption>CRS characteristics</caption> 1267 * <tr><th>Parameter</th> <th>Value</th></tr> 1268 * <tr><td>semi-major axis</td> <td>6377397.155 m</td></tr> 1269 * <tr><td>semi-minor axis</td> <td>6356078.9626186555 m</td></tr> 1270 * <tr><td>Latitude of natural origin</td> <td>52.15616055555556°</td></tr> 1271 * <tr><td>Longitude of natural origin</td> <td>5.38763888888889°</td></tr> 1272 * <tr><td>Scale factor at natural origin</td> <td>0.9999079</td></tr> 1273 * <tr><td>False easting</td> <td>155000.0 m</td></tr> 1274 * <tr><td>False northing</td> <td>463000.0 m</td></tr> 1275 * </table></td><td> 1276 * <table class="ogc"> 1277 * <caption>Test points</caption> 1278 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 1279 * <tr align="right"><td>5°23'15.500"E<br>52°09'22.178"N</td> <td>155000.000 m<br>463000.000 m</td></tr> 1280 * <tr align="right"><td>6°E<br>53°N</td> <td>196105.283 m<br>557057.739 m</td></tr> 1281 * </table></td></tr></table> 1282 * 1283 * @throws FactoryException if the math transform can not be created. 1284 * @throws TransformException if the example point can not be transformed. 1285 * 1286 * @see AuthorityFactoryTest#testEPSG_28992() 1287 */ 1288 @Test 1289 public void testObliqueStereographic() throws FactoryException, TransformException { 1290 description = "Amersfoort / RD New"; 1291 final SamplePoints sample = SamplePoints.forCRS(28992); 1292 createMathTransform(Projection.class, sample); 1293 verifyTransform(sample.sourcePoints, sample.targetPoints); 1294 verifyInDomainOfValidity(sample.areaOfValidity); 1295 } 1296 1297 /** 1298 * Tests the <cite>"American Polyconic"</cite> (EPSG:9818) projection. 1299 * First, this method transforms the some of the points given in Table 19, p 132 of 1300 * <a href="http://pubs.er.usgs.gov/usgspubs/pp/pp1395">Map Projections, a working manual</a> 1301 * by John P.Snyder. Next, this method transforms a random set of points in the projection 1302 * area of validity and ensures that the {@linkplain MathTransform#inverse() inverse transform} 1303 * and the {@linkplain MathTransform#derivative derivatives} are coherent. 1304 * 1305 * <p>The math transform parameters and the sample coordinates are:</p> 1306 * 1307 * <table cellspacing="15" summary="Test data"> 1308 * <tr valign="top"><td><table class="ogc"> 1309 * <caption>CRS characteristics</caption> 1310 * <tr><th>Parameter</th> <th>Value</th></tr> 1311 * <tr><td>semi-major axis</td> <td>6378206.4 m</td></tr> 1312 * <tr><td>semi-minor axis</td> <td>6356583.8 m</td></tr> 1313 * <tr><td>Latitude of natural origin</td> <td>0.0°</td></tr> 1314 * <tr><td>Longitude of natural origin</td> <td>0.0°</td></tr> 1315 * <tr><td>False easting</td> <td>0.0 m</td></tr> 1316 * <tr><td>False northing</td> <td>0.0 m</td></tr> 1317 * </table></td><td> 1318 * <table class="ogc"> 1319 * <caption>Test points</caption> 1320 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 1321 * <tr align="right"><td>See source</td> <td>See source</td></tr> 1322 * </table></td></tr></table> 1323 * 1324 * @throws FactoryException if the math transform can not be created. 1325 * @throws TransformException if the example point can not be transformed. 1326 */ 1327 @Test 1328 public void testPolyconic() throws FactoryException, TransformException { 1329 tolerance = max(tolerance, 0.5); // The sample points are only accurate to 1 metre. 1330 description = "American Polyconic"; 1331 final SamplePoints sample = SamplePoints.forCRS(9818); 1332 createMathTransform(Projection.class, sample); 1333 verifyTransform(sample.sourcePoints, sample.targetPoints); 1334 verifyInDomainOfValidity(sample.areaOfValidity); 1335 } 1336 1337 /** 1338 * Tests the <cite>"Krovak"</cite> (EPSG:9819) projection. 1339 * First, this method transforms the point given in the <cite>Example</cite> section of the 1340 * EPSG guidance note and compares the {@link MathTransform} result with the expected result. 1341 * Next, this method transforms a random set of points in the projection area of validity 1342 * and ensures that the {@linkplain MathTransform#inverse() inverse transform} and the 1343 * {@linkplain MathTransform#derivative derivatives} are coherent. 1344 * 1345 * <p>The math transform parameters and the sample coordinates are:</p> 1346 * 1347 * <table cellspacing="15" summary="Test data"> 1348 * <tr valign="top"><td><table class="ogc"> 1349 * <caption>CRS characteristics</caption> 1350 * <tr><th>Parameter</th> <th>Value</th></tr> 1351 * <tr><td>semi-major axis</td> <td>6377397.155 m</td></tr> 1352 * <tr><td>semi-minor axis</td> <td>6356078.9626186555 m</td></tr> 1353 * <tr><td>Latitude of projection centre</td> <td>49.5°</td></tr> 1354 * <tr><td>Longitude of origin</td> <td>24.5°</td></tr> 1355 * <tr><td>Co-latitude of cone axis</td> <td>30.288139722222222°</td></tr> 1356 * <tr><td>Latitude of pseudo standard parallel</td> <td>78.5°</td></tr> 1357 * <tr><td>Scale factor on pseudo standard parallel</td> <td>0.9999</td></tr> 1358 * <tr><td>False easting</td> <td>0.0 m</td></tr> 1359 * <tr><td>False northing</td> <td>0.0 m</td></tr> 1360 * </table></td><td> 1361 * <table class="ogc"> 1362 * <caption>Test points</caption> 1363 * <tr><th>Source ordinates</th> <th>Expected results</th></tr> 1364 * <tr align="right"><td>16°50'59.179"E<br>50°12'32.442"N</td> <td>-568990.997 m<br>-1050538.643 m</td></tr> 1365 * </table></td></tr></table> 1366 * 1367 * @throws FactoryException if the math transform can not be created. 1368 * @throws TransformException if the example point can not be transformed. 1369 * 1370 * @see AuthorityFactoryTest#testEPSG_2065() 1371 */ 1372 @Test 1373 public void testKrovak() throws FactoryException, TransformException { 1374 description = "CRS S-JTSK (Ferro) / Krovak"; 1375 final SamplePoints sample = SamplePoints.forCRS(2065); 1376 createMathTransform(Projection.class, sample); 1377 verifyTransform(sample.sourcePoints, sample.targetPoints); 1378 verifyInDomainOfValidity(sample.areaOfValidity); 1379 } 1380 1381 /** 1382 * Tests the <cite>"Abridged Molodensky"</cite> (EPSG:9605) datum shift operation. 1383 * First, this method transforms the point given in the <cite>Example</cite> section of the 1384 * EPSG guidance note and compares the {@link MathTransform} result with the expected result. 1385 * Next, this method transforms a random set of geographic coordinates 1386 * and ensures that the {@linkplain MathTransform#inverse() inverse transform} and the 1387 * {@linkplain MathTransform#derivative derivatives} are coherent. 1388 * 1389 * <p>The math transform parameters and the sample coordinates are:</p> 1390 * 1391 * <table cellspacing="15" summary="Test data"> 1392 * <tr valign="top"><td><table class="ogc"> 1393 * <caption>CRS characteristics</caption> 1394 * <tr><th>Parameter</th> <th>Value</th></tr> 1395 * <tr><td>dim</td> <td>3</td></tr> 1396 * <tr><td>src_semi_major</td> <td>6378137.0 m</td></tr> 1397 * <tr><td>src_semi_minor</td> <td>6356752.314247833 m</td></tr> 1398 * <tr><td>X-axis translation</td> <td>84.87 m</td></tr> 1399 * <tr><td>Y-axis translation</td> <td>96.49 m</td></tr> 1400 * <tr><td>Z-axis translation</td> <td>116.95 m</td></tr> 1401 * <tr><td>Semi-major axis length difference</td> <td>251 m</td></tr> 1402 * <tr><td>Flattening difference</td> <td>1.41927E-05</td></tr> 1403 * </table></td><td> 1404 * <table class="ogc"> 1405 * <caption>Test points</caption> 1406 * <tr><th>Source ordinates</th><th>Expected results</th></tr> 1407 * <tr align="right"> 1408 * <td>2°7'46.380"E<br>53°48'33.820"N<br>73.000 m</td> 1409 * <td>2°7'51.477"E<br>53°48'36.563"N<br>28.091 m</td> 1410 * </tr></table></td></tr></table> 1411 * 1412 * @throws FactoryException if the math transform can not be created. 1413 * @throws TransformException if the example point can not be transformed. 1414 */ 1415 @Test 1416 public void testAbridgedMolodensky() throws FactoryException, TransformException { 1417 tolerance = max(tolerance, 0.001 * (NAUTICAL_MILE/60)); // 0.001 angular second (about 3 cm at equator). 1418 description = "WGS84 to ED50"; 1419 final SamplePoints sample = SamplePoints.forCRS(4230); 1420 createMathTransform(Transformation.class, sample); 1421 verifyTransform(sample.sourcePoints, sample.targetPoints); 1422 final Rectangle2D areaOfValidity = sample.areaOfValidity; 1423 verifyInDomain(new double[] { 1424 areaOfValidity.getMinX(), 1425 areaOfValidity.getMinY(), 1426 -1000 1427 }, new double[] { 1428 areaOfValidity.getMaxX(), 1429 areaOfValidity.getMaxY(), 1430 +1000 1431 }, new int[] { 1432 10, 10, 10 1433 }, new Random()); 1434 } 1435 1436 /** 1437 * Asserts that a matrix of derivatives is equals to the expected ones within a positive delta. 1438 */ 1439 @Override 1440 protected void assertMatrixEquals(final String message, final Matrix expected, final Matrix actual, final Matrix tolmat) 1441 throws DerivativeFailure 1442 { 1443 if (tolmat != null) { 1444 final int numRow = tolmat.getNumRow(); 1445 final int numCol = tolmat.getNumCol(); 1446 for (int j=0; j<numRow; j++) { 1447 for (int i=0; i<numCol; i++) { 1448 tolmat.setElement(j, i, DERIVATIVE_TOLERANCE); 1449 } 1450 } 1451 } 1452 super.assertMatrixEquals(message, expected, actual, tolmat); 1453 } 1454}