FoxBase!
msgbartop
Блог Oracle разработчика
msgbarbottom
foxbase

24.02.2010 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 и некоторых дополнительных параметров. 
Максимальный размер карты 512x512 пикселов, как указано в документации, однако реально можно получить картинку размером 640x640
Параметр sensor=false указывает отсутствие датчика местоположения, параметр этот необязательный, однако в документации на API требуется его все равно уазывать.
Параметр maptype указывает на тип карты и может принимать значения roadmap и mobile.
Параметр key при разработке можно не указывать, однако через некоторое число запросов к серверу maps.google.com ваш IP адрес может быть забанен. Рекомендуется получить официальный ключ. При получении ключа для целей разработки указывайте адрес веб сервера как http://localhost
Можно также указать координаты маркеров, которые будут отображены на полученной карте. Более подробно про маркеры можно прочитать в официальной документации на Google Maps Static API.
В ответ на запрос мы получаем картинку, которую и можем отобразить в приложении, например, на Java или Delphi
Например, выполнив такой запрос в браузере мы увидим карту Минска:

http://maps.google.com/staticmap?center=53.901157,27.554741&zoom=12&size=500x500&maptype=roadmap&sensor=false

Карта Минска 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 уровней масштабирования. На любом из уровней проекция Земли размещается целиком, но уровни различаются детализацией. Так нулевой уровень представлен квадратом (битмапом) размерностью 256x256 пикселей. На втором уровне детализация увеличивается ровно вдвое и на втором уровне проекция Земли представлена на квадрате 512x512 пикселей. И так далее, до 19 уровня детализации. 
Учитывая вышесказанное, функции  преобразования координат будут преобразовывать заданную широту и долготу в прямоугольную систему координат на квадрате с количеством пикселов, равным заданному уровню детализации. И наоборот. 

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

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

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;
Массив можно заполнить и так:

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

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;
}
Для вычисления координат в градусах в зависимости от смещения в пикселах можно использовать следующие функции:

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 (половина ширины и высоты карты, выбранные для примера) и преобразовать полученные значения обратно в градусы:

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

Lat0 = 53.951696
Lon0 = 27.468910

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

http://maps.google.com/staticmap?center=53.951696,27.468910&zoom=12&size=500x500&maptype=roadmap&sensor=false

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

Заключение

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



Смотрите также:



Оставьте свой комментарий

Вы должны быть авторизированны, чтобы оставить комментарий.