英文:
geotools reversing lat/lon for WGS when transforming between projections
问题
我在使用Geotools的JTS.transform()时遇到了问题,经纬度似乎被颠倒了,这个问题已经困扰了我好几天。
我有不同投影下定义的不同数据集。目标是,我可以将给定投影WKT下的任何坐标映射到WGS84的(lon,lat)坐标。以下是执行转换的工具类:
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'm having issues with Geotools reversing the latitude and longitude, using JTS.transform(). It'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'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 = "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);
}
}
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:<5.0> but was:<50.0>
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("urn:ogc:def:crs:EPSG:6.6:4326");
} 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("org.geotools.referencing.forceXY", "true");
//wgs = ...
}
which does nothing at all. Can anybody explain what'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[\"Latitude\",NORTH], AXIS[\"Longitude\",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["Geodetic longitude", EAST], AXIS["Geodetic latitude", 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;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论