Привет! Появилась необходимость на одном из серверов в нашей сети сделать «что-то вроде openstreetmap.org», но так, чтобы все это продолжало работать и без подключения к Интернету.
К сожалению я не нашел хорошего мануала на «Великом и Могучем» о том, как это реализовать, потому, потратив на это два дня, решил рассказать о том как мне это удалось.
Что было дано:
- FreeBSD 8.2
- PostgreSQL 8.4.9
- Apache 2.2
- Python 2.7.2
Вообще существует достаточно много вариантов как реализовать требуемое, но я решил остановиться на таком наборе инструментов:
Установка
1. Ставим PostGIS
С этим никаких проблем не возникло, он есть в портах, а именно /usr/ports/databases/postgis
После установки нужно перейти в папку /usr/local/share/postgis/contrib/postgis-1.5
и выполнить там postgis.sql и spatial_ref_sys.sql при помощи утилиты psql
2. Ставим Mapnik
Сам он также есть в портах:/usr/ports/graphics/mapnik
После установки нужно скачать необходимые утилиты, вот тут:
svn.openstreetmap.org/applications/rendering/mapnik/ (какие именно нам будут необходимы расскажу ниже).
3. Ставим TileCache
С TileCache все еще проще — качаем архив отсюда tilecache.org/tilecache-2.11.tar.gz.
Настройка
Естественно настройка куда как увлекательнее установки!
Для начала на картинке поясню как оно все должно работать:
Итак. Сначала нужно получить osm файл. Для этого есть много вариантов, например экспортировать прямо из openstreetmap.org (однако, там есть ограничения на размер области) или
скачать уже готовый экспорт, например отсюда: gis-lab.info/projects/osm_dump/
Этот файл нужно теперь загрузить в базу PostGIS, командой вроде
osm2pgsql -U user RU-SPE.osm
где user это логин к БД, а RU-SPE.osm это карта для загрузки. В моем случае это карта Санкт-Петербурга.
Вывод консоли должен быть примерно таким:
osm2pgsql SVN version 0.80.0 (32bit id space)
Using projection SRS 900913 (Spherical Mercator)
Setting up table: planet_osm_point
Setting up table: planet_osm_line
Setting up table: planet_osm_polygon
Setting up table: planet_osm_roads
Mid: Ram, scale=100
Reading in file: RU-SPE.osm
Processing: Node(1767k 176.7k/s) Way(264k 18.88k/s) Relation(7314 1828.50/s) parse time: 28s
Node stats: total(1767355), max(1633105798) in 10s
Way stats: total(264350), max(150391691) in 14s
Relation stats: total(7314), max(2024096) in 4s
Writing way (264k)
Writing relation (7314)
Committing transaction for planet_osm_point
Sorting data and creating indexes for planet_osm_point
Committing transaction for planet_osm_roads
Sorting data and creating indexes for planet_osm_roads
Committing transaction for planet_osm_line
Sorting data and creating indexes for planet_osm_line
Committing transaction for planet_osm_polygon
Sorting data and creating indexes for planet_osm_polygon
Indexes on planet_osm_roads created in 0s
Completed planet_osm_roads
Indexes on planet_osm_point created in 3s
Completed planet_osm_point
Indexes on planet_osm_line created in 4s
Completed planet_osm_line
Indexes on planet_osm_polygon created in 6s
Completed planet_osm_polygon
Osm2pgsql took 48s overall
Если никаких ошибок нет, то поехали дальше.
Теперь нам нужны границы и береговая линия всего мира — это будет подложкой для нашей карты. Если этого не делать, подложка будет просто одноцветной.
Чтобы держать все в одном месте и в порядке, создадим папку /mapnik/ в своем домашнем каталоге.
Теперь перемещаемся туда и загружаем туда эти границы, для этого воспользуемся командами:
wget tile.openstreetmap.org/world_boundaries-spherical.tgz
tar xvzf world_boundaries-spherical.tgz
wget tile.openstreetmap.org/processed_p.tar.bz2
tar xvjf processed_p.tar.bz2 -C world_boundaries
wget tile.openstreetmap.org/shoreline_300.tar.bz2
tar xjf shoreline_300.tar.bz2 -C world_boundaries
wget www.naturalearthdata.com/http//www.naturalearthdata.com/download/110m/cultural/110m-admin-0-boundary-lines.zip
unzip 110m-admin-0-boundary-lines.zip -d world_boundaries
wget www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/10m-populated-places.zip
unzip 10m-populated-places.zip -d world_boundaries
Выше я обещал рассказать какие утилиты из svn.openstreetmap.org/applications/rendering/mapnik/ нам будут нужны.
Так вот, нам будут нужны:
generate_xml.py (Скорее всего придется подредактировать файл, и заменить import mapnik на import mapnik2 as mapnik)
osm.xml
и папки
inc/
symbols/
Еще может понадобиться скрипт для обновления файла osm.xml, его можно взять тут: github.com/mapnik/mapnik/tree/master/utils/upgrade_map_xml
А можно скачать osm.xml, который я уже поправил вот отсюда: pastebin.com/bMsXytcc
Теперь сгенерируем map.xml, для этого запустим:
./generate_xml.py osm.xml --host localhost --user user --dbname gis --symbols symbols/ --world_boundaries world_boundaries/ --port 5432 --epsg='900913' --accept-none > map.xml
где --accept-none значит принимать непереданные параметры как пустые.
У нас должен получиться достаточно большой файл map.xml
Уже почти все, осталось сконфигурировать только TileCache.
Скачанный архив распакуем в /usr/local/www/data/tilecache
. Тут нужно настроить всего два файла: tilecache.cfg и index.html.
В первом нужно объяснить TileCache откуда брать данные (а брать их надо из map.xml, который мы только что сделали).
Для этого добавим туда таки строки:
[osm-map]
type=MapnikLayer
mapfile=/usr/home/user/mapnik/map.xml
spherical_mercator=true
bbox=-20037508.34,-20037508.34,20037508.34,20037508.34
resolutions=2445.984375,1222.9921875,611.49609375,305.748046875,152.8740234375,76.43701171875,38.218505859375,19.1092529296875,9.55462646484375,4.777314,2.388657,1.1943285,0.59716427,0.298582
metaTile=true
metaSize=8,8
metaBuffer=40
levels=12
extent_type=loose
Важные параметры тут:
mapfile=/usr/home/user/mapnik/map.xml
путь к файлу с данными
bbox=-20037508.34,-20037508.34,20037508.34,20037508.34
границы области. Это границы для всего мира, подробнее можно прочитать тут: docs.openlayers.org/library/spherical_mercator.html
resolutions=… вот это самое интересное. Эти числа — разрешения разных уровней приближения (zoom level), которые должны быть такими, что при делении на них число 20037508.34*2/256 будет давать степень двойки. Это число — сторона «квадрата» мира деленная на сторону одного тайла (маленького квадратика), которая по-умолчанию равна 256 пикселей.
Все другие слои лучше закомментировать для проверки того что наш работает.
Теперь перейдем к index.html.
В нем нужно настроить функцию init(), например так:
function init(){
map = new OpenLayers.Map("map", {
maxExtent: new OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34),
numZoomLevels:14,
maxResolution:156543.03125/64,
units:'m',
projection: "EPSG:900913",
displayProjection: new OpenLayers.Projection("EPSG:4326")
});
layer = new OpenLayers.Layer.WMS( "OSM",
"tilecache.cgi?", {layers: 'osm-map', format: 'image/png'} );
map.addLayer(layer);
map.addControl(new OpenLayers.Control.Permalink());
map.addControl(new OpenLayers.Control.PanZoomBar());
map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false}));
map.addControl(new OpenLayers.Control.Permalink());
map.addControl(new OpenLayers.Control.Permalink('permalink'));
map.addControl(new OpenLayers.Control.MousePosition());
map.addControl(new OpenLayers.Control.OverviewMap());
map.addControl(new OpenLayers.Control.KeyboardDefaults());
if (!map.getCenter()) {
var proj = new OpenLayers.Projection("EPSG:4326");
var point = new OpenLayers.LonLat(30, 60);
map.setCenter(point.transform(proj, map.getProjectionObject()),4);
}
}
Нужно обратить внимание на следующие параметры:
maxExtent: new OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34)
границы должны быть точно такими же, как и в tilecache.cfg.
maxResolution:156543.03125/64
это 2445.984375, т.е. максимальное разрешение.
map.setCenter(point.transform(proj, map.getProjectionObject()),4);
установка центра карты и начального зума так, чтобы был виден общий план Санкт-Петербурга.
Мелкий штрих: разрешить апачу выполнять tilecache.cgi:
<Directory "/usr/local/www/apache22/cgi-bin">
AllowOverride None
Options None
Order allow,deny
Allow from all
И chmod 755 tilecache.cgi
Проверяем
Для проверки нужно просто открыть браузером папку tilecache и если все прошло хорошо, увидеть вот такую карту (правда тут еще загружена Ленинградская область):
Итого
В итоге должен получиться сервер, умеющий читать данные из базы данных PostGIS и превращать их в тайлы без подключения к Интернету.
Постараюсь ответить на вопросы, если что-то пойдет не так.
Автор: k102