Суббота, 23.11.2024, 15:18
 
Главная Регистрация Вход
Приветствую Вас, Гость · RSS
[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 1
  • 1
Как устроен Google Maps
gkmapДата: Четверг, 20.03.2008, 13:10 | Сообщение # 1
Admin
Группа: Администраторы
Сообщений: 44
Репутация: 1
Статус: Offline
Как устроен Google Maps

Данное описание предназначено прежде всего для программистов, желающих использовать снимки Google Maps в своих проектах. Здесь пойдет речь именно о снимках земной поверхности, а не о картах. Сразу предупреждаю, что в статье встречаются всякие там математические формулы. Поэтому если Вы не дружите с математикой, читать не рекомендую. Итак, каким же образом организовано хранение снимков и доступ к ним в сервисе Google Maps?

Вначале определим понятие уровня детализации. Уровень детализации (Level) - это "зум", он задается ползунком на страничке Google Maps. У ползунка есть 20 позиций. Будем считать, что нижняя позиция ползунка - это 1-й уровень (самый общий план Земли), верхняя позиция - 20-й уровень (максимальный зум).

Поверхность Земли отображается на плоскость в квадратный Битмап. Размеры Битмапа зависят от выбранного уровня детализации. Битмап разделен на квадратные блоки размером 256x256 пикселов.

Битмап первого уровня имеет размеры 256x256 пикселов, и таким образом, состоит всего лишь из одного блока. Имя этого блока - t. (Рисунки здесь приведены в уменьшенном виде.)

Битмап второго уровня имеет размеры 512x512 пикселов, он состоит из 2 x 2 = 4 блоков, которые имеют названия tq, tr, tt, ts.

Битмап третьего уровня имеет размеры 1024x1024 пискелов, он состоит уже из 4 x 4 = 16 блоков:

И т.д. до 20-го уровня.

Принцип, по которому образуются имена блоков, следующий. Если на N-ом уровне некоторый блок имеет имя [name], то на (N+1)-ом уровне он "режется" на 4 блока, которые получают имена [name]q, [name]r, [name]t, [name]s в таком порядке:

Code
q | r
-----
t | s

Еще раз отметим, что на любом уровне детализации блоки имеют размер 256x256 пикселов. С увеличением уровня количество блоков, а следовательно, и размеры Битмапа увеличиваются.

Когда на сайте Google Maps Вы при помощи ползунка выбираете уровень детализации, в окошке Вы видите фрагмент Битмапа указанного уровня. Те блоки, которые попали в окошко, постепенно подкачиваются браузером с сайта, и таким образом формируется изображение.

Введем следующие обозначения.

Code
NumTiles[Level] - количество блоков вдоль одной стороны Битмапа уровня Level:
NumTiles[Level] = 2 ^ (Level-1)

Code
NumTiles[1] = 1
NumTiles[2] = 2
NumTiles[3] = 4
NumTiles[4] = 8
NumTiles[5] = 16
NumTiles[6] = 32
NumTiles[7] = 64
NumTiles[8] = 128
NumTiles[9] = 256
NumTiles[10] = 512
NumTiles[11] = 1024
NumTiles[12] = 2048
NumTiles[13] = 4096
NumTiles[14] = 8192
NumTiles[15] = 16384
NumTiles[16] = 32768
NumTiles[17] = 65536
NumTiles[18] = 131072
NumTiles[19] = 262144
NumTiles[20] = 524288

BitmapSize[Level] - размер в пикселах одной стороны Битмапа уровня Level.

Code
BitmapSize[Level] = NumTiles[Level] * 256

BitmapOrigo[Level] - координаты (в пикселах) середины Битмапа уровня Level.

Code
BitmapOrigo[Level] = BitmapSize[Level] / 2

Теперь подробнее о преобразовании координат.

На Битмапе координаты (в пикселах) отсчитываются от левого верхнего угла. Левый верхний пискел имеет координаты (0; 0).

Все меридианы на Битмапе параллельны оси Y, все параллели идут вдоль оси X. Экватор проходит ровно посередине. Нулевой меридиан - тоже ровно посередине. Таким образом, точка с географическими координатами 0° широты, 0° долготы отображается на Битмап уровня Level в точку с координатами X = Y = BitmapOrigo[Level].

Принято следующее правило: широты южнее экватора считаются отрицательными, севернее экватора - положительными. Долготы к западу от нулевого меридиана - отрицательные, к востоку - положительные. По горизонтали Битмап охватывает весь диапазон долгот: от -180° до +180°. По вертикали - примерно от -85° до +85° (более подробно об этом будет сказано ниже).

Пусть заданы географические координаты точки на Земле: Lat - широта, Lon - долгота (в градусах). На Битмапе уровня Level она отображается в точку с координатами

Code
X = floor (BitmapOrigo[Level] + Lon * PixelsPerLonDegree[Level]);
Y = floor (BitmapOrigo[Level] - 0.5 * ln((1+z)/(1-z)) * PixelsPerLonRadian[Level]),
где z = sin (Lat).

Floor - округление до ближайшего целого в меньшую сторону, например:
Code
Floor(-2.8) = -3
Floor(2.8) = 2
Floor(-1.0) = -1

ln - натуральный логарифм.

sin - синус. Заметим, что практически во всех компиляторах на вход синусу надо подавать значение угла в радианах, поэтому Lat надо из градусов перевести в радианы.

PixelsPerLonDegree[Level] - количество пикселов, приходящееся на один градус долготы на Битмапе уровня Level.

Code
PixelsPerLonDegree[Level] = BitmapSize[Level] / 360

Соответственно, PixelsPerLonRadian[Level] - количество пикселов, приходящееся на один радиан долготы.

Code
PixelsPerLonRadian[Level] = BitmapSize[Level] / (2*PI)

Из формул видно, что преобразование между X и Lon линейно. Это означает, что если взять меридианы, расположенные через фиксированное расстояние (в градусах) друг от друга, то и на Битмапе они будут отстоять друг от друга на одинаковое число пикселов. (Поэтому величины PixelsPerLonDegree[Level] и PixelsPerLonRadian[Level] являются фиксированными при конкретном значении Level).

Для преобразования между Y и Lat это неверно. Если взять параллели, расположенные через фиксированное расстояние (в градусах) друг от друга, то на Битмапе они будут расположены "гуще" вблизи экватора и "реже" вблизи полюсов.

Обратное преобразование выполняется по формулам

Code
Lon = (X - BitmapOrigo[Level]) / PixelsPerLonDegree[Level];
Lat = (2 * arctan(exp(z)) - PI/2) * 180/PI,
где z = (Y - BitmapOrigo[Level]) / -PixelsPerLonRadian[Level];

exp(z) - e в степени z.
arctan - арктангенс в радианах.

Далее, как все это использовать.

Пусть дана точка на поверхности Земли с географическими координатами широта=Lat, долгота=Lon. Мы хотим получить блок уровня Level, в который попадает эта точка.

1. По указанным выше формулам получаем координаты точки на Битмапе - X, Y.

2. Получаем номера (по горизонтали и вертикали) блока, в который попадает эта точка:

Code
NumX = floor (X / BlockSize);
NumY = floor (Y / BlockSize);

где BlockSize = 256 (размер стороны блока в пикселах).

Блоки на Битмапе также нумеруются от левого верхнего угла. Левый верхний блок имеет номер (0; 0).

3. Зная Level и номер блока, можно получить его название. Здесь приведем процедуру на Паскале, аналогичную процедуре из скриптов Google.

Code
function GetBlockName (NumX, NumY: integer; Level: integer): string;
var
   d: integer;
   i: integer;
   res: string;
    
begin
   d:= round (power (2, Level-1));

   if (NumX < 0) or (d-1 < NumX) then
   begin
     NumX:= NumX mod d;
     if (NumX < 0) then NumX:= NumX + d;
   end;

   res:= 't';
   for i:= 2 to Level do
   begin
     d:= d div 2;
     if (NumY < d) then
     begin
       if (NumX < d)
         then res:= res + 'q'
         else begin res:= res + 'r'; NumX:= NumX - d; end;
     end
       else
     begin
       if (NumX < d)
         then res:= res + 't'
         else begin res:= res + 's'; NumX:= NumX - d; end;
       NumY:= NumY - d;
     end;
   end;

   Result:= res;
end;

Все снимки хранятся на Google Maps именно в виде таких блоков размером 256x256 пикселов. Каждый блок представляет собой jpeg-файл. Самих Битмапов нигде нет, это виртуальные объекты.

Чтобы получить с сайта блок с именем [name], нужно задать следующий запрос:

http://kh0.google.com/kh?n=404&v=10&t=[name]

В имени блока буквы t, q, r, s должны быть строчными (не заглавными).

При просмотре сайта Google Maps браузером скрипты скачивают блоки попеременно с четырех хостов:

kh0.google.com,

kh1.google.com,

kh2.google.com,

kh3.google.com.

В более ранних версиях скриптов блоки скачивались с одного хоста kh.google.com; сейчас он-по прежнему доступен. Все пять хостов соответствуют одному IP-адресу и выдают абсолютно одинаковые картинки.

В запросе присутствует параметр n=404. Если его убрать, то при попытке получить несуществующий блок Вы получите следующую картинку:

Если же этот параметр указан, то при запросе несуществующего блока хост выдает HTTP-ошибку 404 ("Документ не найден").

Параметр v=10 указывает на "версию" снимков. Периодически скрипты Google Maps переходят на очередную версию, и эта величина увеличивается на единицу. Переход на очередную версию, как правило, связан с добавлением снимков более высоких уровней детализации для некоторых территорий. Старые же снимки остаются неизменными.

Как уже упоминалось, максимальный доступный на Google Maps уровень детализации - 20-й. Однако снимки 20-го уровня есть не для всей поверхности Земли. С таким высоким зумом отсняты в основном крупные города. Разные области Земли покрыты с различной степенью детализации.

Кроме того, некоторые блоки высокого уровня получены "нечестным" путем - простым увеличением блоков более низкого уровня. В результате получается "размазанная" картинка. Вот пример - небольшая территория покрыта блоками 16-го уровня. Часть из них - нормальные снимки, а другая часть получена "размазыванием":

Средний размер jpeg-блоков составляет примерно 11 Кб. Битмап, например, 18-го уровня состоит из 1310722 = 17179869184 блоков. Таким образом, теоретический суммарный объем всех jpeg-блоков 18-го уровня составит порядка 176 Тбайт (180 тысяч Гбайт). "Теоретический" - потому что, как уже упоминалось, блоки 18-го уровня есть не для всей поверхности Земли. Я это все к тому, что если у кого-то возникают мысли "закачать весь Гугол к себе", то ему стоит призадуматься, а хватит ли у него денег на такое количество винчестеров...

Может возникнуть следующий вопрос: а какой масштаб имеет изображение на каждом конкретном уровне детализации? Ответ таков: изображение не имеет фиксированного масштаба. Для Битмапа уровня Level фиксированной является величина PixelsPerLonDegree[Level] - количество пикселов, приходящееся на один градус долготы (т.е. если отмерять этот градус вдоль географической параллели). Но поскольку на разных широтах один градус долготы покрывает различные расстояния (в метрах), то и масштаб будет меняться в зависимости от широты. Например, нижняя сторона блока trt в метрах окажется длиннее, чем его верхняя сторона. Укажем эту зависимость.

На широте fi радиус параллели составляет

Code
r = R * cos (fi)
где R - радиус Земли.

Длина дуги выражается через угол в радианах и радиус:

Code
l = alpha * r = alpha * R * cos (fi)

Следовательно, на широте fi масштаб картинки (уровня Level) по горизонтали составляет
Code
PixelsPerLonRadian[Level] / (R * cos (fi))   пикс/м

Если же отсчитывать градус вдоль меридиана, то тут еще сложнее. Масштаб картинки по вертикали непрерывно меняется с широтой. Единственное, что можно отметить, преобразование между географическими координатами и координатами на Битмапе выбрано таким образом, чтобы пропорции бесконечно малых объектов сохранялись. Это означает, что если на Земле стоит квадратный дом, то и на снимке он должен быть квадратным (хотя бы приблизительно), а не вытянутым по горизонтали или вертикали, иначе ценность таких изображений была бы сомнительной. Т.е. если выбрать какую-нибудь точку, то в малой ее окрестности масштаб картинки по горизонтали и по вертикали будет одинаков. Стоит сдвинуться чуть вверх или вниз - масштаб (и по горизонтали, и по вертикали) немного изменится.

При движении от экватора к полюсам на каждый пиксел приходится все меньше и меньше градусов (и метров). А значит, и в один блок по вертикали "влезает" все меньшее расстояние. Поскольку число блоков ограничено (NumTiles[Level]), то блоки не "доходят" до полюса, а "останавливаются" на широте 85.0511287798066°. Это число можно получить, подставив в формулу обратного преобразования (для Lat) значение Y = 0.

С учетом всего вышесказанного должно быть понятно, что блок вблизи экватора охватывает бОльшую территорию, чем блок того же уровня вблизи полюса. Т.е. ближе к полюсам разрешение блоков возрастает.

Сылка на картинку, отображаемую в окошке, (Link to this page) имеет вид

http://maps.google.com/maps?ll=55.751463,37.617273&spn=0.006493,0.031637&t=k&hl=en

Ее основными параметрами являются:
ll - широта и долгота центра картинки (от английских слов latitude - широта, longitude - долгота);
spn - размеры территории, которая видна в окошке - по горизонтали и вертикали, в градусах (от английского слова span - небольшой участок, объем, размах, диапазон).

Оригинал

 
  • Страница 1 из 1
  • 1
Поиск: