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.gigs;
033
034import java.util.List;
035
036import org.opengis.util.Factory;
037import org.opengis.util.FactoryException;
038import org.opengis.util.NoSuchIdentifierException;
039import org.opengis.referencing.operation.Transformation;
040import org.opengis.referencing.operation.CoordinateOperation;
041import org.opengis.referencing.operation.CoordinateOperationAuthorityFactory;
042import org.opengis.referencing.operation.OperationMethod;
043import org.opengis.test.Configuration;
044import org.opengis.test.FactoryFilter;
045
046import org.junit.Test;
047import org.junit.runner.RunWith;
048import org.junit.runners.Parameterized;
049
050import static org.junit.Assume.*;
051import static org.opengis.test.Assert.*;
052
053
054/**
055 * Verifies reference vertical transformations bundled with the geoscience software.
056 *
057 * <table class="gigs" summary="Test description"><tr>
058 *   <th>Test method:</th>
059 *   <td>Compare transformation definitions included in the software against the EPSG Dataset.</td>
060 * </tr><tr>
061 *   <th>Test data:</th>
062 *   <td><a href="doc-files/GIGS_2009_libVertTfm.csv">{@code GIGS_2009_libVertTfm.csv}</a>
063 *       and EPSG Dataset.</td>
064 * </tr><tr>
065 *   <th>Tested API:</th>
066 *   <td>{@link CoordinateOperationAuthorityFactory#createCoordinateOperation(String)}.</td>
067 * </tr><tr>
068 *   <th>Expected result:</th>
069 *   <td>Transformation definitions bundled with the software should have same name, method name,
070 *       defining parameters and parameter values as in EPSG Dataset. See current version of the EPSG Dataset.
071 *       The values of the parameters should be correct to at least 10 significant figures.
072 *       Transformations missing from the software or at variance with those in the EPSG Dataset should be reported.</td>
073 * </tr></table>
074 *
075 *
076 * <div class="note"><b>Usage example:</b>
077 * in order to specify their factories and run the tests in a JUnit framework, implementors can
078 * define a subclass in their own test suite as in the example below:
079 *
080 * <blockquote><pre>import org.junit.runner.RunWith;
081 *import org.junit.runners.JUnit4;
082 *import org.opengis.test.referencing.gigs.GIGS2009;
083 *
084 *&#64;RunWith(JUnit4.class)
085 *public class MyTest extends GIGS2009 {
086 *    public MyTest() {
087 *        super(new MyCoordinateOperationAuthorityFactory());
088 *    }
089 *}</pre></blockquote>
090 * </div>
091 *
092 * @author  GIGS (IOGP)
093 * @author  Martin Desruisseaux (Geomatys)
094 * @author  Alexis Manin (Geomatys)
095 * @version 3.1
096 * @since   3.1
097 */
098@RunWith(Parameterized.class)
099public strictfp class GIGS2009 extends AuthorityFactoryTestCase<Transformation> {
100    /**
101     * Name of the expected transformation method.
102     */
103    public String methodName;
104
105    /**
106     * The coordinate transformation created by the factory,
107     * or {@code null} if not yet created or if CRS creation failed.
108     *
109     * @see #copAuthorityFactory
110     */
111    private Transformation transformation;
112
113    /**
114     * Factory to use for building {@link Transformation} instances, or {@code null} if none.
115     * This is the factory used by the {@link #getIdentifiedObject()} method.
116     */
117    protected final CoordinateOperationAuthorityFactory copAuthorityFactory;
118
119    /**
120     * Returns a default set of factories to use for running the tests. Those factories are given
121     * in arguments to the constructor when this test class is instantiated directly by JUnit (for
122     * example as a {@linkplain org.junit.runners.Suite.SuiteClasses suite} element), instead than
123     * subclassed by the implementor. The factories are fetched as documented in the
124     * {@link #factories(Class[])} javadoc.
125     *
126     * @return the default set of arguments to be given to the {@code GIGS2009} constructor.
127     */
128    @Parameterized.Parameters
129    @SuppressWarnings("unchecked")
130    public static List<Factory[]> factories() {
131        return factories(FactoryFilter.ByAuthority.EPSG, CoordinateOperationAuthorityFactory.class);
132    }
133
134    /**
135     * Creates a new test using the given factory. If a given factory is {@code null},
136     * then the tests which depend on it will be skipped.
137     *
138     * @param copFactory  factory for creating {@link Transformation} instances.
139     */
140    public GIGS2009(final CoordinateOperationAuthorityFactory copFactory) {
141        super(copFactory);
142        copAuthorityFactory = copFactory;
143    }
144
145    /**
146     * Returns information about the configuration of the test which has been run.
147     * This method returns a map containing:
148     *
149     * <ul>
150     *   <li>All the following values associated to the {@link org.opengis.test.Configuration.Key} of the same name:
151     *     <ul>
152     *       <li>{@link #isStandardNameSupported}</li>
153     *       <li>{@link #isStandardAliasSupported}</li>
154     *       <li>{@link #isDependencyIdentificationSupported}</li>
155     *       <li>{@link #copAuthorityFactory}</li>
156     *     </ul>
157     *   </li>
158     * </ul>
159     *
160     * @return the configuration of the test being run.
161     */
162    @Override
163    public Configuration configuration() {
164        final Configuration op = super.configuration();
165        assertNull(op.put(Configuration.Key.copAuthorityFactory, copAuthorityFactory));
166        return op;
167    }
168
169    /**
170     * Returns the transformation instance to be tested. When this method is invoked for the first time, it creates the
171     * transformation to test by invoking the {@link CoordinateOperationAuthorityFactory#createCoordinateOperation(String)}
172     * method with the current {@link #code} value in argument. The created object is then cached and returned in all
173     * subsequent invocations of this method.
174     *
175     * @return the transformation instance to test.
176     * @throws FactoryException if an error occurred while creating the transformation instance.
177     */
178    @Override
179    public Transformation getIdentifiedObject() throws FactoryException {
180        if (transformation == null) {
181            assumeNotNull(copAuthorityFactory);
182            final String codeAsString = String.valueOf(code);
183            final CoordinateOperation operation;
184            try {
185                operation = copAuthorityFactory.createCoordinateOperation(codeAsString);
186            } catch (NoSuchIdentifierException e) {
187                /*
188                 * Relaxed the exception type from NoSuchAuthorityCodeException because CoordinateOperation creation
189                 * will typically use MathTransformFactory under the hood, which throws NoSuchIdentifierException for
190                 * non-implemented operation methods (may be identified by their name rather than EPSG code).
191                 */
192                unsupportedCode(Transformation.class, code);
193                throw e;
194            }
195            if (operation != null) {  // For consistency with the behavior in other classes.
196                assertInstanceOf(codeAsString, Transformation.class, operation);
197                transformation = (Transformation) operation;
198            }
199        }
200        return transformation;
201    }
202
203    /**
204     * Verifies the properties of the transformation given by {@link #getIdentifiedObject()}.
205     */
206    private void verifyTransformation() throws FactoryException {
207        final Transformation transformation = getIdentifiedObject();
208        assertNotNull("Transformation", transformation);
209        validators.validate(transformation);
210
211        // Transformation identifier.
212        assertContainsCode("Transformation.getIdentifiers()", "EPSG", code, transformation.getIdentifiers());
213
214        // Transformation name.
215        if (isStandardNameSupported) {
216            configurationTip = Configuration.Key.isStandardNameSupported;
217            assertEquals("Transformation.getName()", name, getVerifiableName(transformation));
218            configurationTip = null;
219        }
220
221        // Operation method.
222        final OperationMethod m = transformation.getMethod();
223        assertNotNull("Transformation.getMethod()", m);
224
225        // Operation method name.
226        if (isStandardNameSupported) {
227            configurationTip = Configuration.Key.isStandardNameSupported;
228            assertEquals("Transformation.getMethod().getName()", methodName, getVerifiableName(m));
229            configurationTip = null;
230        }
231    }
232
233    /**
234     * Tests “Baltic depth to AIOC95 depth (1)” transformation creation from the factory.
235     *
236     * <ul>
237     *   <li>EPSG transformation code: <b>5445</b></li>
238     *   <li>EPSG transformation name: <b>Baltic depth to AIOC95 depth (1)</b></li>
239     *   <li>Transformation method: <b>Vertical Offset</b></li>
240     *   <li>Particularly important to E&amp;P industry.</li>
241     * </ul>
242     *
243     * @throws FactoryException if an error occurred while creating the transformation from the EPSG code.
244     */
245    @Test
246    public void testBalticDepth_to_AIOC95() throws FactoryException {
247        important  = true;
248        name       = "Baltic depth to AIOC95 depth (1)";
249        methodName = "Vertical Offset";
250        verifyTransformation();
251    }
252
253    /**
254     * Tests “Baltic height to AIOC95 height (1)” transformation creation from the factory.
255     *
256     * <ul>
257     *   <li>EPSG transformation code: <b>5443</b></li>
258     *   <li>EPSG transformation name: <b>Baltic height to AIOC95 height (1)</b></li>
259     *   <li>Transformation method: <b>Vertical Offset</b></li>
260     *   <li>Particularly important to E&amp;P industry.</li>
261     * </ul>
262     *
263     * @throws FactoryException if an error occurred while creating the transformation from the EPSG code.
264     */
265    @Test
266    public void testBalticHeight_to_AIOC95() throws FactoryException {
267        important  = true;
268        name       = "Baltic height to AIOC95 height (1)";
269        methodName = "Vertical Offset";
270        verifyTransformation();
271    }
272
273    /**
274     * Tests “WGS 84 to EGM96 Geoid height (1)” transformation creation from the factory.
275     *
276     * <ul>
277     *   <li>EPSG transformation code: <b>10084</b></li>
278     *   <li>EPSG transformation name: <b>WGS 84 to EGM96 Geoid height (1)</b></li>
279     *   <li>Transformation method: <b>Geographic3D to GravityRelatedHeight (EGM)</b></li>
280     *   <li>Specific usage / Remarks: <b>Geoid model.</b></li>
281     *   <li>Particularly important to E&amp;P industry.</li>
282     * </ul>
283     *
284     * @throws FactoryException if an error occurred while creating the transformation from the EPSG code.
285     */
286    @Test
287    public void testWGS84_to_EGM96() throws FactoryException {
288        important  = true;
289        name       = "WGS 84 to EGM96 Geoid height (1)";
290        methodName = "Geographic3D to GravityRelatedHeight (EGM)";
291        verifyTransformation();
292    }
293}