Перейти к основному содержимому

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

· 4 мин. чтения

1. Обзор

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

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

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

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

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

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

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

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

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

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 .