在投影之间转换时,geotools 为 WGS 反转 lat/lon
geotools reversing lat/lon for WGS when transforming between projections
我在使用 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()[=39= 的坐标是相反的]!!
我尝试的最后一件事是使用
static {
System.setProperty("org.geotools.referencing.forceXY", "true");
//wgs = ...
}
什么都不做。任何人都可以解释这里发生了什么,有谁知道我如何强制转换的结果始终具有 x=longitude 和 y=latitude?谢谢!
如果您查看 WKT 对 WGS84 的定义,它会清楚地说明 AXIS[\"Latitude\",NORTH], AXIS[\"Longitude\",EAST]
因此您指定的是 Lat,Lon 而不是 Lon,Lat。
但是,如果您使用了 DefaultGeographicCRS.WGS84.toWKT()
,您将得到一个字符串 AXIS["Geodetic longitude", EAST], AXIS["Geodetic latitude", NORTH]]
,这将是您期望的顺序。
因此,唯一可以确定的方法是在转换方法中创建点之前检查输入(和输出)坐标参考系统的轴顺序。
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;
}
我在使用 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()[=39= 的坐标是相反的]!!
我尝试的最后一件事是使用
static {
System.setProperty("org.geotools.referencing.forceXY", "true");
//wgs = ...
}
什么都不做。任何人都可以解释这里发生了什么,有谁知道我如何强制转换的结果始终具有 x=longitude 和 y=latitude?谢谢!
如果您查看 WKT 对 WGS84 的定义,它会清楚地说明 AXIS[\"Latitude\",NORTH], AXIS[\"Longitude\",EAST]
因此您指定的是 Lat,Lon 而不是 Lon,Lat。
但是,如果您使用了 DefaultGeographicCRS.WGS84.toWKT()
,您将得到一个字符串 AXIS["Geodetic longitude", EAST], AXIS["Geodetic latitude", NORTH]]
,这将是您期望的顺序。
因此,唯一可以确定的方法是在转换方法中创建点之前检查输入(和输出)坐标参考系统的轴顺序。
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;
}