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

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

 

1. обзор

При реализации приложений, использующих карты, мы обычно сталкиваемся с проблемой преобразования координат. В большинстве случаев нам нужноconvert latitude and longitude to a 2D point to display. К счастью, для решения этой проблемы мы можем использовать формулы проекции Меркатора.

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

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

Mercator projection - это картографическая проекция, представленная фламандским картографом Герардом Меркатором в 1569 году. Картографическая проекция преобразует координаты широты и долготы на Земле в точку на плоской поверхности. Другими словами,it translates a point on the surface of the earth to a point on a flat map.

Есть два способа реализации проекции Меркатора. The pseudo Mercator projection treats the Earth as a sphere. The true Mercator projection models the Earth as an ellipsoid. Мы будем реализовывать обе версии.

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

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

Этот класс также предоставляет основной и второстепенный радиус Земли, измеряемый в метрах. Хорошо известно, что Земля не совсем сфера. По этой причине нам нужны два радиуса. Во-первых,major radius is the distance from the center of the earth to the equator. Во-вторых,minor radius is the distance from the center of the earth to the north and south poles.

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

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

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

Это также называется проекциейWeb Mercator - обычно используется в веб-приложениях, включая 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;
    }
}

Первое, что следует отметить в этом подходе, - это тот факт, что этот подход представляетradius земли какone constant, а не два, как это есть на самом деле. Во-вторых, мы видим, что мы реализовали две функции, которые можно использовать для преобразования вx-axis projection иy-axis projection. В приведенном выше классе мы использовали библиотекуMath, предоставленную 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. Elliptical Mercator Projectionс

Истинная проекция моделирует Землю как эллипсоид. This projection givesaccurate ratiosfor objects anywhere on Earth. Конечно,it respects objects on the map butnot 100% accurate. Однако этот подход не является наиболее часто используемым, поскольку он сложен в вычислительном отношении.

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

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

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

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

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

Эта проекция отобразит точки в ограничительную рамку (-20037508.34, -34619289.37, 20037508.34, 34619289.37).

3. Conclusionс

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

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