UTFGrid: растровые тайлы с атрибутикой: различия между версиями
(не показано 20 промежуточных версий 3 участников) | |||
Строка 1: | Строка 1: | ||
{{Статья| | {{Статья|Опубликована|utfgrid}} | ||
{{Аннотация|Приведено описание стандарта UTFGrid и рассмотрен пример его использования.}} | |||
== Введение == | == Введение == | ||
Основное назначение любого картографического web-приложения - это предоставление клиенту пространственной информации, включающей геометрическую и атрибутивную составляющие. Поэтому, в любом случае, на начальном этапе каждый разработчик должен ответить на вопрос: "Какой формат передачи данных следует использовать в конкретном случае?" Как известно, все форматы передачи пространственной информации можно разделить на векторные и растровые. Использование векторных форматов (KML, GML, GeoJSON и т.д.) с одной стороны очень удобно: в клиентском приложении сразу становятся доступными и геометрическая, и атрибутивная составляющие, что обеспечивает простоту добавления приложению | Основное назначение любого картографического web-приложения - это предоставление клиенту пространственной информации, включающей геометрическую и атрибутивную составляющие. Поэтому, в любом случае, на начальном этапе каждый разработчик должен ответить на вопрос: "Какой формат передачи данных следует использовать в конкретном случае?" Как известно, все форматы передачи пространственной информации можно разделить на векторные и растровые. Использование векторных форматов (KML, GML, GeoJSON и т.д.) с одной стороны очень удобно: в клиентском приложении сразу становятся доступными и геометрическая, и атрибутивная составляющие, что обеспечивает простоту добавления приложению интерактивности. С другой же - область применения векторных форматов довольно ограничена и определяется главным образом объёмом передаваемых данных. Например, если векторный слой содержит несколько миллионов объектов, то во-первых, клиенту придется ждать пока эти данные будут загружены браузером, а во-вторых пока они будут отрисованы. При этом попытка изменения масштабного уровня вновь потребует перерисовки объектов, что также может занять продолжительное время. Естественно, что ни о каком комфорте при работе с таким приложением речи не идёт, что делает использование векторных форматов недопустимым. В этом случае более подходящим решением является использование растров. | ||
речи не идёт, что делает использование векторных форматов недопустимым. В этом случае более подходящим решением является использование растров. Однако как быть с | |||
Однако как быть с атрибутикой? Допустим, что пользователю нужна возможность получения информации об объекте, на который указывает указатель мыши. Конечно, можно реализовать серверный скрипт, которому будут передаваться текущие координаты, а в ответ возвращаться нужная информация (в случае WMS слоёв можно воспользоваться стандартной возможностью любого WMS-сервера - [http://gis-lab.info/qa/mapserver-getfeatureinfo.html поддержкой запросов GetFeatureInfo]). Однако в данной статье мы рассмотрим другой способ решения этой задачи, предложенный компанией [http://mapbox.com MapBox], известный под именем UTFGrid ([https://github.com/mapbox/utfgrid-spec спецификация]). | |||
UTFGrid представляет собой стандарт, описывающий эффективный с точки зрения объёма передаваемых данных, способ кодирования атрибутивной информации объектов, представленных на растре. Данный стандарт был специально разработан для использования в Веб-браузерах и может использоваться, например, для вывода всплывающих подсказок при перемещении указателя мыши (например как [http://gis-lab.info/qa/tilemill-begin.html#.D0.9F.D1.83.D0.B1.D0.BB.D0.B8.D0.BA.D0.B0.D1.86.D0.B8.D1.8F_.D0.BA.D0.B0.D1.80.D1.82.D1.8B_.D0.B2_.D0.98.D0.BD.D1.82.D0.B5.D1.80.D0.BD.D0.B5.D1.82 здесь]). В качестве контейнера UTFGrid использует формат JSON. | |||
Рассмотрим пример данных, закодированных при помощи UTFGrid. Предположим, у нас есть некоторый растровый слой: | |||
[[Файл:Moscow-tile.png|256px|thumb|center|<center>Пример исходного растра</center>]] | |||
тогда его представление при помощи UTFGrid будет выглядеть следующим образом: | |||
<syntaxhighlight lang="javascript" line="GESHI_FANCY_LINE_NUMBERS"> | |||
{ | |||
"data": { | |||
"BOG": { | |||
"name": "район Богородское" | |||
}, | |||
"VNUK": { | |||
"name": "район Внуково" | |||
}, | |||
"ALT": { | |||
"name": "Алтуфьевский район" | |||
}, | |||
"SIL": { | |||
"name": "район Силино" | |||
}, | |||
"DOR": { | |||
"name": "район Дорогомилово" | |||
}, | |||
"ZUZ": { | |||
"name": "район Зюзино" | |||
}, | |||
"AIR": { | |||
"name": "район Аэропорт" | |||
}, | |||
"BIR": { | |||
"name": "район Бирюлево Восточное" | |||
}, | |||
"VESH": { | |||
"name": "район Вешняки" | |||
}, | |||
"LEF": { | |||
"name": "район Лефортово" | |||
} | |||
}, | |||
"grid": [ | |||
" ! ", | |||
" !!!!!! ", | |||
" !!!!!!!! # ", | |||
" !!!!!!!! ! ", | |||
" !!!!!!!!!! !! ", | |||
" !!!!! !!! !!!!!! ", | |||
" !!!!!! ! !!!!!! ", | |||
" !!!!! ! ", | |||
" !!! !!! $$$$ ", | |||
" !!!!!! $$ ", | |||
" !!!!!! $$$$ ", | |||
" !!!!!! $$$ ", | |||
" !! $$ ", | |||
" !! $$ $$ ", | |||
" !! %$$$$$$$ ", | |||
" !!! %%%%$$$$$$$$$$$ ", | |||
" !!! %%%%%%%$$$$$$$$$$$$ ", | |||
" !!!!!%%%%%%%%%%$$$$$$$$$$$$$ ", | |||
" !!!%%%%%%%%%$$$$$$$$$$$### ", | |||
" !!! !!!!%%%%%%%%%$$$$$$$$$$$#### ", | |||
" !!!!!!!!!!%%%%%%%%$$$$$$$$$#$$##### ", | |||
" !!!!!!!!!!%%%%%%%%&&$$$$$$$######### ", | |||
" !!!!!!!!!!!%%%%%%%%&&&&&&&########### ", | |||
" !!!!!!!!!!%%%%%%%&&&&&&&&############ ", | |||
" ! !!!!!!!!%%%%%%&&&&&&&&############# ### ", | |||
" '!!!!!!!!%%%%%%%&&&&&&################# ", | |||
" !!!!!!!!%%%%%%%&&&&&############### ", | |||
" !!!!!!!!!!%%%%%%&&&&&############### ", | |||
" ''!!!!!!!!!!%%%%%%&&&&&############### ", | |||
" '' !!!!!!!!!!%%%%%%&&&&&&&&&########### ", | |||
" '' ''''''''!!!!%&&&&&&&&&&&&&&########## ", | |||
" ''''''''!''!%&&&&&&&&&&&&(((######### ", | |||
" ''''''''!'''&&&&&&&&&&&&(((#######))# ", | |||
" '''''!!'''''&&&&&&&&&&&&(((#####)))# ))) ", | |||
" '''''''''''&&&&&&&&&&&&&&((((##)))))))) ", | |||
" '''''''''&&''&&&&&&&&&&&&(((((())))))) ) ", | |||
" '''''''''''''&&&&&&&&((((((((((()))))))))))) ", | |||
" ''''''''''''''&&&(((((((((((())())))))))))) ", | |||
" '''''''''''''((((((((((((((())))))))))) ", | |||
" '''''''''''(((((((((((((((()))))))))) ) ", | |||
" '''''''''(((((((((((((((()))))))))) )))", | |||
" ''''''''***((((((((((((()))))))) )) ))))", | |||
" ''''''''''****((((((((((())))))))) ", | |||
" ''' ''''''''********((((((()))))))))) ", | |||
" '''''' '''''********(++(+((()))))))))) ", | |||
" '''''' ''**********(+++++()))))++))) ", | |||
" '''''' '*********(((+++++++++++++))) ", | |||
" '''' *********(((+++++++++++++) ", | |||
" ' ********++++++++++++++++ ", | |||
" ''' '''''' *******+++++++++++++++ ", | |||
" '''' ''''' *******++++++++++++++ ", | |||
" ' '''''' ******+++++++++++++ ", | |||
" '''' ****++++++++++++ ", | |||
" ***++++++++++ ", | |||
" ***** ++++++ ", | |||
" **** ", | |||
" *** ", | |||
" ***** ", | |||
" ******** ", | |||
" ******** ", | |||
" ***** ", | |||
" ***** ", | |||
" ** ** ", | |||
" *** " | |||
], | |||
"keys": [ | |||
"", | |||
"SIL", | |||
"BOG", | |||
"ALT", | |||
"AIR", | |||
"DOR", | |||
"VNUK", | |||
"LEF", | |||
"VESH", | |||
"ZUZ", | |||
"BIR" | |||
] | |||
} | |||
</syntaxhighlight> | |||
== Структура UTFGrid-файла == | |||
Представленный файл содержит три основных свойства: <code>data</code>, <code>grid</code>, <code>keys</code>. Свойство <code>keys</code> содержит список идентификаторов всех объектов тайла, в <code>data</code> представлены атрибутивные значения этих объектов. Свойство <code>grid</code> содержит текстовое представление растрового тайла. В нашем примере <code>grid</code> содержит 64 строки по 64 символа в каждой, то есть каждый такой символ соответствует объекту размером 4x4 пиксела в оригинальном растре (согласно спецификации UTFGrid по умолчанию использует шаг дискретизации 2x2 пиксела, но этот размер можно изменять, что соответственным образом скажется на размере UTFGrid-файла). | |||
== Как это работает == | |||
* Когда пользователь осуществляет некоторые действия (перемещает указатель мыши или кликает по карте) над тайлом, то происходит загрузка UTFGrid-файла, соответствующего этому тайлу; | |||
* Определяется положение указателя мыши внутри тайла и этому положению ставится в соответствие символ из свойства <code>grid</code> загруженного UTFGrid-файла. Предположим, указатель мыши наведён на объект "район Аэропорт". Соответствующий символ грида - "%"; | |||
* Согласно [https://github.com/mapbox/utfgrid-spec спецификации] вычисляется порядковый номер идентификатора в списке <code>keys</code>: находим [http://www.utf8-chartable.de/unicode-utf8-table.pl?utf8=dec десятичный код] символа грида в нашем случае он равен 37, вычитаем из него 1 (так как 37 > 35) и вычитаем 32. Получаем 4 (в Python для выполнения этой операции можно воспользоваться командой <code>ord</code>, обратная операция выполняется при помощи <code>unichr</code>); | |||
* В списке <code>keys</code> находим идентификатор, расположенный по указанному индексу (нумерация начинается с 0). В нашем случае <code>keys[4]="AIR"</code>; | |||
* Внутри объекта <code>data</code> по полученному идентификатору находим атрибутивную информацию. | |||
UTFGrid используется, в частности, в таком популярном продукте как [http://gis-lab.info/qa/tilemill-begin.html TileMil], [http://tiles.mapbox.com/answer42/map/geosample например]. Поддержка UTFGrid также реализована в библиотеке [http://dev.openlayers.org/releases/OpenLayers-2.12/examples/utfgrid.html OpenLayers]. Ознакомиться в интерактивном режиме с UTFGrid можно на сайте [http://mapbox.com/demo/visiblemap/ visible map]. | |||
== Преимущества и недостатки == | |||
С одной стороны, при небольшом количестве кликов на тайл, количество запросов будет сопоставимо с GetFeatureInfo для WMS-слоя. Однако объем переданных клиенту данных будет больше, так как веб-браузеру будет "в нагрузку" передана информация о тех объектах, которые не попадают в область его интересов. Так же клиенту будет передана "лишняя" информация в случае если один элемент будет размещен на нескольких тайлах, в том числе на тайлах разного уровня. С другой стороны, задача раздачи статического контента, как правило, куда менее затратна для веб-сервера с точки зрения потребляемых ресурсов и проще поддается масштабированию при росте нагрузки на сервер. | |||
По этой причине, вряд ли будет рационально использовать этот механизм для векторного слоя состоящего из миллионов объектов, в случае если им пользуется полтора пользователя. В проектах же с большой аудиторией, где регулярно происходит обращение к одним и тем же данным, использование UTFGrid видится вполне целесообразным. | |||
Так же, к недостаткам можно отнести то факт, что если растровый тайл построен на базе векторных данных, содержащих перекрывающиеся объекты, то с помощью UTFGrid мы не сможем закодировать информацию о таких объектах, то есть элементы списка <code>keys</code> сами по себе не могут быть списками. | |||
== Заключение == | |||
Мы рассмотрели лишь описание стандарта UTFGrid, пример создание полноценного сервиса с поддержкой UTFGrid будет рассмотрен в одной из следующих статей. Пример UTFGrid, представленный в статье, был сгенерирован при помощи [https://github.com/springmeyer/utfgrid-example-writers/blob/master/ogr_renderer.py ogr_renderer.py]. |
Текущая версия от 19:58, 5 сентября 2012
по адресу http://gis-lab.info/qa/utfgrid.html
Приведено описание стандарта UTFGrid и рассмотрен пример его использования.
Введение
Основное назначение любого картографического web-приложения - это предоставление клиенту пространственной информации, включающей геометрическую и атрибутивную составляющие. Поэтому, в любом случае, на начальном этапе каждый разработчик должен ответить на вопрос: "Какой формат передачи данных следует использовать в конкретном случае?" Как известно, все форматы передачи пространственной информации можно разделить на векторные и растровые. Использование векторных форматов (KML, GML, GeoJSON и т.д.) с одной стороны очень удобно: в клиентском приложении сразу становятся доступными и геометрическая, и атрибутивная составляющие, что обеспечивает простоту добавления приложению интерактивности. С другой же - область применения векторных форматов довольно ограничена и определяется главным образом объёмом передаваемых данных. Например, если векторный слой содержит несколько миллионов объектов, то во-первых, клиенту придется ждать пока эти данные будут загружены браузером, а во-вторых пока они будут отрисованы. При этом попытка изменения масштабного уровня вновь потребует перерисовки объектов, что также может занять продолжительное время. Естественно, что ни о каком комфорте при работе с таким приложением речи не идёт, что делает использование векторных форматов недопустимым. В этом случае более подходящим решением является использование растров.
Однако как быть с атрибутикой? Допустим, что пользователю нужна возможность получения информации об объекте, на который указывает указатель мыши. Конечно, можно реализовать серверный скрипт, которому будут передаваться текущие координаты, а в ответ возвращаться нужная информация (в случае WMS слоёв можно воспользоваться стандартной возможностью любого WMS-сервера - поддержкой запросов GetFeatureInfo). Однако в данной статье мы рассмотрим другой способ решения этой задачи, предложенный компанией MapBox, известный под именем UTFGrid (спецификация).
UTFGrid представляет собой стандарт, описывающий эффективный с точки зрения объёма передаваемых данных, способ кодирования атрибутивной информации объектов, представленных на растре. Данный стандарт был специально разработан для использования в Веб-браузерах и может использоваться, например, для вывода всплывающих подсказок при перемещении указателя мыши (например как здесь). В качестве контейнера UTFGrid использует формат JSON.
Рассмотрим пример данных, закодированных при помощи UTFGrid. Предположим, у нас есть некоторый растровый слой:
тогда его представление при помощи UTFGrid будет выглядеть следующим образом:
{
"data": {
"BOG": {
"name": "район Богородское"
},
"VNUK": {
"name": "район Внуково"
},
"ALT": {
"name": "Алтуфьевский район"
},
"SIL": {
"name": "район Силино"
},
"DOR": {
"name": "район Дорогомилово"
},
"ZUZ": {
"name": "район Зюзино"
},
"AIR": {
"name": "район Аэропорт"
},
"BIR": {
"name": "район Бирюлево Восточное"
},
"VESH": {
"name": "район Вешняки"
},
"LEF": {
"name": "район Лефортово"
}
},
"grid": [
" ! ",
" !!!!!! ",
" !!!!!!!! # ",
" !!!!!!!! ! ",
" !!!!!!!!!! !! ",
" !!!!! !!! !!!!!! ",
" !!!!!! ! !!!!!! ",
" !!!!! ! ",
" !!! !!! $$$$ ",
" !!!!!! $$ ",
" !!!!!! $$$$ ",
" !!!!!! $$$ ",
" !! $$ ",
" !! $$ $$ ",
" !! %$$$$$$$ ",
" !!! %%%%$$$$$$$$$$$ ",
" !!! %%%%%%%$$$$$$$$$$$$ ",
" !!!!!%%%%%%%%%%$$$$$$$$$$$$$ ",
" !!!%%%%%%%%%$$$$$$$$$$$### ",
" !!! !!!!%%%%%%%%%$$$$$$$$$$$#### ",
" !!!!!!!!!!%%%%%%%%$$$$$$$$$#$$##### ",
" !!!!!!!!!!%%%%%%%%&&$$$$$$$######### ",
" !!!!!!!!!!!%%%%%%%%&&&&&&&########### ",
" !!!!!!!!!!%%%%%%%&&&&&&&&############ ",
" ! !!!!!!!!%%%%%%&&&&&&&&############# ### ",
" '!!!!!!!!%%%%%%%&&&&&&################# ",
" !!!!!!!!%%%%%%%&&&&&############### ",
" !!!!!!!!!!%%%%%%&&&&&############### ",
" ''!!!!!!!!!!%%%%%%&&&&&############### ",
" '' !!!!!!!!!!%%%%%%&&&&&&&&&########### ",
" '' ''''''''!!!!%&&&&&&&&&&&&&&########## ",
" ''''''''!''!%&&&&&&&&&&&&(((######### ",
" ''''''''!'''&&&&&&&&&&&&(((#######))# ",
" '''''!!'''''&&&&&&&&&&&&(((#####)))# ))) ",
" '''''''''''&&&&&&&&&&&&&&((((##)))))))) ",
" '''''''''&&''&&&&&&&&&&&&(((((())))))) ) ",
" '''''''''''''&&&&&&&&((((((((((()))))))))))) ",
" ''''''''''''''&&&(((((((((((())())))))))))) ",
" '''''''''''''((((((((((((((())))))))))) ",
" '''''''''''(((((((((((((((()))))))))) ) ",
" '''''''''(((((((((((((((()))))))))) )))",
" ''''''''***((((((((((((()))))))) )) ))))",
" ''''''''''****((((((((((())))))))) ",
" ''' ''''''''********((((((()))))))))) ",
" '''''' '''''********(++(+((()))))))))) ",
" '''''' ''**********(+++++()))))++))) ",
" '''''' '*********(((+++++++++++++))) ",
" '''' *********(((+++++++++++++) ",
" ' ********++++++++++++++++ ",
" ''' '''''' *******+++++++++++++++ ",
" '''' ''''' *******++++++++++++++ ",
" ' '''''' ******+++++++++++++ ",
" '''' ****++++++++++++ ",
" ***++++++++++ ",
" ***** ++++++ ",
" **** ",
" *** ",
" ***** ",
" ******** ",
" ******** ",
" ***** ",
" ***** ",
" ** ** ",
" *** "
],
"keys": [
"",
"SIL",
"BOG",
"ALT",
"AIR",
"DOR",
"VNUK",
"LEF",
"VESH",
"ZUZ",
"BIR"
]
}
Структура UTFGrid-файла
Представленный файл содержит три основных свойства: data
, grid
, keys
. Свойство keys
содержит список идентификаторов всех объектов тайла, в data
представлены атрибутивные значения этих объектов. Свойство grid
содержит текстовое представление растрового тайла. В нашем примере grid
содержит 64 строки по 64 символа в каждой, то есть каждый такой символ соответствует объекту размером 4x4 пиксела в оригинальном растре (согласно спецификации UTFGrid по умолчанию использует шаг дискретизации 2x2 пиксела, но этот размер можно изменять, что соответственным образом скажется на размере UTFGrid-файла).
Как это работает
- Когда пользователь осуществляет некоторые действия (перемещает указатель мыши или кликает по карте) над тайлом, то происходит загрузка UTFGrid-файла, соответствующего этому тайлу;
- Определяется положение указателя мыши внутри тайла и этому положению ставится в соответствие символ из свойства
grid
загруженного UTFGrid-файла. Предположим, указатель мыши наведён на объект "район Аэропорт". Соответствующий символ грида - "%"; - Согласно спецификации вычисляется порядковый номер идентификатора в списке
keys
: находим десятичный код символа грида в нашем случае он равен 37, вычитаем из него 1 (так как 37 > 35) и вычитаем 32. Получаем 4 (в Python для выполнения этой операции можно воспользоваться командойord
, обратная операция выполняется при помощиunichr
); - В списке
keys
находим идентификатор, расположенный по указанному индексу (нумерация начинается с 0). В нашем случаеkeys[4]="AIR"
; - Внутри объекта
data
по полученному идентификатору находим атрибутивную информацию.
UTFGrid используется, в частности, в таком популярном продукте как TileMil, например. Поддержка UTFGrid также реализована в библиотеке OpenLayers. Ознакомиться в интерактивном режиме с UTFGrid можно на сайте visible map.
Преимущества и недостатки
С одной стороны, при небольшом количестве кликов на тайл, количество запросов будет сопоставимо с GetFeatureInfo для WMS-слоя. Однако объем переданных клиенту данных будет больше, так как веб-браузеру будет "в нагрузку" передана информация о тех объектах, которые не попадают в область его интересов. Так же клиенту будет передана "лишняя" информация в случае если один элемент будет размещен на нескольких тайлах, в том числе на тайлах разного уровня. С другой стороны, задача раздачи статического контента, как правило, куда менее затратна для веб-сервера с точки зрения потребляемых ресурсов и проще поддается масштабированию при росте нагрузки на сервер.
По этой причине, вряд ли будет рационально использовать этот механизм для векторного слоя состоящего из миллионов объектов, в случае если им пользуется полтора пользователя. В проектах же с большой аудиторией, где регулярно происходит обращение к одним и тем же данным, использование UTFGrid видится вполне целесообразным.
Так же, к недостаткам можно отнести то факт, что если растровый тайл построен на базе векторных данных, содержащих перекрывающиеся объекты, то с помощью UTFGrid мы не сможем закодировать информацию о таких объектах, то есть элементы списка keys
сами по себе не могут быть списками.
Заключение
Мы рассмотрели лишь описание стандарта UTFGrid, пример создание полноценного сервиса с поддержкой UTFGrid будет рассмотрен в одной из следующих статей. Пример UTFGrid, представленный в статье, был сгенерирован при помощи ogr_renderer.py.