RU:Создание локального OSM-сервера
От автора
Данная инструкция не претендует на абсолютную точность. Написана по памяти, с уточнением мест, где лежат грабли, на которые наступил автор. За точной информацией стоит сходить по ссылкам, в которых по шагам расписывается установка Mapnik, Mapnik/PostGIS, The_Rails_Port, Mod_tile, tilecache[1],osmosis,openlayers и примеры кода для openlayers[2]. Основная задача данной инструкции объяснить принцип и логику построения подобной системы, указать направления получения информации и изучения, чтобы читающий, при установке подобной системы тыкался носом как котёнок меньше, чем это делал автор, а так же не утомлять повторными расспросами уважаемое сообщество[3]. Если же читающие добавят информации, уточнят неточности и в конце концов сделают из этой страницы полноценное руководство - то автор будет рад.
Успехов в создании локального сервера!
Постановка задачи
Техническое задание
Необходимо иметь локальный (в локальной сети предприятия) сервер, на который можно сохранять коммерческие гео-данные, преднозначенные для использования внутри предприятия. Данные заносить с помощью josm. Так же на этом локальном сервере должна рисоваться и отображаться пользователям карта по этим данным.
Более того, необходимо иметь обновляемую копию данных России в виде локальной базы, по которой будет рисоваться подложка/слой OSM. Т.е. данные OSM и внутренних гео-данных предприятия не будут смешиваться. OSM данные будут использоваться как слой для рисования в JOSM или же как полупрозрачный фон-подложка при просмотре карт, построенных по гео-данным предприятия.
Дизайн
Данная задача реализуется следующими инструментами:
- postgres+расширение postgis как хранилище гео-данных
- Apache как плаформа для web-содержимого
- Rails-сервер как основной сервер OSM (основная логика OSM - api, пользователи, web, сохранение и обработка треков и т.д.)
- mapnik как рендер карты, т.е. продукт, который занимается созданием *.png из гео-данных в postgres
- mod_tile как сервис (и модуль для apache) организации отрисовки (рендеринга) "на лету" и отдачи *.png по запросу пользователя (при обращении к конкретному "тайлу")
- tilecache[4] как сервис, отрисовки (рендеринга) "на лету" и отдачи *.png по запросу пользователя в виде простых запросов (в виде z/x/y.png), так и в виде запросов по координатам, необходимым для отрисовки OSM данных в виде полу-прозрачных слоёв.
- osmosis и osm2pgsql как утилиты для экспорта/импорта в базы и вычисления diff-файлов изменений OSM-данных.
- openlayers как js-библиотеки для создания html-страничек с картами, базовыми элементами управления и т.п.
Логика
Основная схема представлена на изображении:
Логика работы системы состоит в следующем
- Создаём базу в postgres, где будут храниться наши данные, назовём её drsk_osm.
- Ставим rails-сервер, настраиваем его на нашу базу. Чтобы данные, передаваемые редактором в rails-сервер через api складывались в нашу базу.
- Создаём базу в postgres с расширением postgis. Назовём её drsk_gis. В эту базу регулярно будут мигрировать (скриптами) данные из базы drsk_osm.
- Устанавливаем mapnik. Настраиваем (создаём конфиг drsk.xml, содержащий стили, логин/пароль по доступу к базе) его на доступ к базе drsk_gis.
- Устанавливаем mod_tile, настраиваем его на наш конфиг drsk.xml. Теперь mod_tile будет генерировать тайлы по нашему конфигу и отдавать их через apache.
- Подправляем конфиг rails-сервера public/openlayers/OpenStreetMap.js, заменяя
http://a.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png
наhttp://наш_локальный_сервер_osm/drsk/${z}/${x}/${y}.png
так, чтобы тайлы брались с mod_tile с секции конфига о drsk. - Пишем скрипт, который будет регулярно "перекидывать" данные с drsk_osm в drsk_gis, генерировать список измённых тайлов (проанализировав изменения между старым срезом базы drsk_osm и новым срезом базы drsk_osm), передавать этот список mod_tile-у для перерисовки этих тайлов.
Первый этап выполнен - теперь мы можем подключаться josm-ом на http://наш_локальный_сервер_osm/api и добавлять туда данные, а потом просматривать их как тайлы на основной странице http://наш_локальный_сервер_osm/.
Логика настройки подложки osm из данных карты с openstreetmap.org. Т.е. мы хотим брать (регулярно) дамп, к примеру, России и отрисовывать его локально. И пользоваться этим слоем как подложкой для рисования/просмотра своих данных предприятия. При этом данные предприятия и данные свободной карты не смешиваются. Итак, донастройка сервера:
- Создаём базу local_osm_gis в postgres с расширением postgis.
- Скачиваем дамп России в osm.bz2, заливаем его в эту базу.
- Настраиваем конфиг в mapnik для доступа и отрисовки базы local_osm_gis, например local_osm.xml.
- Прописываем секцию в конфиг mod_tile для отрисовки по конфигу local_osm.xml.
- Подправляем конфиг rails-сервера public/openlayers/OpenStreetMap.js, заменяя http://a.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png в секции Osmarender на http://наш_локальный_сервер_osm/osm/${z}/${x}/${y}.png так, чтобы тайлы брались с mod_tile с секции об osm.
- Пишем скрипт, который будет регулярно скачивать изменения для России с http://data.gis-lab.info/osm_dump/diff/RU/ , "доливать" эти изменения в базу local_osm_gis, генерировать список измённых тайлов (проанализировав файл скачанных изменений), передавать этот список mod_tile-у для перерисовки этих тайлов.
Установка и настройка компонент
Debian
Взято во многом тут.
Ставим Rails OSM Server
Устанавливаем нужные пакеты:
Новый вариант:
apt-get install postgresql-9.1-postgis postgresql-server-dev-9.1 postgresql-contrib-9.1 ruby-rmagick rails rubygems git ruby1.9.3 ruby-switch libxml-ruby1.9.1 libxml2-dev ruby1.9.1 libruby1.9.1 ruby1.9.1-dev ri1.9.1 libmagickwand-dev libxml2-dev libxslt1-dev apache2 apache2-threaded-dev build-essential git-core postgresql postgresql-contrib libpq-dev postgresql-server-dev-all libsasl2-dev checkinstall osm2pgsql php5-odbc php-db php5-pgsql python-mapnik2 gem1.9.1 install bundle --no-rdoc --no-ri mkdir -p /opt/osm cd /opt/osm/ git clone https://github.com/openstreetmap/openstreetmap-website.git cd openstreetmap-website bundle install
Устанавливаем nodejs:
cd /tmp wget -N http://nodejs.org/dist/node-latest.tar.gz tar xzvf node-latest.tar.gz && cd node-v* ./configure checkinstall -y --install=no --pkgversion $(echo $(pwd) | sed -n -re's/.+node-v(.+)$/\1/p') make -j$(($(nproc)+1)) install dpkg -i node_*
Правим конфиги, задаём пользователя БД:
cp config/example.application.yml config/application.yml cp config/example.database.yml config/database.yml
Создаём пользователя postgres и базы:
su postgres psql CREATE USER openstreetmap WITH PASSWORD 'myPassword'; \q
Создаём базы (где drsk_osm - это основная база, имя исправлено со стандартного openstreetmap в файле **config/database.yml**):
createdb -E UTF8 -O openstreetmap drsk_osm createdb -E UTF8 -O openstreetmap osm_test createdb -E UTF8 -O openstreetmap osm
Даём возможность пересоздания тестовой таблицы пользователю, чтобы прошёл тест rake (ниже):
psql GRANT ALL PRIVILEGES on DATABASE osm_test to openstreetmap; ALTER USER openstreetmap with CREATEDB; alter role openstreetmap superuser; \q
Ставим расширение **btree_gist** иначе migrate вывалится с ошибкой:
psql -d drsk_osm -c "CREATE EXTENSION btree_gist" psql -d osm_test -c "CREATE EXTENSION btree_gist" psql -d osm -c "CREATE EXTENSION btree_gist"
Переходим в root:
exit
Компилим библиотеки:
cd /opt/osm/openstreetmap-website/db/functions make libpgosm.so cd ../.. su postgres psql -d drsk_osm -c "CREATE FUNCTION maptile_for_point(int8, int8, int4) RETURNS int4 AS '`pwd`/db/functions/libpgosm', 'maptile_for_point' LANGUAGE C STRICT" psql -d drsk_osm -c "CREATE FUNCTION tile_for_point(int4, int4) RETURNS int8 AS '`pwd`/db/functions/libpgosm', 'tile_for_point' LANGUAGE C STRICT" psql -d drsk_osm -c "CREATE FUNCTION xid_to_int4(xid) RETURNS int4 AS '`pwd`/db/functions/libpgosm', 'xid_to_int4' LANGUAGE C STRICT"
Выходим из под пользователя postgres в root:
exit
Запускаем инициализацию баз:
bundle exec rake db:migrate RAILS_ENV=development
Запускаем тест:
bundle exec rake test
Вывлится несколько ошибок вида:
Attribute lat redefined
Их можно игнорировать.
Собственно можно запустить сервер:
bundle exec rails server
Настройка API-сервера
cd /opt/osm/openstreetmap-website/config
Правим параметры в application.yml:
server_url: "osm.company.ru" generator: "OSM Объекты Компании" email_from: "Компания OSM <osm@company.ru>" email_return_path: "osm@company.ru"
Правим параметры в database.yml:
development:
adapter: postgresql
database: drsk_osm
username: openstreetmap
password: XXXXXXX
host: localhost
encoding: utf8
test:
adapter: postgresql
database: osm_test
username: openstreetmap
password: XXXXXXX
host: localhost
encoding: utf8
production:
adapter: postgresql
database: osm
username: openstreetmap
password: XXXXXX
host: localhost
encoding: utf8
Добавляем сервис OSM в автозагрузку
Создаём скрипт запуска **/etc/init.d/osm-rails-server**. Скрипт нужно доделывать stop почему-то не работает (по TERM-сигналу):
#! /bin/sh
### BEGIN INIT INFO
# Provides: osm_rails
# Required-Start: $syslog $time $network
# Required-Stop: $syslog $time $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Deferred execution scheduler
# Description: Debian init script for the atd deferred executions
# scheduler
## END INIT INFO
#
# Author: progserega <semenov@rsprim.ru>
#
OSM_PATH=/opt/osm/openstreetmap-website
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
DAEMON=/usr/bin/ruby1.9.1
PIDFILE=/var/run/osm-rails-server.pid
#EXE=/usr/local/bin/bundle
EXE=/usr/local/bin/rails
test -x $DAEMON || exit 0
. /lib/lsb/init-functions
case "$1" in
start)
log_daemon_msg "Starting OSM Rails Server" "osm-rails-server"
cd ${OSM_PATH}
#start-stop-daemon --start -p $PIDFILE -b --chdir ${OSM_PATH} --exec ${EXE} -- exec rails server
start-stop-daemon --start -p $PIDFILE -b --chdir ${OSM_PATH} --exec ${EXE} -- server
log_end_msg $?
;;
stop)
log_daemon_msg "Stopping OSM Rails Server" "osm-rails-server"
killproc -p $PIDFILE $DAEMON
log_end_msg $?
;;
force-kill)
log_daemon_msg "Force kill OSM Rails Server" "osm-rails-server"
killall -9 ruby1.9.1
log_end_msg $?
;;
force-reload|restart)
$0 stop
$0 start
;;
status)
status_of_proc -p $PIDFILE $DAEMON rails && exit 0 || exit $?
;;
*)
echo "Usage: /etc/init.d/atd {start|stop|force-kill|restart|force-reload|status}"
exit 1
;;
esac
exit 0
Добавляем скрипт в автозапуск:
update-rc.d osm-rails-server enable
Или:
update-rc.d osm-rails-server start
Или
update-rc.d osm-rails-server start 3
Включение apache2 прокси для OSM-Rails
Т.к. Rails-порт запускается на порту 3000, то добавляем виртуальный хост в apache2 с перенаправлением на Rails. Создаём файл **/etc/apache2/sites-available/03_osm.rs.int_vhost.conf**:
<proxy balancer://mongrelcluster>
BalancerMember http://127.0.0.1:3000
</proxy>
#forward requests to mongrel cluster
<virtualhost *:80>
ServerName osm.rs.int
ServerAlias osm.prim.drsk.ru
ProxyPass / balancer://mongrelcluster/
ProxyPassReverse / balancer://mongrelcluster/
ProxyPreserveHost on
ErrorLog /var/log/apache2/osm.rs.int-error.log
</virtualhost>
Включаем виртуальный хост:
cd /etc/apache2/sites-enabled ln -s ../sites-available/03_osm.rs.int_vhost.conf 03_osm.rs.int_vhost.conf
Включаем модуль **proxy** в apache2:
a2enmod proxy a2enmod proxy_http a2enmod proxy_balancer service apache2 restart
Базовая настройка пересылки почты
Для того, чтобы сервер OSM мог отправлять почту во вне, нужно провести настройку **exim4**.
И запустить команду:
dpkg-reconfigure exim4-config
И сказать, что можно отправлять в интернет, relay только для localhost.
Импорт существующей базы данных объектов
Ставим osmosis
apt-get install osmosis
Заливаем базу
Отрисовка гео-данных
Настраиваем сервисы отрисовки данных - ставим сервисы WMS и TMS слоёв, настраиваем их.
Установка с помощью puppet-шаблона
Для упрощения этой, как оказалось, непростой задачи (нужно было патчить не один пакет, т.к. вместе они работать не хотели), автор написал puppet шаблон. В принципе, это просто набор правил в определённом несложном синтаксисе (см. документацию по ресурсам puppet), по которым производятся последовательные действия. Даже не имея настроенного puppet-сервера, можно, согласно этим правилам установить соответствующие сервисы.
Если Вы далеки от puppet, то можно этот шаблон использовать как инструкцию:
Основная последовательность действий по установке находится тут.
В этой инструкции используются файлы, которые лежат тут, а так же шаблоны, которые лежат тут. В случае шаблонов необходимо будет их немного подправить, т.к. внутри них используются переменные из osm-render-server.pp. Т.е. нужно будет заменить вставки вида db_user="<%= @db_user %>" на db_user="your_db_user_name" и т.п.
Ручная установка
Ставим mapnik
apt-get install python-mapnik2 mapnik-utils
Ставим tilecache
apt-get install tilecache
Ставим kothic
Берём данные из систем контроля версий:
mkdir -p /opt/osm/mapcss/kothic_converter_src/ cd /opt/osm/mapcss/kothic_converter_src/ hg clone https://code.google.com/p/kothic/
Накладываем патч для обеспечения парольного доступа к базе:
diff -ru kothic_orig/src/komap.conf kothic/src/komap.conf
--- kothic_orig/src/komap.conf 2013-02-06 16:17:11.000000000 +1100
+++ kothic/src/komap.conf 2013-02-08 09:38:40.000000000 +1100
@@ -3,9 +3,12 @@
db_proj = +init=epsg:3857
table_prefix = planet_osm_
db_user = postgres
+db_passwd = XXXXXX
db_name = drsk_gis
+db_host = localhost
+db_port = 5432
db_srid = 900913
world_bnd_path = /opt/osm/mapnik/world_boundaries
cleantopo_dem_path = /raid/srtm/Full/CleanTOPO2merc.tif
srtm_dem_path = /raid/srtm/srtmm.vrt
diff -ru kothic_orig/src/komap.py kothic/src/komap.py
--- kothic_orig/src/komap.py 2013-02-05 11:11:22.000000000 +1100
+++ kothic/src/komap.py 2013-02-08 09:35:10.000000000 +1100
@@ -78,6 +78,9 @@
libkomapnik.table_prefix = config.get("mapnik", "table_prefix")
libkomapnik.db_user = config.get("mapnik", "db_user")
libkomapnik.db_name = config.get("mapnik", "db_name")
+libkomapnik.db_passwd = config.get("mapnik", "db_passwd")
+libkomapnik.db_host = config.get("mapnik", "db_host")
+libkomapnik.db_port = config.get("mapnik", "db_port")
libkomapnik.db_srid = config.get("mapnik", "db_srid")
libkomapnik.icons_path = config.get("mapnik", "icons_path")
libkomapnik.world_bnd_path = config.get("mapnik", "world_bnd_path")
diff -ru kothic_orig/src/libkomapnik.py kothic/src/libkomapnik.py
--- kothic_orig/src/libkomapnik.py 2012-07-10 11:59:58.000000000 +1100
+++ kothic/src/libkomapnik.py 2013-02-08 09:37:34.000000000 +1100
@@ -27,6 +27,9 @@
table_prefix = ""
db_user = ""
db_name = ""
+db_passwd = ""
+db_host = ""
+db_port = ""
db_srid = ""
icons_path = ""
world_bnd_path = ""
@@ -343,13 +346,16 @@
<Parameter name="st_prefix">true</Parameter>
<Parameter name="user">%s</Parameter>
<Parameter name="dbname">%s</Parameter>
+ <Parameter name="password">%s</Parameter>
+ <Parameter name="host">%s</Parameter>
+ <Parameter name="port">%s</Parameter>
<Parameter name="srid">%s</Parameter>
<Parameter name="geometry_field">way</Parameter>
<Parameter name="geometry_table">%s%s</Parameter>
<Parameter name="estimate_extent">false</Parameter>
<Parameter name="extent">-20037508.342789244, -20037508.342780735, 20037508.342789244, 20037508.342780709</Parameter>
</Datasource>
- </Layer>"""%(layer_id, db_proj, subs, interesting_tags, table_prefix, geom, sql, intersection_SQL, db_user, db_name, db_srid, table_prefix, geom)
+ </Layer>"""%(layer_id, db_proj, subs, interesting_tags, table_prefix, geom, sql, intersection_SQL, db_user, db_name, db_passwd, db_host, db_port, db_srid, table_prefix, geom)
elif type == "postgis-process":
return """
<Layer name="l%s" status="on" srs="%s">
@@ -364,13 +370,16 @@
<Parameter name="st_prefix">true</Parameter>
<Parameter name="user">%s</Parameter>
<Parameter name="dbname">%s</Parameter>
+ <Parameter name="password">%s</Parameter>
+ <Parameter name="host">%s</Parameter>
+ <Parameter name="port">%s</Parameter>
<Parameter name="srid">%s</Parameter>
<Parameter name="geometry_field">way</Parameter>
<Parameter name="geometry_table">%s%s</Parameter>
<Parameter name="estimate_extent">false</Parameter>
<Parameter name="extent">-20037508.342789244, -20037508.342780735, 20037508.342789244, 20037508.342780709</Parameter>
</Datasource>
- </Layer>"""%(layer_id, db_proj, subs, sql, intersection_SQL, db_user, db_name, db_srid, table_prefix, geom)
+ </Layer>"""%(layer_id, db_proj, subs, sql, intersection_SQL, db_user, db_name, db_passwd, db_host, db_port, db_srid, table_prefix, geom)
elif type == "coast":
if zoom < 9:
return """
Правим конфиг /opt/osm/mapcss/kothic_converter_src/kothic/src/komap.conf:
[mapnik]
map_proj = +init=epsg:3857
db_proj = +init=epsg:3857
table_prefix = planet_osm_
db_user = postgres
db_passwd = XXXXXXX
db_name = drsk_gis
db_host = localhost
db_port = 5432
db_srid = 900913
icons_path = /opt/osm/mapnik/mapnik_icons/drsk/
world_bnd_path = /opt/osm/mapnik/world_boundaries
cleantopo_dem_path = /raid/srtm/Full/CleanTOPO2merc.tif
srtm_dem_path = /raid/srtm/srtmm.vrt
cleantopo_hs_path = /raid/srtm/Full/CleanTOPO2merchs.tif
srtm_hs_path = /raid/srtm/srtmhs.vrt
Ошибки
После заливки данных osmosis-ом проблемы с добавлением данных/пользователей на карту/сайт
Это происходит потому, что osmosis не обновляет индексы текущих идентификаторов (точек, линий, отношений, пользователей и т.д.). В результате сервер ругается у себя в логи (/opt/osm/openstreetmap-website/log/development.log) примерно так:
ERROR: duplicate key value violates unique constraint "current_nodes_pkey1"
Для этого нужно обновить индексы в базе (в нашем случае в drsk_osm):
SELECT pg_catalog.setval('acls_id_seq', (SELECT MAX(id) FROM acls));
SELECT pg_catalog.setval('changesets_id_seq', (SELECT MAX(id) FROM changesets ));
SELECT pg_catalog.setval('client_applications_id_seq', (SELECT MAX(id) FROM client_applications));
SELECT pg_catalog.setval('current_nodes_id_seq', (SELECT MAX(id) FROM current_nodes));
SELECT pg_catalog.setval('current_relations_id_seq', (SELECT MAX(id) FROM current_relations));
SELECT pg_catalog.setval('current_ways_id_seq', (SELECT MAX(id) FROM current_ways));
SELECT pg_catalog.setval('diary_comments_id_seq', (SELECT MAX(id) FROM diary_comments));
SELECT pg_catalog.setval('diary_entries_id_seq', (SELECT MAX(id) FROM diary_entries));
SELECT pg_catalog.setval('friends_id_seq', (SELECT MAX(id) FROM friends));
SELECT pg_catalog.setval('gpx_file_tags_id_seq', (SELECT MAX(id) FROM gpx_file_tags));
SELECT pg_catalog.setval('gpx_files_id_seq', (SELECT MAX(id) FROM gpx_files));
SELECT pg_catalog.setval('messages_id_seq', (SELECT MAX(id) FROM messages));
SELECT pg_catalog.setval('note_comments_id_seq', (SELECT MAX(id) FROM note_comments));
SELECT pg_catalog.setval('notes_id_seq', (SELECT MAX(id) FROM notes));
SELECT pg_catalog.setval('oauth_nonces_id_seq', (SELECT MAX(id) FROM oauth_nonces));
SELECT pg_catalog.setval('oauth_tokens_id_seq', (SELECT MAX(id) FROM oauth_tokens));
SELECT pg_catalog.setval('redactions_id_seq', (SELECT MAX(id) FROM redactions));
SELECT pg_catalog.setval('user_blocks_id_seq', (SELECT MAX(id) FROM user_blocks));
SELECT pg_catalog.setval('user_roles_id_seq', (SELECT MAX(id) FROM user_roles));
SELECT pg_catalog.setval('user_tokens_id_seq', (SELECT MAX(id) FROM user_tokens));
SELECT pg_catalog.setval('users_id_seq', (SELECT MAX(id) FROM users));
Взято [5].
Более того, можно посмотреть как это выглядит в бэкапе базы, сделав бэкап базы:
pg_dump -F p -b -f "drsk_osm.sql" -Upostgres drsk_osm
И поискать строки установки индексов:
fgrep pg_catalog.setval drsk_osm.sql
Получим:
SELECT pg_catalog.setval('acls_id_seq', 1, false);
SELECT pg_catalog.setval('changesets_id_seq', 104, true);
SELECT pg_catalog.setval('client_applications_id_seq', 1, true);
SELECT pg_catalog.setval('current_nodes_id_seq', 1621, true);
SELECT pg_catalog.setval('current_relations_id_seq', 5, true);
SELECT pg_catalog.setval('current_ways_id_seq', 64, true);
SELECT pg_catalog.setval('diary_comments_id_seq', 1, false);
SELECT pg_catalog.setval('diary_entries_id_seq', 1, false);
SELECT pg_catalog.setval('friends_id_seq', 1, false);
SELECT pg_catalog.setval('gpx_file_tags_id_seq', 1, false);
SELECT pg_catalog.setval('gpx_files_id_seq', 1, false);
SELECT pg_catalog.setval('messages_id_seq', 1, false);
SELECT pg_catalog.setval('note_comments_id_seq', 1, false);
SELECT pg_catalog.setval('notes_id_seq', 1, false);
SELECT pg_catalog.setval('oauth_nonces_id_seq', 1, false);
SELECT pg_catalog.setval('oauth_tokens_id_seq', 5, true);
SELECT pg_catalog.setval('redactions_id_seq', 1, false);
SELECT pg_catalog.setval('user_blocks_id_seq', 1, false);
SELECT pg_catalog.setval('user_roles_id_seq', 1, false);
SELECT pg_catalog.setval('user_tokens_id_seq', 12, true);
SELECT pg_catalog.setval('users_id_seq', 19, true);
Как раз это пример из неверных последовательностей - в результате чего добавление данных в базу не работало. И даже добавление нового пользователя вываливалось с ошибкой.
Gentoo
Ставим postgres и postgis
emerge -v dev-db/postgresql-server dev-db/postgis
Чтобы сборка постгреса не вываливалась с ошибкой про threads-unsafe:
USE="-threads" emerge -v dev-db/postgresql-server
Я лично поменял домашнюю директорию пользователя postgres:
#chown postgres:postgres -R /home/postgres #/etc/init.d/postgresql-9.0 stop #usermod -d /home/postgres postgres #/etc/init.d/postgresql-9.0 start
Если поставится 9.x, то возникает проблема с путями. И возможно понадобится прописать соответствующие пути:
#echo "PATH=/usr/lib64/postgresql-9.0/bin ROOTPATH=/usr/lib64/postgresql-9.0/bin LDPATH=/usr/lib64/postgresql-9.0/lib64" > /etc/env.d/47postgres # env-update
Ну и я добавил пользователю postgres следующее:
#echo "#!/bin/bash export PATH="$PATH:/usr/lib64/postgresql-9.0/bin" export LD_LIBRARY_PATH="/usr/lib64/postgresql-9.0/lib64" > /home/postgres/.bashrc
Ставим ruby
В основном всё ставится по статье The_Rails_Port. Где-то я могу ошибиться - пишу по памяти.
#emerge -v dev-lang/ruby #emerge -v dev-ruby/rubygems dev-ruby/rmagick
Устанавливаем разные gem пакеты:
#gem install -v=2.3.14 rails #gem install timecop #gem install pg #gem install ruby-openid #gem install rack-openid #gem install oauth
Скачиваем rails-сервер:
#mkdir /opt/osm #git clone git://git.openstreetmap.org/rails.git
Инициализация rails:
#cd /path/to/rails_port/ #cp config/example.application.yml config/application.yml #cp config/postgres.example.database.yml config/database.yml #rake gems:install
Инициализация БД
#rake db:migrate #env RAILS_ENV=production rake db:migrate
Запуск теста
Правим конфиг в rails (в нашем случае это /opt/osm/rails/config/database.yml):
#vim config/database.yml
Прописываем на все базы:
username: openstreetmap password: secret
Запускаем тест:
#rake test
Ставим Mapnik
Вообще, в репозитариях есть mapnik2 (0.7 не собрался у меня) уже. И я его ставил командой:
# emerge -av sci-geosciences/mapnik
Перед этим, конечно, "размаскнул". Однако почему-то после установки там нет некоторых базовых скриптов - для конвертации xml и т.п., потому на всякий случай я в довесок взял mapnik из svn:
#cd /opt/osm/ #svn co http://svn.openstreetmap.org/applications/rendering/mapnik
Скачиваем границы мира:
#wget http://tile.openstreetmap.org/world_boundaries-spherical.tgz # (50 MB) #wget http://tile.openstreetmap.org/processed_p.tar.bz2 # (357 MB) #wget http://tile.openstreetmap.org/shoreline_300.tar.bz2 # (46 MB) #wget http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/10m-populated-places.zip (1.5 MB) #wget http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/110m/cultural/110m-admin-0-boundary-lines.zip # (38 KB)
Сохраняем их, распаковываем в /opt/osm/mapnik/world_boundaries
Создаём базовый конфиг для mapnik
#./generate_xml.py osm.xml --host localhost --user postgres --dbname drsk_gis --symbols ./symbols/ --world_boundaries ../world_boundaries/ --port 5432 --password 'XXXXX' --epsg='900913' #upgrade_map_xml.py osm.xml drsk.xml
Последняя команда нужна чтобы mapnik не ругался на конфиг.
Создание полноценного стиля с помощью Mapcss
Т.к. править конфиг mapnik-а (созданный в предыдущем разделе) практически нереально, то для полноценного создания стиля карты используются стили mapcss.
Логика такая:
- создаём конфиг мой_стиль_карты.mapcss
- конвертируем мой_стиль_карты.mapcss в конфиг mapnik-а с помощью kothic
- обновляем сконвертированный конфиг до mapnik2 с помощью upgrade_map_xml.py
- полученный конфиг мапника прописываем либо в конфиг mod_tile либо в конфиг tilecache.
Установка kothic
git clone https://github.com/kothic/kothic
Устанавливаем зависимости (список в README kothic):
emerge -v =dev-python/psycopg-2.4.5 dev-python/lxml dev-python/pip dev-python/pyproj media-fonts/unifont pip install Shapely
В моём случае komap.py заработал только с версией 2.7 питона. С третьей - ругался.
Проверка работоспособности:
cd kothic/src python komap.py --help
На данный момент 13.02.2013 по-умолчанию kothic генерирует конфиг, который подключается к postgis на localhost. Если необходимо иное, то нужно пропатчить kothic с помощью патча:
diff -ru kothic_orig/src/komap.conf kothic/src/komap.conf
--- kothic_orig/src/komap.conf 2013-02-06 16:17:11.000000000 +1100
+++ kothic/src/komap.conf 2013-02-08 09:38:40.000000000 +1100
@@ -3,9 +3,12 @@
db_proj = +init=epsg:3857
table_prefix = planet_osm_
db_user = postgres
+db_passwd = XXXXXX
db_name = drsk_gis
+db_host = localhost
+db_port = 5432
db_srid = 900913
world_bnd_path = /opt/osm/mapnik/world_boundaries
cleantopo_dem_path = /raid/srtm/Full/CleanTOPO2merc.tif
srtm_dem_path = /raid/srtm/srtmm.vrt
diff -ru kothic_orig/src/komap.py kothic/src/komap.py
--- kothic_orig/src/komap.py 2013-02-05 11:11:22.000000000 +1100
+++ kothic/src/komap.py 2013-02-08 09:35:10.000000000 +1100
@@ -78,6 +78,9 @@
libkomapnik.table_prefix = config.get("mapnik", "table_prefix")
libkomapnik.db_user = config.get("mapnik", "db_user")
libkomapnik.db_name = config.get("mapnik", "db_name")
+libkomapnik.db_passwd = config.get("mapnik", "db_passwd")
+libkomapnik.db_host = config.get("mapnik", "db_host")
+libkomapnik.db_port = config.get("mapnik", "db_port")
libkomapnik.db_srid = config.get("mapnik", "db_srid")
libkomapnik.icons_path = config.get("mapnik", "icons_path")
libkomapnik.world_bnd_path = config.get("mapnik", "world_bnd_path")
diff -ru kothic_orig/src/libkomapnik.py kothic/src/libkomapnik.py
--- kothic_orig/src/libkomapnik.py 2012-07-10 11:59:58.000000000 +1100
+++ kothic/src/libkomapnik.py 2013-02-08 09:37:34.000000000 +1100
@@ -27,6 +27,9 @@
table_prefix = ""
db_user = ""
db_name = ""
+db_passwd = ""
+db_host = ""
+db_port = ""
db_srid = ""
icons_path = ""
world_bnd_path = ""
@@ -343,13 +346,16 @@
<Parameter name="st_prefix">true</Parameter>
<Parameter name="user">%s</Parameter>
<Parameter name="dbname">%s</Parameter>
+ <Parameter name="password">%s</Parameter>
+ <Parameter name="host">%s</Parameter>
+ <Parameter name="port">%s</Parameter>
<Parameter name="srid">%s</Parameter>
<Parameter name="geometry_field">way</Parameter>
<Parameter name="geometry_table">%s%s</Parameter>
<Parameter name="estimate_extent">false</Parameter>
<Parameter name="extent">-20037508.342789244, -20037508.342780735, 20037508.342789244, 20037508.342780709</Parameter>
</Datasource>
- </Layer>"""%(layer_id, db_proj, subs, interesting_tags, table_prefix, geom, sql, intersection_SQL, db_user, db_name, db_srid, table_prefix, geom)
+ </Layer>"""%(layer_id, db_proj, subs, interesting_tags, table_prefix, geom, sql, intersection_SQL, db_user, db_name, db_passwd, db_host, db_port, db_srid, table_prefix, geom)
elif type == "postgis-process":
return """
<Layer name="l%s" status="on" srs="%s">
@@ -364,13 +370,16 @@
<Parameter name="st_prefix">true</Parameter>
<Parameter name="user">%s</Parameter>
<Parameter name="dbname">%s</Parameter>
+ <Parameter name="password">%s</Parameter>
+ <Parameter name="host">%s</Parameter>
+ <Parameter name="port">%s</Parameter>
<Parameter name="srid">%s</Parameter>
<Parameter name="geometry_field">way</Parameter>
<Parameter name="geometry_table">%s%s</Parameter>
<Parameter name="estimate_extent">false</Parameter>
<Parameter name="extent">-20037508.342789244, -20037508.342780735, 20037508.342789244, 20037508.342780709</Parameter>
</Datasource>
- </Layer>"""%(layer_id, db_proj, subs, sql, intersection_SQL, db_user, db_name, db_srid, table_prefix, geom)
+ </Layer>"""%(layer_id, db_proj, subs, sql, intersection_SQL, db_user, db_name, db_passwd, db_host, db_port, db_srid, table_prefix, geom)
elif type == "coast":
if zoom < 9:
return """
Создание своего стиля mapcss
Пример стилей для объектов энергетики.
В директории kothic/src/styles есть большое количестов замечательных стилей. osmosnimki-maps.mapcss содержит большое количество комментариев и объяснений, из которых можно понять как и что рисовать.
Например, нам нужно создать слой линий эл-передач с прозрачным фоном, который будет накладываться поверх mapnik-а, рисуемого через mod_tile. Тогда mapcss стиль будет выглядеть примерно так (создано на основе стиля osmosnimki-maps.mapcss из проекта kothic):
meta { title: "Osmosnimki mapcss stylesheet"; /* title shown in the menu */ } /* Deja Vu MapCSS styles Osmosnimki maps style */ /* коментарии отделяются так и могут встречаться везде, где можно поставить пробел */ /* Прозрачный фон: */ canvas {opacity:0; -x-mapnik-true-layers: false} /* Непрозрачный фон: */ /*canvas { fill-color: #F1EEE8; -x-mapnik-dem-hack: true; } */ canvas { background-color: #fcf8e4; /* for josm: ground color*/ default-points: false; default-lines: false; } way::* { linejoin: miter; linecap: none; } area { fill-opacity: 0.0001; } way:closed, relation[type=multipolygon] { fill-opacity: 1.0; } *::* { text-halo-color: white; text-anchor-horizontal: center; text-anchor-vertical: center; } /* селектор, что рисовать. canvas - фон, считается одним большим полигоном, намного больше карты. К нему можно применять свойства заливок. Для mapnik'a нельзя выбирать разные параметры фона для разных зумов, и не поддерживаются иные параметры, кроме цвета node - точка. way - путь. выбирает одновременно все границы полигонов и все линейные объекты line - линейные объекты (обычно - незамкнутые пути, обычно к ним неприменима заливка) area - площадные объекты (обычно - замкнутые пути, применимы как заливки, так и линии контуров) */ /* квадратные скобки после объекта - селектор по тегам. основные варианты: тег=значение тег!=значение - выбрать все, кроме тег=значение тег - тег присутствует, значение не важно */ {fill-position:background; fill-color:#f3eceb; z-index:1} /* z-index - порядковый номер слоя, в котором будет лежать объект. чем меньше, тем ниже будет находиться объект (другие будут перекрывать), относительно z-index можно расставлять приоритеты в отрисовке, то что рисуется раньше, вытеснит, то что рисуется позже. магия: на развязках обводки будут учитывать слои эстакад, номер слоя можно посмотреть в семантике - ключ layer. Если нужно принудительно положить линию поверх всех дорог: -x-mapnik-layer: top; (к примеру, использовалось для рисования разделительных полос на primary ) Если (вдруг) понадобится принудительно положить линию под все дороги (фон): -x-mapnik-layer: bottom; /* fill-color: - html-цвет заливки */ /* после селектора типа объекта можно опционально ограничить зумы: |zA-B, A < B если нам не нужна какая-то из границ ("от минимального зума до такого-то" либо "от такого-то до бесконечности") - число A или B можно опустить. */ /* свойства с префиксом background- в основном относятся к заливкам, без префиксов - к линиям. width - ширина линии color - цвет линии opacity - прозрачность (1 - видимый полностью, 0 - совсем невидимый) casing-width - ширина обводки casing-color - цвет обводки casing-opacity - прозрачность обводки */ /* Рабочие ЛЭП*/ /* 10 кВ*/ way|z2-[power=line][voltage=10000] {color:green; width:3;z-index: 20; -x-mapnik-layer: top; text: name; text-position: line; text-color: #ffffff; font-family: DejaVu Sans Book; font-size:9; text-halo-radius: 1; text-halo-color: #404040}
Фактически всё что менялось - это прозрачный фон и последнее правило рисования 10 кВ линий. Подобный стиль отрисует зелёные линии с названиями из, взятыми из тега name.
Конвертирование mapcss->mapnik
Правим конфиг kothic:
vim kothic/src/komap.conf
Правим его под себя:
- world_bnd_path - путь до границ суши, рек
- db_user - имя пользователя для доступа к postgis
- icons_path - путь до иконок
Например в моём (пропатченом - см. выше по уставке komap) случае:
[mapnik] map_proj = +init=epsg:3857 db_proj = +init=epsg:3857 table_prefix = planet_osm_ db_user = postgres db_passwd = XXXXX db_name = drsk_gis db_host = localhost db_port = 5432 db_srid = 900913 icons_path = /opt/osm/mapnik/mapnik_icons/drsk/ world_bnd_path = /opt/osm/mapnik/world_boundaries cleantopo_dem_path = /raid/srtm/Full/CleanTOPO2merc.tif srtm_dem_path = /raid/srtm/srtmm.vrt cleantopo_hs_path = /raid/srtm/Full/CleanTOPO2merchs.tif srtm_hs_path = /raid/srtm/srtmhs.vrt
Правка конфига tilecache и подключение слоя в openlayer
Отображение данных
Создаём простую страничку для отображения своих данных
Т.е. это отдельная html-страничка по своему адресу, которая с помощью библиотеки openlayers отображает карту, инструменты управления картой, разные слои данных. На этой страничке хочется иметь прозрачные слои Bing,OSM которые можно было бы отображать параллельно с данными предприятия. Файл /var/www/vhosts/gpw.rs.int/htdocs/openlayer/index.html, содержимое:
<html>
<head>
<title>OpenLayers Example</title>
<script
src="http://openlayers.org/api/OpenLayers.js"></script>
</head>
<body>
<div style="width:100%; height:100%" id="map"></div>
<script defer="defer" type="text/javascript">
var map = null;
var shade = null;
var maxOpacity = 0.9;
var minOpacity = 0.1;
options = {controls:[
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PanZoomBar(),
new OpenLayers.Control.LayerSwitcher({'ascending':false}),
new OpenLayers.Control.Permalink(),
new OpenLayers.Control.ScaleLine(),
new OpenLayers.Control.Permalink('permalink'),
new OpenLayers.Control.MousePosition(),
new OpenLayers.Control.OverviewMap(),
new OpenLayers.Control.KeyboardDefaults()
]};
options = OpenLayers.Util.extend({
maxExtent: new OpenLayers.Bounds(-20037508.34,
-20037508.34,20037508.34,20037508.34),
maxResolution: 156543.0339,
units: "m",
projection: "EPSG:900913"//,
//transitionEffect: "resize"
}, options);
var map = new OpenLayers.Map('map', options);
var apiKey = "XXXXXXX";
var bing = new OpenLayers.Layer.Bing({
name: "Bing Images",
key: apiKey,
transparent: 'true',
type: "Aerial"}
);
map.addLayer(bing);
var osm = new OpenLayers.Layer.WMS( "local osm transparent",
"http://gpw.rs.int/tilecache/tilecache.cgi?",
{ layers: 'osm',
transparent: 'true',
format: 'png'},
{isBaseLayer: false, opacity: 0.7});
map.addLayer(osm);
var drsk_transp = new OpenLayers.Layer.WMS( "drsk transparent",
"http://gpw.rs.int/tilecache/tilecache.cgi?",
{ layers: 'drsk',
transparent: 'true',
format: 'png'},
{isBaseLayer: false, opacity: 0.7});
map.addLayer(drsk_transp);
var drsk = new OpenLayers.Layer.XYZ(
"drsk",
"http://tile.osm.rs.int/drsk/${z}/${x}/${y}.png",
{
numZoomLevels: 18,
transparent: 'true',
sphericalMercator: true
}
);
map.addLayers([drsk]);
var local_osm = new OpenLayers.Layer.XYZ(
"local_osm",
"http://tile.osm.rs.int/osm/${z}/${x}/${y}.png",
{
numZoomLevels: 18,
transparent: 'true',
sphericalMercator: true
}
);
map.addLayers([local_osm]);
map.setCenter(new OpenLayers.LonLat(0, 0), 0);
map.zoomToMaxExtent();
</script>
</body>
</html>
apiKey взять на сайте Bing, правда придётся там зарегистрироваться или взять ID товарища :-)
Ставим копию openstreetmap.ru
Можно поставить полноценный сайт и настроить его под себя. Т.е. это просто хороший, красивый сайт, который будет показывать (нашу локальную и не только) карту, показывать нужные инструменты (линейку) и т.п. Так же там работает поиск по адресам, можно настроить отображение внутренних данных в виде POI и дополнительной информации по ним.
Установка локальной копии сайта OpenStreetMap.ru
Правка компонент под себя
Названия слоёв
По умолчанию есть список слоёв:
- Mapnik
- Osmarender
- Карта для велосипедистов
- Выделить улицы без названия
Хотелось бы оставить парочку слоёв и назвать их по-своему.
Переименовываем
В директории rails-сервера:
#vim config/locales/ru.yml
Находим упоминание: "Выделить улицы без названий" И правим, чтобы было примерно так:
javascripts: map: base: cycle_map: Карта для велосипедистов mapnik: Объекты ОАО Название_нашей_фирмы noname: Выделить улицы без названий osmarender: Базовый слой OSM
Удаляем лишние слои
В директории rails-сервера:
#vim public/javascripts/map.js
Комментируем ненужные слои:
/* var cyclemap = new OpenLayers.Layer.OSM.CycleMap(i18n("javascripts.map.base.cycle_map"), { keyid: "cyclemap", displayOutsideMaxExtent: true, wrapDateLine: true, layerCode: "C" }); map.addLayer(cyclemap); var nonamekey = nonamekeys[document.domain]; var noname = new OpenLayers.Layer.OSM(i18n("javascripts.map.base.noname"), [ "http://a.tile.cloudmade.com/" + nonamekey + "/3/256/${z}/${x}/${y}.png", "http://b.tile.cloudmade.com/" + nonamekey + "/3/256/${z}/${x}/${y}.png", "http://c.tile.cloudmade.com/" + nonamekey + "/3/256/${z}/${x}/${y}.png" ], { displayOutsideMaxExtent: true, wrapDateLine: true, numZoomLevels: 19, layerCode: "N" }); map.addLayer(noname); */
Скрипты по миграции данных
Обновление локальной базы OSM
#!/bin/bash
# Скрипт скачивает изменения для базы России, применяет их к PostGis-базе и составляет задание для
# рендера по отрисовке изменившихся тайлов.
# Изменения скачиваются в виде очереди. В случае ошибки, задание откладывается до следующего раза.
#log=/dev/stdout
log="/var/log/osm/local_osm_update.log"
var_dir="/var/spool/osm/local_osm_update/"
spool_dir="${var_dir}/diffs/"
block_file="${var_dir}/block_file"
lock_file="${var_dir}/lock_file"
wget_log="${var_dir}/wget.log"
zabbix_status_file=/var/spool/zabbix/osm/local_osm_update.status
render_expired=/opt/osm/mod_tile/render_expired
osm2pgsql=/usr/bin/osm2pgsql
#wget -c -t 0 --limit-rate=30k http://data.gis-lab.info/osm_dump/dump/latest/RU.osm.bz2
echo "`date +%Y.%m.%d-%T` Запуск скрипта $0" >> ${log}
current_date=`date +%y%m%d`
mkdir -p ${spool_dir}
# Формируем задание для сегодняйшней даты:
echo "`date +%Y.%m.%d-%T` Формируем задание на ${current_date}" >> ${log}
touch ${spool_dir}/${current_date}
# Проверяем, выполняется ли скрипт - если да, то выходим
if [ -f ${lock_file} ]
then
echo "`date +%Y.%m.%d-%T` скрипт уже выполняется, т.к. создан файл блокировки:
${lock_file}
выходим." >> ${log}
exit
fi
# Создаём файл блокировки повторного запуска:
touch ${lock_file}
# Проверяем, завершились ли предыдущие запуски успешно:
if [ -f ${block_file} ]
then
echo "`date +%Y.%m.%d-%T` Задание для $current_date не может быть выполнено, т.к. создан файл блокировки:
${block_file}
Файл блокировки создаётся в результате ошибки загрузки изменений в базу.
Уточните по логу ситуацию за `stat --printf=%y ${block_file}`." >> ${log}
exit
fi
cd ${spool_dir}
ls -1|sort -n|while read current_date
do
echo "`date +%Y.%m.%d-%T` Загружаем изменения ($current_date):" >> ${log}
tmp=`mktemp /tmp/XXXXXX`
lftp -e "ls;exit" http://data.gis-lab.info/osm_dump/diff/RU/ > ${tmp}
file_name=`cat ${tmp} |grep "\-${current_date}\.osc"|awk '{print $5}'`
rm ${tmp}
if [ -z $file_name ]
then
echo "`date +%Y.%m.%d-%T` Файла изменений *-${current_date}.osc.gz нет на сервере, откладываю в отложенные задания."
mkdir -p ${spool_dir}
touch ${spool_dir}/${current_date}
exit
fi
echo "`date +%Y.%m.%d-%T` Скачиваю файл изменений http://data.gis-lab.info/osm_dump/diff/RU/${file_name}" >> ${log}
wget -t 0 -c http://data.gis-lab.info/osm_dump/diff/RU/${file_name} -O ${var_dir}/${file_name} -o ${wget_log}
if [ ! 0 -lt `stat --printf=%s ${var_dir}/${file_name}` ]
then
echo "`date +%Y.%m.%d-%T` Скачан пустой файл - это ошибка.
Создаём отложенное задание, сообщаем о неудачном статусе загрузки zabbix-у и выходим" >> ${log}
touch ${spool_dir}/${current_date}
echo "ERROR `date +%Y.%m.%d-%T`: ошибка загрузки файла изменений с сервера" > ${zabbix_status_file}
exit
fi
# Распаковываем файл:
#gunzip ${var_dir}/${file_name}
# Применяем изменения к базе:
osm2pgsql --append --style /usr/share/osm2pgsql/default.style --database local_osm_gis --username openstreetmap --prefix planet_osm --slim --cache 2048 --hstore ${var_dir}/${file_name}
if [ ! 0 -eq $? ]
then
echo "ERROR `date +%Y.%m.%d-%T`: ошибка загрузки файла изменений в базу с помощью osm2pgsql" > ${zabbix_status_file}
echo "`date +%Y.%m.%d-%T`: ERROR ошибка загрузки файла изменений в базу с помощью osm2pgsql.
Создаём файл блокировки ${block_file}, чтобы предотвратить последующие попытки загрузки (что может повредить базу). " >> ${log}
touch ${block_file}
exit
else
echo "SUCCESS `date +%Y.%m.%d-%T`: успешно загрузил файл изменений за ${current_date} в базу с помощью osm2pgsql" > ${zabbix_status_file}
echo "`date +%Y.%m.%d-%T`: SUCCESS успешно загрузил файл изменений за ${current_date} в базу с помощью osm2pgsql" >> ${log}
fi
# Формируем задание для рендера:
${osm2pgsql} -a --database local_osm_gis --username openstreetmap --prefix planet_osm --slim -e 15:15 -o ${tmp} ${var_dir}/${file_name}
${render_expired} --min-zoom=10 --max-zoom=18 -m local_osm --touch-from=10 -s /var/run/renderd/renderd.sock < ${tmp}
# Удаляем скачанный файл изменений:
rm ${var_dir}/${file_name}
# Удаляем успешно выполненное задание:
rm ${spool_dir}/${current_date}
done
# Удаляем файл блокировки повторного запуска:
rm ${lock_file}
Обновление osm2pgsql-стиля
В случае, если вы решили ввести новые теги для обозначения каких-то своих объектов, то для того, чтобы эти теги мигрировали из osm в gis базу - нужно добавить эти теги в стилевой файл миграции данных. В скрипте, описанном ниже есть команда:
osm2pgsql --append --style /usr/share/osm2pgsql/default.style --database drsk_gis --username openstreetmap --prefix planet_osm --slim --cache 2048 --hstore ${diff_api_changes} &>> ${log}
Где:
--style /usr/share/osm2pgsql/default.style
как раз и есть указание на файл стиля. Нам нужно добавить в этот файл стиля свои теги, для того, чтобы они мигрировали в gis-базу и мы могли бы отрисовывать объекты, обозначенные данным тегом, особым образом на карте. Добавляем теги в этот файл:
node,way power_usage_percent text polygon
node,way power_usage_date text polygon
node,way power_usage_kva text polygon
node,way power:usage:percent text polygon
node,way power:usage:kva text polygon
node,way power:usage:date text polygon
node,way communication text polygon
node,way type text polygon
node,way bandwidth text polygon
node,way tower:type text linear
Полностью файл можно взять тут.
Как я понял, в последнем столбце нужно проставлять тип объекта с такими тегами. Т.е. если объект с такими тегами может быть полигоном - нужно ставить polygon, если только точка или линия - linear.
Важно: После правки стиля миграции данных и перед загрузкой данных в gis-базу, эту gis-базу нужно заново пересоздать. Обычный скрипт (описан ниже), который льёт только изменения из osm-базы не сможет перелить новые теги. После пересоздания gis-базы и полной заливки данных в неё из osm-базы, можно опять продолжать лить только изменения.
Скрипт миграции данных из drsk_osm в drsk_gis
#!/bin/bash
osmosis="/root/osmosis-0.39/bin/osmosis"
log="/var/log/osm/openstreetmap2drsk_gis.log"
var_dir="/var/spool/osm/drsk_gis_update/"
drsk_osm_new="${var_dir}/drsk_osm_new.osm"
drsk_osm_prev="${var_dir}/drsk_osm_prev.osm"
diff_api_changes="${var_dir}/diff_api_changes.osc"
need_to_render="${var_dir}/tiles_to_render.list"
echo "`date +%Y.%m.%d-%T`: Выгружаем новый файл выгрузки из базы openstreetmap:" >> ${log}
${osmosis} --read-apidb host="localhost" database="drsk_osm" user="openstreetmap" password="XXXXXX" validateSchemaVersion=no --write-xml file="${drsk_osm_new}" &>> ${log}
rm ${diff_api_changes}
echo "`date +%Y.%m.%d-%T`: Выявление изменения между прошлой и новой выгрузкой:" >> ${log}
${osmosis} --read-xml ${drsk_osm_new} --read-xml ${drsk_osm_prev} --derive-change --write-xml-change ${diff_api_changes} &>> ${log}
mv ${drsk_osm_new} ${drsk_osm_prev}
echo "`date +%Y.%m.%d-%T`: Размер файла изменений: `cat ${diff_api_changes}|wc -l` строк" >> ${log}
echo "`date +%Y.%m.%d-%T`: Вносим изменения в базу:" >> ${log}
osm2pgsql --append --style /usr/share/osm2pgsql/default.style --database drsk_gis --username openstreetmap --prefix planet_osm --slim --cache 2048 --hstore ${diff_api_changes} &>> ${log}
echo "`date +%Y.%m.%d-%T`: Формируем список тайлов на отрисовку:" >> ${log}
cat /dev/null > ${need_to_render}
/usr/bin/osm2pgsql --database drsk_gis --username openstreetmap --prefix planet_osm -a --slim -e 15:15 -o ${need_to_render} ${diff_api_changes}
cat ${need_to_render} >> ${log}
echo "$start_render_date: Обновляем тайлы:" >> ${log}
/opt/osm/mod_tile/render_expired --min-zoom=10 --max-zoom=18 -m drsk_gis --touch-from=10 -s /var/run/renderd/renderd.sock < ${need_to_render}
rm ${need_to_render}
Единственный момент - почему-то сбоит обновление тайлов в этом скрипте. Тот же самый код в полне работает для local_osm_gis, но не работает для drsk_gis...
Исправление ошибок и проблем
Ошибки mapnik
generate_tiles
Если при тестовом запуске generate_tiles.sh идёт много ругани насчёт неверного xml, то, возможно нужно сконвертировать файл настроек xml:
upgrade_map_xml.py osm.xml osm2.xml
Ошибки osm2pgsql
В случае, если загрузка данных с помощью osm2pgsql рукается, что таких таблиц нет, то возможно, стоит указать prefix не planet, а planet_osm.
Ошибки mod_tile
Если рендер упорно не хочет обновлять тайлы и пишет, что:
Total tiles ignored (not on disk): 14
Или другое количество тайлов, то нужно проверить пути. Путь к кэшу формируется не из имени секции в файле конфига mod_tile, а из имени базы postgis. Чтобы проверить, к каким действительно файлам хочет обращаться, нужно запускать render_expired с ключём "--verbose":
/opt/osm/mod_tile/render_expired --verbose --min-zoom=10 --max-zoom=18 -m drsk_gis \ --touch-from=10 -s /var/run/renderd/renderd.sock < /tmp/list
Где содержимое /tmp/list в моём случае:
15/28396/12027 15/28397/12027 15/28396/12028 15/28397/12028
В результате я выяснил, что:
Rendering client read: x=28396 y=12027 z=15 process: x=227168 y=96216 z=18 not on disk: /var/lib/mod_tile/drsk_gis/18/49/119/119/109/8.meta process: x=113584 y=48108 z=17 not on disk: /var/lib/mod_tile/drsk_gis/17/16/187/187/190/8.meta process: x=56792 y=24054 z=16 not on disk: /var/lib/mod_tile/drsk_gis/16/0/213/221/223/128.meta ... Total tiles ignored (not on disk): 14
Оказалось, что у меня была директория /var/lib/mod_tile/drsk взамен /var/lib/mod_tile/drsk_gis
Полезные ссылки
- postgres+разширение postgis
- Rails-сервер
- mapnik
- mod_tile
- Tilecache
- osmosis
- osm2pgsql
- openlayers
- Примеры кода на базе Openlayers
- Создание и поддержка актуальности локальной базы данных ОСМ
- Apache как прокси для доступа к rails-серверу
- Обсуждение создания локального сервера OSM на форуме openstreetmap
- Установка на debian
- Исправление проблемы с неуникальными идетификаторами
- Mapcss стили для объектов энергетики
- Установка локальной копии сайта OpenStreetMap.ru
Выдержки из переписки
К сожалению, данная документация оставляет желать лучшего, отчасти из-за неаккуратности автора, отчасти из-за недостаточных знаний предмета. Поэтому читающие её обращались к автору по почте за дополнительными разъяснениями. Мне кажется, некоторые выдержки стоит добавить в вики:
Объяснение логики системы
Логика такая:
1. Настраиваете ваш сервер OSM, например по адресу osm.corp.local
2. На этом сервере у вас есть база с вашими объектами (бэкенд для рельсов). База postgres (без расширений postgis). Назовём её, к примеру, "corp_osm".
3. Вы подключаетесь на 3000-й порт браузером, регистрируете пользователя (например petya)
4. Запускаете JOSM, в настройках прописываете адрес вашего сервера: [6]
5. Прописываете пользователя petya и его пароль
6. Загружаете с вашего сервера какую-либо область. Объектов, понятное дело, там никаких не будет.
7. Рисуете ваши объекты (подложку в JOSM можно подключить Bing, mapnik).
8. Загружаете нарисованное на ваш сервер.
Всё.
Теперь нужно говорить об отображении ваших данных.
1. Создаём базу postgis, назовём её, к примеру, "corp_gis".
2. Автоматическим скриптом раз в час, к примеру, по cron-у запускается скрипт, который анализирует изменения в базе corp_osm, создаёт diff и этот diff применяет к базе "corp_gis". Или же можно проще - просто делать выгрузку в osm-формат всей базы corp_osm, полное удаление corp_gis, создание её и заливка данных в неё. Но тагда будут ошибки и перерывы в работе для пользователей (т.к. рендеры будут "терять" postgis базу). Мой скрипт описан тут: [7]
3. Далее нужно отобразить эти данные. Можно сделать по-разному. В моём случае я пришёл к такому варианту: Есть подложки mapnik и Bing, поверх них рисуются слои наших данных с прозрачным фоном. Так же, как это сделано вот тут для названий улиц: [8] Слоёв у нас много, данные разбиты по ним. Отдельно добавлен слой кадастра (берётся из интернета).
4. Чтобы сгенерировать подобные прозрачные тайлы, которые можно накладывать поверх Bing или mapnik - нужно поставить tilecache, mapnik и конвертилку стилей mapcss->mapnik, т.к. написать конфиг к мапнику - нетривиальная задача.
5. Рисуем конфиг для своих данных на mapcss-языке. Например, для начала, один слой у нас будет показывать только опоры ВЛ (power=tower). Прописываем это в mapcss-стиле, конвертируем из него стиль для mapnik-а, подсовываем этот конфиг tilecache-у.
6. Создаём web-страничку на openlayer или leaflet (я вот недавно перешёл на leaflet, честно сказать в основном из-за просьб пользователей - добавить инструмент "линейка" на карту - взял сырцы сайта openstreetmap.ru и чуток их под нас заточил).
7. Прописываем на нашем сайте mapnik, Bing и наш слой, который ссылается на наш tilecache-сервер.
8. В резульате у нас получается сайт, который поверх Bing или mapnik (берётся из интернета) рисует наши коммерческие данные (если включить галочку в списке слоёв).
Дополнительно, если хочется не тянуть mapnik-слой из интернета, а сделать его локальным, то можно создать специальную postgis-базу, например, "local_mapnik_gis", скачать дамп OSM-России (весь мир слишком тяжёл), залить в эту базу, скачать мировую линию воды: "world_boundaries", поставить mod_tile, подсунуть ему стандартный конфиг мапника, подсунуть world_boundaries, подсунуть базу local_mapnik_gis, написать конфиг для mod_tile и добавить этот слой на ваш сайт (который openlayer или leaflet). В результате, если пользователи будут глядеть ваш сайт и ваши корпоративные данные поверх mapnik, то тайлы mapnik-а будут не из интернета браться, а генерироваться mod_tile-ом из вашей базы local_mapnik_gis. Ну и обновлять данные в этой базе из интернета можно через некоторое время (у меня раз в месяц льётся полный дамп, т.к. с дифами там что-то плохо было - нерегулярно они на рамблере для России создавались). Но, повторюсь, локальное генерирование подложки mapnik - не обязательно. Можно и из интернета её тянуть как и Bing.