/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2005-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.referencing.operation; import java.util.Collections; import java.util.Map; import javax.measure.unit.SI; import javax.measure.unit.NonSI; import org.opengis.referencing.cs.*; import org.opengis.referencing.crs.*; import org.opengis.referencing.datum.*; import org.opengis.referencing.operation.*; import org.opengis.referencing.IdentifiedObject; import org.opengis.referencing.FactoryException; import org.opengis.parameter.ParameterValueGroup; import org.geotools.factory.Hints; import org.geotools.referencing.ReferencingFactoryFinder; import org.junit.*; import static org.junit.Assert.*; /** * Tests of the {@code createProjectedCRS(...)} setting up the CRS with a 3D cartesian output for * one test, and using a 2D + vertical CRS compound for the second test. This test constructs most * objects using GeoAPI only (except for a few helper classes). * * * @source $URL$ * @version $Id$ * @author Justin Couch * @author Martin Desruisseaux */ public final class Transform3DTest { /** * Convenience method returning a set of properties for a CRS with the specified name. */ private static Map<String,String> name(final String name) { return Collections.singletonMap(IdentifiedObject.NAME_KEY, name); } /** * Tests a 3D projected to geocentric transform. * * @throws FactoryException If an object can't be created. * @throws TransformException If a coordinate transformation failed. */ @Test public void testProjectedToGeocentric() throws FactoryException, TransformException { // ---------------------------------------------------------- // Gets factories to be used for all object creations // ---------------------------------------------------------- final Hints hints = new Hints(); final CSFactory csFactory = ReferencingFactoryFinder.getCSFactory (hints); final CRSFactory crsFactory = ReferencingFactoryFinder.getCRSFactory (hints); final DatumFactory datumFactory = ReferencingFactoryFinder.getDatumFactory (hints); final MathTransformFactory mtFactory = ReferencingFactoryFinder.getMathTransformFactory (hints); final CoordinateOperationFactory opFactory = ReferencingFactoryFinder.getCoordinateOperationFactory(hints); // ---------------------------------------------------------- // Creates datum // ---------------------------------------------------------- final PrimeMeridian greenwichMeridian = datumFactory.createPrimeMeridian( name("Greenwich Meridian"), 0, NonSI.DEGREE_ANGLE); final Ellipsoid wgs84Ellipsoid = datumFactory.createFlattenedSphere( name("WGS84 Ellipsoid"), 6378137, 298.257223563, SI.METER); final GeodeticDatum wgs84 = datumFactory.createGeodeticDatum( name("WGS84 Datum"), wgs84Ellipsoid, greenwichMeridian); final VerticalDatum wgs84_height = datumFactory.createVerticalDatum( name("WGS84 Ellispoidal height"), VerticalDatumType.ELLIPSOIDAL); // ---------------------------------------------------------- // Creates non-standard (in geodesy) geocentric axis // ---------------------------------------------------------- final CoordinateSystemAxis x_axis = csFactory.createCoordinateSystemAxis( name("X"), "X", AxisDirection.OTHER, SI.METER); final CoordinateSystemAxis y_axis = csFactory.createCoordinateSystemAxis( name("Y"), "Y", AxisDirection.WEST, SI.METER); final CoordinateSystemAxis z_axis = csFactory.createCoordinateSystemAxis( name("Z"), "Z", AxisDirection.NORTH, SI.METER); // ---------------------------------------------------------- // Creates target CRS // ---------------------------------------------------------- final CartesianCS world_cs = csFactory.createCartesianCS( name("Rendered Cartesian CS"), x_axis, z_axis, y_axis); final GeocentricCRS output_crs = crsFactory.createGeocentricCRS( name("Output Cartesian CRS"), wgs84, world_cs); // ---------------------------------------------------------- // Creates geographic and projected axis for source CRS // ---------------------------------------------------------- final CoordinateSystemAxis latitude_axis = csFactory.createCoordinateSystemAxis( name("Geodetic Latitude"), "lat", AxisDirection.NORTH, NonSI.DEGREE_ANGLE); final CoordinateSystemAxis longitude_axis = csFactory.createCoordinateSystemAxis( name("Geodetic Longitude"), "lon", AxisDirection.EAST, NonSI.DEGREE_ANGLE); final CoordinateSystemAxis northing_axis = csFactory.createCoordinateSystemAxis( name("Northing"), "N", AxisDirection.NORTH, SI.METER); final CoordinateSystemAxis easting_axis = csFactory.createCoordinateSystemAxis( name("Easting"), "E", AxisDirection.EAST, SI.METER); final CoordinateSystemAxis height_axis = csFactory.createCoordinateSystemAxis( name("Ellipsoidal height"), "Up", AxisDirection.UP, SI.METER); // ---------------------------------------------------------- // Creates the geographic CRS // ---------------------------------------------------------- final EllipsoidalCS ellipsoidal_2d_cs = csFactory.createEllipsoidalCS( name("2D ellipsoidal"), longitude_axis, latitude_axis); final EllipsoidalCS ellipsoidal_3d_cs = csFactory.createEllipsoidalCS( name("3D ellipsoidal"), longitude_axis, latitude_axis, height_axis); final GeographicCRS geographic_2d_crs = crsFactory.createGeographicCRS( name("2D geographic CRS"), wgs84, ellipsoidal_2d_cs); final GeographicCRS geographic_3d_crs = crsFactory.createGeographicCRS( name("3D geographic CRS"), wgs84, ellipsoidal_3d_cs); // ---------------------------------------------------------- // Creates various coordinate systems for projected CRS // ---------------------------------------------------------- final CartesianCS utm_cartesian_3d_cs = csFactory.createCartesianCS( name("UTM 3D Cartesian CS"), northing_axis, easting_axis, height_axis); final CartesianCS utm_cartesian_2d_cs = csFactory.createCartesianCS( name("UTM 2D Cartesian CS"), northing_axis, easting_axis); final VerticalCS utm_height_cs = csFactory.createVerticalCS( name("Height CS"), height_axis); final VerticalCRS height_crs = crsFactory.createVerticalCRS( name("WGS84 Height CRS"), wgs84_height, utm_height_cs); // ---------------------------------------------------------- // Set the projection for UTM zone 12 // ---------------------------------------------------------- final int zone_num = 12; final ParameterValueGroup parameters = mtFactory.getDefaultParameters("Transverse_Mercator"); parameters.parameter("central_meridian") .setValue(-180 + zone_num*6 - 3); parameters.parameter("latitude_of_origin").setValue(0.0); parameters.parameter("scale_factor") .setValue(0.9996); parameters.parameter("false_easting") .setValue(500000.0); parameters.parameter("false_northing") .setValue(0.0); // ---------------------------------------------------------- // From here we create a 2D projected system and combine // it with a height-only CRS to give it a full 3D transform // ---------------------------------------------------------- final ProjectedCRS proj_2d = crsFactory.createProjectedCRS( name("WGS 84 / UTM Zone 12/ 2D"), geographic_2d_crs, new DefiningConversion("Transverse_Mercator", parameters), utm_cartesian_2d_cs); final CompoundCRS compound_3d = crsFactory.createCompoundCRS( name("3D Compound WGS 84 / UTM Zone 12"), new CoordinateReferenceSystem[] { proj_2d, height_crs }); final double[] out1 = checkTransformation(opFactory.createOperation(compound_3d, output_crs)); // ---------------------------------------------------------- // From here we create a 3D projected system directly // ---------------------------------------------------------- final ProjectedCRS proj_3d = crsFactory.createProjectedCRS( name("WGS 84 / UTM Zone 12/ 3D"), geographic_3d_crs, new DefiningConversion("Transverse_Mercator", parameters), utm_cartesian_3d_cs); final double[] out2 = checkTransformation(opFactory.createOperation(proj_3d, output_crs)); // ---------------------------------------------------------- // The two set of transformed coordinates should be the same // ---------------------------------------------------------- final int upper = out1.length; assertEquals(upper, out2.length); for (int i=0; i<upper; i++) { assertEquals(out1[i], out2[i], 1E-5); } } /** * Tries to transforms some points using the specified operation. * This method transforms two points from the projected CRS to the geocentric CRS. * The first point is on the ellipsoid, and the second point is 10 km above the ellipsoid. * After transformation to geocentric CRS using a cartesian CS, the two points should still * ten kilometers apart each others. * * @return Transformed coordinates. */ private static double[] checkTransformation(final CoordinateOperation operation) throws TransformException { assertTrue(operation.getSourceCRS() instanceof ProjectedCRS); assertTrue(operation.getTargetCRS() instanceof GeocentricCRS); assertTrue(operation.getTargetCRS().getCoordinateSystem() instanceof CartesianCS); final MathTransform mt = operation.getMathTransform(); // Now a couple of transforms to show it working or not working... final double[] input = {41451.73, 572227, 0}; final double[] output = new double[input.length * 2]; mt.transform(input, 0, output, 0, 1); input[2] = 10000; mt.transform(input, 0, output, input.length, 1); double distance = 0; for (int i=0; i<input.length; i++) { final double delta = output[i] - output[input.length + i]; distance += delta*delta; } distance = Math.sqrt(distance); assertEquals("Distance", 10000, distance, 1E-5); return output; } }