Google Maps. Преобразование координат

Google Maps очень удобный инструмент для встраивания карт в корпоративные приложения. Существует развитый API для использования Google Maps в веб-интерфейсе на JavaScript. Однако при попытке использовать Google Maps в иных языках программирования может оказаться удобнее использовать простой статический API от Google Maps. 

Google Maps Static API

Принцип использования статического API предельно прост, и заключается в общем случае в передаче в качестве параметров серверу maps.google.com координат центра интересующей нас области (Широта-Latitude, Долгота-Longitude), размера карты в пикселах (ширина, высота), номера уровня-Zoom Level и некоторых дополнительных параметров. 
Максимальный размер карты 512×512 пикселов, как указано в документации, однако реально можно получить картинку размером 640×640
Параметр sensor=false указывает отсутствие датчика местоположения, параметр этот необязательный, однако в документации на API требуется его все равно уазывать.
Параметр maptype указывает на тип карты и может принимать значения roadmap и mobile.
Параметр key при разработке можно не указывать, однако через некоторое число запросов к серверу maps.google.com ваш IP адрес может быть забанен. Рекомендуется получить официальный ключ. При получении ключа для целей разработки указывайте адрес веб сервера как http://localhost
Можно также указать координаты маркеров, которые будут отображены на полученной карте. Более подробно про маркеры можно прочитать в официальной документации на Google Maps Static API.
В ответ на запрос мы получаем картинку, которую и можем отобразить в приложении, например, на Java или Delphi
Например, выполнив такой запрос в браузере мы увидим карту Минска:


Карта Минска 1
Более подробно о Google Maps Static API можно прочитать здесь, на официальном сайте Google
Все замечательно до тех пор, пока мы не захотим в нашем приложении сделать что-то большее. Например, отрисовать свои объекты, не используя маркеры Google Maps Static API. Или же вычислять координаты в градусах по положению курсора мыши. Для этого нам необходимо выполнять преобразования координат. Из десятичных градусов в декартову систему координат и наоборот.
Далее мы рассмотрим основы, которые необходимо знать для понимания преобразования координат, и напишем соответствующие функции на языке Java.  

Проекция Google Maps

Земля в Google Maps развернута в проекции Меркатора. Иными словами Земля представляет собой развернутый на плоскость цилиндр. В проекции Меркатора меридианы всегда равноудалены друг от друга. Т.е. преобразование координат по оси X будет линейно. Напротив, параллели в проекции Меркатора не равноудалены друг от друга и преобразования координат по оси Y носит нелинейный характер, что связано с особенностью цилиндрической проекции. Это первое, что нам необходимо знать про проекцию Земли в Google Maps. Также вспомним, что широта Земли имеет границы от -90 до 90 градусов, а долгота – от -180 до 180 градусов. 
Следующее важное свойство Google Maps состоит в том, что Земля разбита на 20 уровней масштабирования. На любом из уровней проекция Земли размещается целиком, но уровни различаются детализацией. Так нулевой уровень представлен квадратом (битмапом) размерностью 256×256 пикселей. На втором уровне детализация увеличивается ровно вдвое и на втором уровне проекция Земли представлена на квадрате 512×512 пикселей. И так далее, до 19 уровня детализации. 
Учитывая вышесказанное, функции  преобразования координат будут преобразовывать заданную широту и долготу в прямоугольную систему координат на квадрате с количеством пикселов, равным заданному уровню детализации. И наоборот. 

Функции преобразования координат

Для ускорения вычислений определим массив, хранящий размерности квадратов для каждого уровня.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private double[] LevelSize = new double[20];

LevelSize[0]=256;
LevelSize[1]=512;
LevelSize[2]=1024;
LevelSize[3]=2048;
LevelSize[4]=4096;
LevelSize[5]=8192;
LevelSize[6]=16384;
LevelSize[7]=32768;
LevelSize[8]=65536;
LevelSize[9]=131072;
LevelSize[10]=262144;
LevelSize[11]=524288;
LevelSize[12]=1048576;
LevelSize[13]=2097152;
LevelSize[14]=4194304;
LevelSize[15]=8388608;
LevelSize[16]=16777216;
LevelSize[17]=33554432;
LevelSize[18]=67108864;
LevelSize[19]=134217728;
Массив можно заполнить и так:

1
2
3
4
5
6
double k=256;
for (int i=0; i<20; i++)
{
  LevelSize[i]=k;
  k=k*2;
}
Представленные далее функции предназначены для преобразования широты и долготы в координаты пиксела на битмапе, соответствующем заданному уровню, и наоборот. Математику приводить не будем, покажем сразу работоспособные функции, пригодные для практического применения. Для точности вычислений координаты пикселов не округляются, это можно выполнить непосредственно в вашем приложении.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public double GoogleLon2BmpPix(double Lon, int Level)
{
  return (LevelSize[Level] / 2 + Lon * LevelSize[Level] / 360);
}

public double GoogleBmpPix2Lon(double x, int Level)
{
  return (x - LevelSize[Level] / 2) / (LevelSize[Level] / 360);
}

public double GoogleLat2BmpPix(double Lat, int Level)
{
  double k = Math.sin(Lat * Math.PI / 180);
  return (LevelSize[Level] / 2 - 0.5 * Math.log((1 + k) / (1 - k)) * LevelSize[Level] / (2 * Math.PI));
}

public double GoogleBmpPix2Lat(double y, int Level)
{
  double k = (y - LevelSize[Level] / 2) / - (LevelSize[Level] / (2 * Math.PI));
  return (2 * Math.atan(Math.exp(k)) - Math.PI / 2) * 180 / Math.PI;
}
Для вычисления координат в градусах в зависимости от смещения в пикселах можно использовать следующие функции:

1
2
3
4
5
6
7
8
9
public double GoogleLonPixDiff(double Lon, int Level, int Diff)
{
  return GoogleBmpPix2Lon(GoogleLon2BmpPix(Lon,Level)+Diff,Level);      
}

public double GoogleLatPixDiff(double Lat, int Level, int Diff)
{
  return GoogleBmpPix2Lat(GoogleLat2BmpPix(Lat,Level)+Diff,Level);      
}

Пример использования функций преобразования координат


Полученные функции преобразования координат позволяют нам выполнять все необходимые вычисления. Например, для получения координат в градусах верхнего левого угла карты, представленной в начале статьи, необходимо получить пиксельные координаты центра карты, вычесть из этих координат по 250 (половина ширины и высоты карты, выбранные для примера) и преобразовать полученные значения обратно в градусы:

1
2
double Lat0 = GoogleLatPixDiff(53.901157,12,-250);
double Lon0 = GoogleLonPixDiff(27.554741,12,-250);
С учетом округления до шести знаков получим:

Lat0 = 53.951696
Lon0 = 27.468910

Выполним запрос с полученными значениями:


Мы видим карту, в которой верхний левый угол предыдущей карты точно помещен теперь в центр.
Карта Минска 2
Этот пример показал нам, каким образом получать координаты в градусах, смещенные на заданное количество пикселов, что может быть полезно при реализации функции смещения карты пользователем при помощи мыши. 
Для рисования собственных объектов на полученной картинке необходимо получить координаты объекта в пикселах для заданного уровня и преобразовать их к координатам в пикселах экрана отображения карты. Необходимо заметить, что делать это нужно через вычисление смещения в пикселах координат отображаемого объекта относительно центра карты. Иные способы вычисления пиксельных экранных координат (например, через вычисление координат левого верхнего угла, как это общепринято) могут давать заметную ошибку по вертикали из-за нелинейного преобразования, на которое мы указывали в это статье выше. 
И еще. При вычислении координат в пикселах не следует округлять промежуточные результаты. Округление необходимо производить над конечным результатом, иначе также можно получить заметные визуально ошибки преобразования.

Заключение

Описанные в этой статье функции для практического применения удобно оформить в виде отдельного Java класса.
Представленные преобразования координат позволяют использовать Google Maps Static API в приложениях на любых языках программирования для решения задач различной сложности, от отрисовки собственных объектов до организации полноценного интерактивного взаимодействия пользователей с картами на основе Google Maps

Related Post

Аппроксимация на Java Решение для аппроксимац...
Quartz CRON Пришлось разбираться с CRON выражениями в версии Quartz, результаты некоторых изысканий ниже, дабы не забыть. 02 53 11 06 05 ? 2015    - за...
Загрузка данных в MyBatis. Часть 2... В предыдущей статье мы ...
Загрузка данных в MyBatis. Часть 3... В предыдущих статьях (Час...

One thought on “Google Maps. Преобразование координат

  1. Very interesting and useful paper, but … I couldn’t find answer on my question – can I see Polar Map on Google with help of any tools?

Leave a Reply

Your email address will not be published. Required fields are marked *