Основы работы динамических TMS-сервисов

Материал из GIS-Lab
Перейти к навигации Перейти к поиску

Введение

TMS-сервис может функционировать в одном из двух режимов - статическом и динамическом. В первом случае это ни что иное, как просто набор файлов, организованных определённым образом в файловой системе - тайловый кэш (здесь и далее в статье мы предполагаем, что тайловый сервис отвечает лишь за передачу самих тайлов (Tile Resources), остальные ресурсы, описываемые в спецификации, мы рассматривать не будем в виду их тривиальности). При запросе конкретного тайла HTTP-сервер (Apache, nginx) самостоятельно отображает запрашиваемый URL на структуру файловой системы и возвращает клиенту нужный тайл. Пример организации тайлового кэша:

└── admin_EPSG3857
    ├── 1
    │   ├── 0
    │   │   ├── 0.png
    │   │   └── 1.png
    │   └── 1
    │       ├── 0.png
    │       └── 1.png
    └── 2
        ├── 0
        │   ├── 0.png
        │   ├── 1.png
        │   ├── 2.png
        │   └── 3.png
        ├── 1
        │   ├── 0.png
        │   ├── 1.png
        │   ├── 2.png
        │   └── 3.png
        ├── 2
        │   ├── 0.png
        │   ├── 1.png
        │   ├── 2.png
        │   └── 3.png
        └── 3
            ├── 0.png
            ├── 1.png
            ├── 2.png
            └── 3.png

В данном случае, чтобы получить, тайл с координатами (0, 0) на втором масштабном уровне, необходимо выполнить запрос, который может выглядеть следующим образом:

http://10.22.0.9/tms/1.0.0/admin_EPSG3857/2/0/0.png

Для создания тайлового кэша существует различное программное обеспечение, например, утилиты gdal2tiles и mapproxy-seed, TileMill, QTiles. Процесс создания тайлового кэша называется сидированием (seeding). Данная процедура весьма требовательна к объёму жесткого диска и может занимать очень много времени. Например, время создания тайлового кэша на территорию Казахстана вплоть до 16 масштабного уровня (профиль global-mercator) при средней наполненности слоёв составляет 2-3 дня, поэтому на практике данный способы используется для подготовки кэшей карт небольших территорий или для создания кэшей определённых масштабных уровней.

Второй режим работы тайлового сервиса - динамический - предполагает, что никакого тайлового кэша нет, а запрашиваемые клиентом тайлы генерируются по запросу "на лету".

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

Чтобы разобраться с тем, как организована работа современных тайловых серверов (TileCache, MapProxy) (фактически работающих в смешанном режиме), попытаемся написать собственный динамический TMS-сервер.

Архитектура динамического TMS-сервиса

Логику любого динамического TMS-сервиса можно упрощённо представить в виде следующей схемы:

Схема работы динамического TMS-сервиса

Из данной схемы следует, что для создания сервиса необходимы инструменты, позволяющие следующее:

  1. Элемент нумерованного списка
  2. Элемент маркированного списка
  3. Извлекать информацию о координатах тайла из URL
  4. По вычисленным координатам тайла получать его охват в единицах измерения карты
  5. Извлекать данные из хранилища по переданному охвату
  6. Отрисовывать (рендерить) извлечённые данные
  7. Формировать HTTP ответ, содержащий готовый тайл

Каждая из этих задач может быть решена с помощью широкого спектра инструментов (библиотек), не связанных друг с другом. Например, процедуру извлечения данных из хранилища можно выполнить с помощью таких библиотек как GDAL/OGR или OWSLib, рендеринга - Mapnik или MapScript и т.д.

Выбор инструментов

Для решения 1 и 5 задачи подходит любой Веб-фреймворк. Поскольку наши требования к его функциональности достаточно скромные, то нет нужды использовать что-то вроде Django или Pyramid, вполне можно обойтись любым микрофреймворком, таким как Flask или Bottle. Остановимся на последнем.

2-я задача довольно простая, решим её самостоятельно без привлечения сторонних библиотек.

Для решения 3-й и 4-й задачи воспользуемся Mapnik-ом. Заметьте, что Mapnik в данном случае выступает не только в роли рендерера, но и в роли библиотеки, умеющей извлекать данные из хранилища. Полный список форматов, которые умеет читать Mapnik, доступен здесь. Mapnik вообще очень универсальный инструмент, позволяющий, в частности, отрисовывать объекты и без предоставления прямого доступа к хранилищу.

Установка и настройка Mapnik

Mapnik присутствует в репозиториях Debian GNU/Linux 7.0 и поэтому его установка сводится к выполнению следующей команды:

sudo aptitude install libmapnik2-2.0 mapnik-utils

Информацию об установке Mapnik на другие платформы можно найти на странице Mapnik Installation.

Чтобы убедиться в том, что Mapnik установился успешно, выполните команду (в используемой версии Debian модуль называется mapnik2, в других версиях или на других платформах может быть использовано имя mapnik):

python -c "import mapnik2"

Если в ответ на эту команду не последует никаких сообщение об ошибках, значит Mapnik установился корректно.

Mapnik поддерживает 2 способа конфигурирования - с помощью команд Python и с помощью специального *.xml файла. Основы конфигурирования Mapnik с помощью XML можно найти на странице Mapnik Getting Started In XML. В рамках нашей задачи будем использовать именно этот подход.

Создадим файл mapnik-config.xml и поместим в него следующее содержимое:

<?xml version="1.0" encoding="utf-8"?>
<Map srs="+init=epsg:32644" background-color="#b8dee6">
    <Style name="Admin style">
        <Rule>
            <PolygonSymbolizer fill="#ffffff"/>
            <LineSymbolizer stroke="#85c5d3" stroke-width="2" stroke-linejoin="round" />
        </Rule>
    </Style>
    <Style name="Ecoregions style">
        <Rule>
            <LineSymbolizer stroke="#85c5d3" stroke-width="0.5" stroke-linejoin="round" />
        </Rule>
    </Style>
    <Layer name="admin" srs="+init=epsg:4326">
        <StyleName>Admin style</StyleName>
        <Datasource>
            <Parameter name="dbname">geosample</Parameter>
            <Parameter name="geometry_field">the_geom</Parameter>
            <Parameter name="host">gis-lab.info</Parameter>
            <Parameter name="password">guest</Parameter>
            <Parameter name="table">(select the_geom from admin where id=2) as admin</Parameter>
            <Parameter name="type">postgis</Parameter>
            <Parameter name="user">guest</Parameter>
        </Datasource>
    </Layer>
    <Layer name="ecoregions" srs="+init=epsg:4326">
        <StyleName>Ecoregions style</StyleName>
        <Datasource>
            <Parameter name="dbname">geosample</Parameter>
            <Parameter name="geometry_field">the_geom</Parameter>
            <Parameter name="host">gis-lab.info</Parameter>
            <Parameter name="password">guest</Parameter>
            <Parameter name="table">(select the_geom from ecoregions where name='Алтайский край') as ecoregions</Parameter>
            <Parameter name="type">postgis</Parameter>
            <Parameter name="user">guest</Parameter>
        </Datasource>
    </Layer>
</Map>

Данный файл сообщает Mapnik-у, что наша карта будет состоять из двух слоёв набора Geosample - admin и ecoregiogions (только Алтайский край), расположенных в базе данных PostGIS, и отрисованных стилями Admin style и Ecoregions style, описанных здесь же в *.xml файле. Также обратите внимание, что мы перепроецируем исходные данные из географической системы координат в проекцию UTM зона 44 EPSG:32644 опять же средствами самого Mapnik-а.

Проверим, что наш *.xml файл составлен корректно. Для этого в той же директории создадим файл test.py и поместим в него следующий код:

import mapnik2 as mapnik
m = mapnik.Map(256,256)
mapnik.load_map(m, 'mapnik-config.xml')
m.zoom_all()
mapnik.render_to_file(m,'altay.png', 'png')

После чего выполним его:

python test.py

Представленный код считывает настройки Mapnik-а из файла mapnik-config.xml и отрисовывает карту в файл altay.png, расположенный в этой же директории. Откройте его (если операция выполняется на сервере без графического интерфейса, то просто сделайте симлинк в директорию /var/www/ и откройте изображение в браузере), он должен выглядеть следующим образом:

Пример карты, отрисованной с помощью Mapnik

Установка Bottle

Установим Bottle в виртуальное окружение:

sudo aptitude install python-virtualenv
cd ~
virtualenv --system-site-packages tms
source tms/bin/activate
pip install bottle

Подробнее об установки Bottle здесь.

Мы создали директорию tms с ключом --system-site-packages. Это сделано для того, чтобы в виртуальном окружении были доступны системные библиотеки, в частности Mapnik.

Установим HTTP-сервер Waitress:

pip install waitress

Создание собственного TMS-сервера

Переходим в директорию нашего виртуального окружения tms:

Заключение

Таким образом, мы написали свой собственный примитивный TMS-сервер в котором пока нет ни возможности кэширования тайлов, ни многих других важных функций, но который наглядно отражает подходы, используемые современным ПО данного класса.