[Geoserver-users] Converting from one projection to another and back

Hey all,

I think I am misunderstanding something regarding the projections. If someone could help me out here, I would really appreciate it.

We have in our code functions to convert a lat/long to the Google projection, and back. It is a bunch of straight math transforms on points, and I wanted to make it a little more generic to use the Geometry class. I started up a test to check that I could go from one to the other (note: I am not certain what the actual expected values from the Google projection are right now, so bear with me) and back, but I obviously have something wrong. Can someone look over what I have below and let me know where my confusion is? I have tried changing both the source and target projections in the transform, as well as using the same source and target projections but inverting the transform. Here is my code:

package ca.intelliware.services;

import junit.framework.TestCase;

import org.geotools.geometry.jts.JTS;

import org.geotools.referencing.CRS;

import org.geotools.referencing.factory.AbstractAuthorityFactory;

import org.geotools.referencing.factory.epsg.PostgreDataSource;

import org.opengis.referencing.FactoryException;

import org.opengis.referencing.crs.CoordinateReferenceSystem;

import org.opengis.referencing.operation.MathTransform;

import com.vividsolutions.jts.geom.Coordinate;

import com.vividsolutions.jts.geom.Geometry;

import com.vividsolutions.jts.geom.Point;

import com.vividsolutions.jts.geom.PrecisionModel;

public class TestProjectAndProjectBack extends TestCase {

public static final String EPSG_4326 = “EPSG:4326”;

public static final String EPSG_900913 = “PROJCS["WGS84 / Google Mercator", GEOGCS["WGS 84", DATUM["World Geodetic System 1984", SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]], AUTHORITY["EPSG","6326"]], PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]], UNIT["degree", 0.017453292519943295], AXIS["Geodetic latitude", NORTH], AXIS["Geodetic longitude", EAST], AUTHORITY["EPSG","4326"]], PROJECTION["Mercator_1SP"], PARAMETER["semi_minor", 6378137.0], PARAMETER["latitude_of_origin", 0.0], PARAMETER["central_meridian", 0.0], PARAMETER["scale_factor", 1.0], PARAMETER["false_easting", 0.0], PARAMETER["false_northing", 0.0], UNIT["m", 1.0], AXIS["Easting", EAST], AXIS["Northing", NORTH], AUTHORITY["EPSG","900913"]]”;

@SuppressWarnings(“deprecation”)

public void testConvertFromDecimalDegreesToGoogleAndBackGivesSameValuesUsingGeometries() {

Geometry original = new Point(new Coordinate(new Double(“-81.123456”), new Double(“45.123456”)),new PrecisionModel(PrecisionModel.FLOATING_SINGLE), 4326);

Geometry converted = fromDecimalDegreesToGoogleTransverseMercator(original);

assertSignificantlyDifferent(original, converted);

Geometry convertedBack = fromGoogleTransverseMercatorToDecimalDegrees(original);

assertNotSignificantlyDifferent(original, convertedBack);

}

private void assertSignificantlyDifferent(Geometry geo1, Geometry geo2) {

assertTrue(!geo1.equals(geo2));

}

private void assertNotSignificantlyDifferent(Geometry geo1, Geometry geo2) {

assertTrue(geo1.equals(geo2));

}

private Geometry fromDecimalDegreesToGoogleTransverseMercator(Geometry geom) {

try {

MathTransform math = CRS.findMathTransform(getEpsg4326CRS(), getEpsg900913CRS());

return JTS.transform(geom, math);

} catch (Exception e) {

throw new IllegalStateException(“Unable to convert geometry:\n” + e.getMessage());

}

}

public Geometry fromGoogleTransverseMercatorToDecimalDegrees(Geometry geom) {

try {

MathTransform math = CRS.findMathTransform(getEpsg900913CRS(), getEpsg4326CRS());

return JTS.transform(geom, math);

// MathTransform math = CRS.findMathTransform(getEpsg4326CRS(), getEpsg900913CRS());

// return JTS.transform(geom, math.inverse());

} catch (Exception e) {

throw new IllegalStateException(“Unable to convert geometry:\n” + e.getMessage());

}

}

public CoordinateReferenceSystem getEpsg4326CRS() {

try {

PostgreDataSource postgreDataSource = SpringLocator.getEPSGPostgreDataSource();

AbstractAuthorityFactory abstractAuthorityFactory = postgreDataSource.createFactory(null);

return abstractAuthorityFactory.createCoordinateReferenceSystem(EPSG_4326);

} catch (Exception e) {

throw new RuntimeException("FATAL: Unable to create a CRS for " + EPSG_4326);

}

}

public CoordinateReferenceSystem getEpsg900913CRS() {

try {

return CRS.parseWKT(EPSG_900913);

} catch (FactoryException e) {

throw new RuntimeException("FATAL: Unable to create a CRS for " + EPSG_900913);

}

}

}

Thanks,

-mike


“I don’t think that the right time to tell a dog not to pee on the carpet is semiannually.”

House MD on performance reviews

Hi Mike,

The problem lies in the line:

Geometry convertedBack = fromGoogleTransverseMercatorToDecimalDegrees(original);

Should not converted be passed into that method. I changed it and ran the test case again and the resulting point is pretty much identical, minus a bit of round off error.

-Justin

Michael Melvin wrote:

Hey all,

I think I am misunderstanding something regarding the projections. If someone could help me out here, I would really appreciate it.

We have in our code functions to convert a lat/long to the Google projection, and back. It is a bunch of straight math transforms on points, and I wanted to make it a little more generic to use the Geometry class. I started up a test to check that I could go from one to the other (note: I am not certain what the actual expected values from the Google projection are right now, so bear with me) and back, but I obviously have something wrong. Can someone look over what I have below and let me know where my confusion is? I have tried changing both the source and target projections in the transform, as well as using the same source and target projections but inverting the transform. Here is my code:

package ca.intelliware.services;

import junit.framework.TestCase;

import org.geotools.geometry.jts.JTS;

import org.geotools.referencing.CRS;

import org.geotools.referencing.factory.AbstractAuthorityFactory;

import org.geotools.referencing.factory.epsg.PostgreDataSource;

import org.opengis.referencing.FactoryException;

import org.opengis.referencing.crs.CoordinateReferenceSystem;

import org.opengis.referencing.operation.MathTransform;

import com.vividsolutions.jts.geom.Coordinate;

import com.vividsolutions.jts.geom.Geometry;

import com.vividsolutions.jts.geom.Point;

import com.vividsolutions.jts.geom.PrecisionModel;

public class TestProjectAndProjectBack extends TestCase {

            public static final String EPSG_4326 = "EPSG:4326";

            public static final String EPSG_900913 = "PROJCS[\"WGS84 / Google Mercator\", GEOGCS[\"WGS 84\", DATUM[\"World Geodetic System 1984\", SPHEROID[\"WGS 84\", 6378137.0, 298.257223563, AUTHORITY[\"EPSG\",\"7030\"]], AUTHORITY[\"EPSG\",\"6326\"]], PRIMEM[\"Greenwich\", 0.0, AUTHORITY[\"EPSG\",\"8901\"]], UNIT[\"degree\", 0.017453292519943295], AXIS[\"Geodetic latitude\", NORTH], AXIS[\"Geodetic longitude\", EAST], AUTHORITY[\"EPSG\",\"4326\"]], PROJECTION[\"Mercator_1SP\"], PARAMETER[\"semi_minor\", 6378137.0], PARAMETER[\"latitude_of_origin\", 0.0], PARAMETER[\"central_meridian\", 0.0], PARAMETER[\"scale_factor\", 1.0], PARAMETER[\"false_easting\", 0.0], PARAMETER[\"false_northing\", 0.0], UNIT[\"m\", 1.0], AXIS[\"Easting\", EAST], AXIS[\"Northing\", NORTH], AUTHORITY[\"EPSG\",\"900913\"]]";

            @SuppressWarnings("deprecation")

            public void testConvertFromDecimalDegreesToGoogleAndBackGivesSameValuesUsingGeometries() {

                        Geometry original = new Point(new Coordinate(new Double("-81.123456"), new Double("45.123456")),new PrecisionModel(PrecisionModel.FLOATING_SINGLE), 4326);

                        Geometry converted = fromDecimalDegreesToGoogleTransverseMercator(original);

                        assertSignificantlyDifferent(original, converted);

                        Geometry convertedBack = fromGoogleTransverseMercatorToDecimalDegrees(original);

                        assertNotSignificantlyDifferent(original, convertedBack);

            }

            private void assertSignificantlyDifferent(Geometry geo1, Geometry geo2) {

                        assertTrue(!geo1.equals(geo2));

            }

            private void assertNotSignificantlyDifferent(Geometry geo1, Geometry geo2) {

                        assertTrue(geo1.equals(geo2));

            }

            private Geometry fromDecimalDegreesToGoogleTransverseMercator(Geometry geom) {

                        try {

                                    MathTransform math = CRS.findMathTransform(getEpsg4326CRS(), getEpsg900913CRS());

                                    return JTS.transform(geom, math);

                        } catch (Exception e) {

                                    throw new IllegalStateException("Unable to convert geometry:\n" + e.getMessage());

                        }

            }

            public Geometry fromGoogleTransverseMercatorToDecimalDegrees(Geometry geom) {

                        try {

                                    MathTransform math = CRS.findMathTransform(getEpsg900913CRS(), getEpsg4326CRS());

                                    return JTS.transform(geom, math);

// MathTransform math = CRS.findMathTransform(getEpsg4326CRS(), getEpsg900913CRS());

// return JTS.transform(geom, math.inverse());

                        } catch (Exception e) {

                                    throw new IllegalStateException("Unable to convert geometry:\n" + e.getMessage());

                        }

            }

            public CoordinateReferenceSystem getEpsg4326CRS() {

                        try {

                                    PostgreDataSource postgreDataSource = SpringLocator.getEPSGPostgreDataSource();

                                    AbstractAuthorityFactory abstractAuthorityFactory = postgreDataSource.createFactory(null);

                                    return abstractAuthorityFactory.createCoordinateReferenceSystem(EPSG_4326);

                        } catch (Exception e) {

                                    throw new RuntimeException("FATAL: Unable to create a CRS for " + EPSG_4326);

                        }

            }

            public CoordinateReferenceSystem getEpsg900913CRS() {

                        try {

                                    return CRS.parseWKT(EPSG_900913);

                        } catch (FactoryException e) {

                                    throw new RuntimeException("FATAL: Unable to create a CRS for " + EPSG_900913);

                        }

            }

}

Thanks,

-mike

------------------------------------------------------------------------

“I don't think that the right time to tell a dog not to pee on the carpet is semiannually.”

*/House MD on performance reviews /**//*

------------------------------------------------------------------------

------------------------------------------------------------------------------
This SF.net email is sponsored by:
High Quality Requirements in a Collaborative Environment.
Download a free trial of Rational Requirements Composer Now!
http://p.sf.net/sfu/www-ibm-com

------------------------------------------------------------------------

_______________________________________________
Geoserver-users mailing list
Geoserver-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/geoserver-users

--
Justin Deoliveira
OpenGeo - http://opengeo.org
Enterprise support for open source geospatial.