地理工具在投影之间转换时反转WGS的纬度/经度。

huangapple go评论79阅读模式
英文:

geotools reversing lat/lon for WGS when transforming between projections

问题

我在使用Geotools的JTS.transform()时遇到了问题经纬度似乎被颠倒了这个问题已经困扰了我好几天

我有不同投影下定义的不同数据集目标是我可以将给定投影WKT下的任何坐标映射到WGS84的(lonlat)坐标以下是执行转换的工具类

public class TransformUtil {
    private static CoordinateReferenceSystem wgs;
    static {
        wgs = DefaultGeographicCRS.WGS84;
    }

    private static double[] convert(String wkt, double x, double y) throws TransformException {
        CoordinateReferenceSystem sourceCRS = CRS.parseWKT(wkt);
        MathTransform transform = CRS.findMathTransform(sourceCRS, WGS, true);
        Point point = geometryFactory.createPoint(new Coordinate(x, y));
        Geometry targetGeometry = JTS.transform(point, transform);
        Coordinate coord = targetGeometry.getCoordinate();
        return new double[]{coord.x, coord.y};
    }
}

以下是单元测试:

public class TestTransformUtil {
    private double lon = 5;
    private double lat = 50;
    private double margin = 1E-5d;

    @Test
    public void testWgs() {
        String wkt = "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AXIS[\"Latitude\",NORTH],AXIS[\"Longitude\",EAST],AUTHORITY[\"EPSG\",\"4326\"]]";
        double[] res = TransformUtil.toLonLat(lon, lat, wkt);
        Assert.assertEquals("Longitude", lon, res[0], margin);
        Assert.assertEquals("Latitude", lat, res[1], margin);
    }

    @Test
    public void testLaea() {
        double x = 3962799.45096;
        double y = 2999718.85316;
        String wkt = "PROJCS[\"ETRS89-extended / LAEA Europe\",GEOGCS[\"ETRS89\",DATUM[\"European_Terrestrial_Reference_System_1989\",SPHEROID[\"GRS 1980\",6378137,298.257222101004,AUTHORITY[\"EPSG\",\"7019\"]],AUTHORITY[\"EPSG\",\"6258\"]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4258\"]],PROJECTION[\"Lambert_Azimuthal_Equal_Area\"],PARAMETER[\"latitude_of_center\",52],PARAMETER[\"longitude_of_center\",10],PARAMETER[\"false_easting\",4321000],PARAMETER[\"false_northing\",3210000],UNIT[\"metre\",1],AXIS[\"Easting\",EAST],AXIS[\"Northing\",NORTH]]";
        double[] res = TransformUtil.toLonLat(x, y, wkt);
        Assert.assertEquals("Longitude", lon, res[0], margin);
        Assert.assertEquals("Latitude", lat, res[1], margin);
    }
}

发生的事情确实令人困惑。对于WGS84到WGS84的投影testWgs(),变换操作颠倒了坐标。Coordinate.x变成了纬度,Coordinate.y变成了经度,因此断言失败:

java.lang.AssertionError: Longitude expected:<5.0> but was:<50.0>

**testLaea()**没有任何问题通过了。

我在Geotools文档中找到了这个提示:https://docs.geotools.org/stable/userguide/tutorial/geometry/geometrycrs.html#workarounds,建议使用:

private static CoordinateReferenceSystem wgs;
static {
    try {
        CRSAuthorityFactory factory = CRS.getAuthorityFactory(true);
        wgs = factory.createCoordinateReferenceSystem("urn:ogc:def:crs:EPSG:6.6:4326");
    } catch (FactoryException e) {
        e.printStackTrace();
    }
}

现在当我运行测试时,**testWgs()通过了,但是现在testLaea()**的坐标被颠倒了!

最后我尝试了:

static {
    System.setProperty("org.geotools.referencing.forceXY", "true");
    //wgs = ...
}

但是这根本没有任何效果。有人能解释这里发生了什么吗?还有人知道如何强制转换的结果始终使x=经度且y=纬度吗?谢谢!


<details>
<summary>英文:</summary>

I&#39;m having issues with Geotools reversing the latitude and longitude, using JTS.transform(). It&#39;s been driving me mad now for days. 

I have different data sets defined in different projections. The goal is that I can map any coordinate in a given projection WKT to a (lon, lat) in WGS84. Here&#39;s my util that does the conversion:

	public class TransformUtil {
    	private static CoordinateReferenceSystem wgs;
		static {
			wgs = DefaultGeographicCRS.WGS84;
		}

    	private static double[] convert(String wkt, double x, double y) throws TransformException {
			CoordinateReferenceSystem sourceCRS = CRS.parseWKT(wkt);
			MathTransform transform = CRS.findMathTransform(sourceCRS, WGS, true);
			Point point = geometryFactory.createPoint( new Coordinate( x, y ) );
			Geometry targetGeometry = JTS.transform( point , transform);
			Coordinate coord = targetGeometry.getCoordinate();
			return new double[] {coord.x, coord.y};
		}
	}

and here are my unit tests:

	public class TestTransformUtil {
		private double lon = 5;
		private double lat = 50;
		private double margin = 1E-5d;

		@Test
		public void testWgs() {
			String wkt = &quot;GEOGCS[\&quot;WGS 84\&quot;,DATUM[\&quot;WGS_1984\&quot;,SPHEROID[\&quot;WGS 84\&quot;,6378137,298.257223563,AUTHORITY[\&quot;EPSG\&quot;,\&quot;7030\&quot;]],AUTHORITY[\&quot;EPSG\&quot;,\&quot;6326\&quot;]],PRIMEM[\&quot;Greenwich\&quot;,0],UNIT[\&quot;degree\&quot;,0.0174532925199433,AUTHORITY[\&quot;EPSG\&quot;,\&quot;9122\&quot;]],AXIS[\&quot;Latitude\&quot;,NORTH],AXIS[\&quot;Longitude\&quot;,EAST],AUTHORITY[\&quot;EPSG\&quot;,\&quot;4326\&quot;]]&quot;;
			double[] res = TransformUtil.toLonLat(lon, lat, wkt);
			Assert.assertEquals(&quot;Longitude&quot;, lon, res[0], margin);
			Assert.assertEquals(&quot;Latitude&quot;, lat, res[1], margin);
		}
	
		@Test
		public void testLaea() {
			double x= 3962799.45096;
			double y = 2999718.85316;
			String wkt = &quot;PROJCS[\&quot;ETRS89-extended / LAEA Europe\&quot;,GEOGCS[\&quot;ETRS89\&quot;,DATUM[\&quot;European_Terrestrial_Reference_System_1989\&quot;,SPHEROID[\&quot;GRS 1980\&quot;,6378137,298.257222101004,AUTHORITY[\&quot;EPSG\&quot;,\&quot;7019\&quot;]],AUTHORITY[\&quot;EPSG\&quot;,\&quot;6258\&quot;]],PRIMEM[\&quot;Greenwich\&quot;,0],UNIT[\&quot;degree\&quot;,0.0174532925199433,AUTHORITY[\&quot;EPSG\&quot;,\&quot;9122\&quot;]],AUTHORITY[\&quot;EPSG\&quot;,\&quot;4258\&quot;]],PROJECTION[\&quot;Lambert_Azimuthal_Equal_Area\&quot;],PARAMETER[\&quot;latitude_of_center\&quot;,52],PARAMETER[\&quot;longitude_of_center\&quot;,10],PARAMETER[\&quot;false_easting\&quot;,4321000],PARAMETER[\&quot;false_northing\&quot;,3210000],UNIT[\&quot;metre\&quot;,1],AXIS[\&quot;Easting\&quot;,EAST],AXIS[\&quot;Northing\&quot;,NORTH]]&quot;;
			double[] res = TransformUtil.toLonLat(x, y, wkt);
			Assert.assertEquals(&quot;Longitude&quot;, lon, res[0], margin);
			Assert.assertEquals(&quot;Latitude&quot;, lat, res[1], margin);
		}
	}

What happens is really confusing. For the WGS84 to WGS84 projection **testWgs()**, the transform action reverses the coordinates. Coordinate.x becomes the latitude, Coordinate.y is the longitude, thus the assert fails:

	java.lang.AssertionError: Longitude expected:&lt;5.0&gt; but was:&lt;50.0&gt;

The **testLaea()** passes without problems.

I found this tip in the geotools docs: https://docs.geotools.org/stable/userguide/tutorial/geometry/geometrycrs.html#workarounds that says that you should use

    private static CoordinateReferenceSystem wgs;
    static {
		try {
			CRSAuthorityFactory factory = CRS.getAuthorityFactory(true);
			wgs = factory.createCoordinateReferenceSystem(&quot;urn:ogc:def:crs:EPSG:6.6:4326&quot;);
		} catch (FactoryException e) {
			e.printStackTrace();
		}
	}

When I run the tests now, **testWgs()** passes, but now the coordinates are reversed for **testLaea()**!!

The final thing I tried is to use

	static {
		System.setProperty(&quot;org.geotools.referencing.forceXY&quot;, &quot;true&quot;);
		//wgs = ...
	}

which does nothing at all. Can anybody explain what&#39;s happing here, and does anyone know how I can force the outcome of the transform always to have x=longitude and y=latitude? Thanks!



</details>


# 答案1
**得分**: 2

```java
private static double[] convert(String wkt, double x, double y) throws TransformException, FactoryException {
    CoordinateReferenceSystem sourceCRS = CRS.parseWKT(wkt);
    MathTransform transform = CRS.findMathTransform(sourceCRS, WGS, true);
    Point point;
    if (CRS.getAxisOrder(sourceCRS).equals(AxisOrder.EAST_NORTH)) {
        point = geometryFactory.createPoint(new Coordinate(x, y));
    } else {
        point = geometryFactory.createPoint(new Coordinate(y, x));
    }
    Geometry targetGeometry = JTS.transform(point, transform);
    Coordinate coord = targetGeometry.getCoordinate();
    double[] ret;
    if (CRS.getAxisOrder(WGS).equals(AxisOrder.EAST_NORTH)) {
        ret = new double[] { coord.x, coord.y };
    } else {
        ret = new double[] { coord.y, coord.x };
    }
    return ret;
}
英文:

If you look at your WKT definition of WGS84, it clearly states AXIS[\&quot;Latitude\&quot;,NORTH], AXIS[\&quot;Longitude\&quot;,EAST] so you are specifying that you want Lat,Lon not Lon,Lat.

If however, you had used DefaultGeographicCRS.WGS84.toWKT() you would have had a string that said AXIS[&quot;Geodetic longitude&quot;, EAST], AXIS[&quot;Geodetic latitude&quot;, NORTH]] which would be the order you expected.

So the only way to be sure is to check the axis order of the input (and output) coordinate reference system before you create the points in your convert method.

  private static double[] convert(String wkt, double x, double y) throws TransformException, FactoryException {
    CoordinateReferenceSystem sourceCRS = CRS.parseWKT(wkt);
    MathTransform transform = CRS.findMathTransform(sourceCRS, WGS, true);
    Point point;
    if (CRS.getAxisOrder(sourceCRS).equals(AxisOrder.EAST_NORTH)) {
      point = geometryFactory.createPoint(new Coordinate(x, y));
    } else {
      point = geometryFactory.createPoint(new Coordinate(y, x));
    }
    Geometry targetGeometry = JTS.transform(point, transform);
    Coordinate coord = targetGeometry.getCoordinate();
    double[] ret;
    if (CRS.getAxisOrder(WGS).equals(AxisOrder.EAST_NORTH)) {
      ret = new double[] { coord.x, coord.y };
    } else {
      ret = new double[] { coord.y, coord.x };
    }
    return ret;
  }

huangapple
  • 本文由 发表于 2020年7月26日 01:46:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/63091589.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定