геоинструменты, меняющие широту и долготу для WGS при преобразовании между проекциями

У меня проблемы с Geotools, меняющие местами широту и долготу с помощью JTS.transform (). Это сводит меня с ума уже несколько дней.

У меня разные наборы данных, определенные в разных прогнозах. Цель состоит в том, чтобы я мог сопоставить любую координату в данной проекции WKT с координатой (долгота, широта) в WGS84. Вот моя утилита, которая выполняет преобразование:

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);
    }
}

То, что происходит, действительно сбивает с толку. Для проекции testWgs () из WGS84 в WGS84 действие преобразования меняет координаты на противоположные. 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 = широту? Спасибо!


person hinsbergen    schedule 25.07.2020    source источник
comment
Кстати, если я конвертирую DefaultGeographicCRS.WGS84 в DefaultGeographicCRS.WGS84, он работает нормально.   -  person hinsbergen    schedule 26.07.2020
comment
Это «моя» WGS wkt: GEOGCS [WGS 84, DATUM [WGS_1984, SPHEROID [WGS 84, 6378137.0, 298.257223563, AUTHORITY [EPSG, 7030]], AUTHORITY [EPSG, 6326]], PRIMEM [Greenwich, 0.0], UNIT [градус, 0,017453292519943295], ОСЬ [Широта, СЕВЕР], ОСЬ [Долгота, ВОСТОК], АВТОРИТЕТ [EPSG, 4326]] По умолчанию: GEOGCS [WGS84 (DD), DATUM [WGS84, SPHEROID [WGS84, 6378137.0, 298.2573563] ], PRIMEM [Гринвич, 0,0], UNIT [градус, 0,017453292519943295], AXIS [Геодезическая долгота, ВОСТОК], AXIS [Геодезическая широта, СЕВЕР]]   -  person hinsbergen    schedule 26.07.2020


Ответы (1)


Если вы посмотрите на 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;
  }
person Ian Turton    schedule 26.07.2020
comment
Отлично!! Я видел операторы AXIS, но не осознавал, что порядок определяет ввод / вывод. В конце концов я реализовал if-оператор как CRS.getAxisOrder (sourceCRS) .equals (CRS.getAxisOrder (wgs)), работает как шарм :) - person hinsbergen; 27.07.2020