Рубрики
Без рубрики

Преобразование широты и долготы в 2D-точку на Java

Узнайте, как использовать проекцию Меркатора для преобразования координат широты и долготы на 2D-поверхность

Автор оригинала: Grigorios Dimopoulos.

1. Обзор

При реализации приложений, используя карты, мы, как правило, запускаем проблему преобразования координат. Большую часть времени, мы должны конвертировать широту и долготу в 2D-точку для отображения . К счастью, чтобы решить эту проблему, мы можем использовать формулы проекции Меркатора.

В этом учебнике мы покроем проекцию Меркатора и научимся реализовывать два варианта.

2. Проекция Меркатора

Проекция Меркатора это картографические проекции, введенные фламандского картографа Херардуса Меркатора в 1569 году. Проекция карты преобразует координаты широты и долготы на Земле в точку на плоской поверхности. Другими словами, он переводит точку на поверхности земли в точку на плоской карте .

Существует два способа реализации проекции Меркатора. Псевдо-проекция Меркатора рассматривает Землю как сферу. Истинная проекция Меркатора моделирует Землю как эллипсоидную . Мы будем реализовывать обе версии.

Начнем с базового класса для обеих реализаций проекции Mercator:

abstract class Mercator {
    final static double RADIUS_MAJOR = 6378137.0;
    final static double RADIUS_MINOR = 6356752.3142;

    abstract double yAxisProjection(double input);
    abstract double xAxisProjection(double input);
}

Этот класс также обеспечивает основной и незначительный радиус Земли, измеряемый в метрах. Хорошо известно, что Земля не совсем сфера. По этой причине нам нужны два радиуса. Во-первых, основным радиусом является расстояние от центра земли до экватора . Во-вторых, незначительный радиус – это расстояние от центра земли до северного и южного полюсов .

2.1. Сферическая проекция Меркатора

Псевдопроекция модели рассматривает Землю как сферу. В отличие от эллиптической проекции, где Земля будет проецироваться на более точную форму. Такой подход позволяет нам быстрая оценка к более точным, но вычислительным тяжелее эллиптические проекция. В результате этого прямое измерения расстояний в этой проекции будет приблизительным.

Кроме того, пропорции фигур на карте незначительно изменятся. В результате этого широта и соотношения форм объектов на карте, таких как страны, озера, реки и т.д., не точно сохранились .

Это также называется Веб Меркатор проекция – широко используется в веб-приложениях, включая Google Maps.

Давайте реализуем этот подход:

public class SphericalMercator extends Mercator {

    @Override
    double xAxisProjection(double input) {
        return Math.toRadians(input) * RADIUS_MAJOR;
    }

    @Override
    double yAxisProjection(double input) {
        return Math.log(Math.tan(Math.PI / 4 + Math.toRadians(input) / 2)) * RADIUS_MAJOR;
    }
}

Первое, что следует отметить на этот подход является тот факт, что этот подход представляет радиус земли по одна постоянная а не два, как есть на самом деле.  Во-вторых, мы видим, что мы реализовали две функции для преобразования в проекция x-оси и проекция y-оси . В классе выше мы использовали Математика библиотека предоставлена Java, чтобы помочь нам сделать наш код проще.

Давайте проверьте простое преобразование:

Assert.assertEquals(2449028.7974520186, sphericalMercator.xAxisProjection(22));
Assert.assertEquals(5465442.183322753, sphericalMercator.yAxisProjection(44));

Стоит отметить, что этот прогноз будет картировать точки в окаймливая коробка (слева, внизу, справа, сверху) (-20037508.34, -23810769.32, 20037508.34, 23810769.32).

2.2. Эллиптическая проекция Меркатора

Истинная проекция моделирует Землю как эллипсоид. Эта проекция дает точные соотношения для объектов в любой точке земного . Конечно, он уважает объекты на карте, но не 100% точный . Однако этот подход не является наиболее часто используемым, поскольку он является вычислительно сложным.

Давайте реализуем этот подход:

class EllipticalMercator extends Mercator {
    @Override
    double yAxisProjection(double input) {

        input = Math.min(Math.max(input, -89.5), 89.5);
        double earthDimensionalRateNormalized = 1.0 - Math.pow(RADIUS_MINOR / RADIUS_MAJOR, 2);

        double inputOnEarthProj = Math.sqrt(earthDimensionalRateNormalized) * 
          Math.sin( Math.toRadians(input));

        inputOnEarthProj = Math.pow(((1.0 - inputOnEarthProj) / (1.0+inputOnEarthProj)), 
          0.5 * Math.sqrt(earthDimensionalRateNormalized));
        
        double inputOnEarthProjNormalized = 
          Math.tan(0.5 * ((Math.PI * 0.5) - Math.toRadians(input))) / inputOnEarthProj;
        
        return (-1) * RADIUS_MAJOR * Math.log(inputOnEarthProjNormalized);
    }

    @Override
    double xAxisProjection(double input) {
        return RADIUS_MAJOR * Math.toRadians(input);
    }
}

Выше мы видим, насколько сложен этот подход в отношении проекции на оси. Это потому, что он должен принимать во внимание не круглую форму земли. Хотя истинный подход Меркатора кажется сложным, он более точен, чем сферический подход, поскольку он используется в радиусе для представления Земли одного несовершеннолетнего и одного майора.

Давайте проверьте простое преобразование:

Assert.assertEquals(2449028.7974520186, ellipticalMercator.xAxisProjection(22));
Assert.assertEquals(5435749.887511954, ellipticalMercator.yAxisProjection(44));

Этот прогноз будет карта точек в предельный ящик (-20037508.34, -34619289.37, 20037508.34, 34619289.37).

3. Заключение

Если нам нужно преобразовать координаты широты и долготы на 2D-поверхность, мы можем использовать проекцию Меркатора. В зависимости от точности, необходимой для реализации, мы можем использовать сферический или эллиптические подходы.

Как всегда, мы можем найти код этой статьи более на GitHub .