在投影之间转换时,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;
  }