MyTetra Share
Делитесь знаниями!
Создание локального OSM-сервера
Время создания: 16.07.2018 18:27
Текстовые метки: openstreetmap, osm, сервер, локальный, копия, картография
Раздел: Компьютер - Программное обеспечение - Картография и навигация
Запись: xintrea/mytetra_syncro/master/base/1531754830mkxjrkfk78/text.html на raw.github.com

Содержание


1 От автора

2 Постановка задачи

2.1 Техническое задание

2.2 Дизайн

3 Логика

4 Установка и настройка компонент

4.1 Debian

4.1.1 Ставим Rails OSM Server

4.1.1.1 Устанавливаем нужные пакеты:

4.1.1.2 Настройка API-сервера

4.1.1.3 Добавляем сервис OSM в автозагрузку

4.1.1.4 Включение apache2 прокси для OSM-Rails

4.1.2 Базовая настройка пересылки почты

4.1.3 Импорт существующей базы данных объектов

4.1.3.1 Ставим osmosis

4.1.3.1.1 Заливаем базу

4.1.4 Отрисовка гео-данных

4.1.4.1 Установка с помощью puppet-шаблона

4.1.4.2 Ручная установка

4.1.4.2.1 Ставим mapnik

4.1.4.2.2 Ставим tilecache

4.1.4.2.3 Ставим kothic

4.1.5 Ошибки

4.1.5.1 После заливки данных osmosis-ом проблемы с добавлением данных/пользователей на карту/сайт

4.2 Gentoo

4.2.1 Ставим postgres и postgis

4.2.2 Ставим ruby

4.2.3 Ставим Mapnik

4.3 Создаём базовый конфиг для mapnik

4.4 Создание полноценного стиля с помощью Mapcss

4.4.1 Установка kothic

4.4.2 Создание своего стиля mapcss

4.4.3 Конвертирование mapcss->mapnik

4.4.4 Правка конфига tilecache и подключение слоя в openlayer

5 Отображение данных

5.1 Создаём простую страничку для отображения своих данных

5.2 Ставим копию openstreetmap.ru

6 Правка компонент под себя

6.1 Названия слоёв

6.1.1 Переименовываем

6.1.2 Удаляем лишние слои

6.2 Скрипты по миграции данных

6.2.1 Обновление локальной базы OSM

6.2.2 Обновление osm2pgsql-стиля

6.2.3 Скрипт миграции данных из drsk_osm в drsk_gis

7 Исправление ошибок и проблем

7.1 Ошибки mapnik

7.1.1 generate_tiles

7.2 Ошибки osm2pgsql

7.3 Ошибки mod_tile

8 Полезные ссылки

9 Выдержки из переписки

9.1 Объяснение логики системы


От автора

Данная инструкция не претендует на абсолютную точность. Написана по памяти, с уточнением мест, где лежат грабли, на которые наступил автор. За точной информацией стоит сходить по ссылкам, в которых по шагам расписывается установка Mapnik , Mapnik/PostGIS , The_Rails_Port , Mod_tile , tilecache[1] ,osmosis ,openlayers и примеры кода для openlayers[2] . Основная задача данной инструкции объяснить принцип и логику построения подобной системы, указать направления получения информации и изучения, чтобы читающий, при установке подобной системы тыкался носом как котёнок меньше, чем это делал автор, а так же не утомлять повторными расспросами уважаемое сообщество[3] . Если же читающие добавят информации, уточнят неточности и в конце концов сделают из этой страницы полноценное руководство - то автор будет рад.

Успехов в создании локального сервера!

Постановка задачи

Техническое задание

Необходимо иметь локальный (в локальной сети предприятия) сервер, на который можно сохранять коммерческие гео-данные, преднозначенные для использования внутри предприятия. Данные заносить с помощью josm. Так же на этом локальном сервере должна рисоваться и отображаться пользователям карта по этим данным.

Более того, необходимо иметь обновляемую копию данных России в виде локальной базы, по которой будет рисоваться подложка/слой OSM. Т.е. данные OSM и внутренних гео-данных предприятия не будут смешиваться. OSM данные будут использоваться как слой для рисования в JOSM или же как полупрозрачный фон-подложка при просмотре карт, построенных по гео-данным предприятия.

Дизайн

Данная задача реализуется следующими инструментами:

  1. postgres+расширение postgis как хранилище гео-данных
  2. Apache как плаформа для web-содержимого
  3. Rails-сервер как основной сервер OSM (основная логика OSM - api, пользователи, web, сохранение и обработка треков и т.д.)
  4. mapnik как рендер карты, т.е. продукт, который занимается созданием *.png из гео-данных в postgres
  5. mod_tile как сервис (и модуль для apache) организации отрисовки (рендеринга) "на лету" и отдачи *.png по запросу пользователя (при обращении к конкретному "тайлу")
  6. tilecache[4] как сервис, отрисовки (рендеринга) "на лету" и отдачи *.png по запросу пользователя в виде простых запросов (в виде z/x/y.png), так и в виде запросов по координатам, необходимым для отрисовки OSM данных в виде полу-прозрачных слоёв.
  7. osmosis и osm2pgsql как утилиты для экспорта/импорта в базы и вычисления diff-файлов изменений OSM-данных.
  8. openlayers как js-библиотеки для создания html-страничек с картами, базовыми элементами управления и т.п.

Логика

Основная схема представлена на изображении:

Логика работы системы состоит в следующем

  1. Создаём базу в postgres, где будут храниться наши данные, назовём её drsk_osm.
  2. Ставим rails-сервер, настраиваем его на нашу базу. Чтобы данные, передаваемые редактором в rails-сервер через api складывались в нашу базу.
  3. Создаём базу в postgres с расширением postgis. Назовём её drsk_gis. В эту базу регулярно будут мигрировать (скриптами) данные из базы drsk_osm.
  4. Устанавливаем mapnik. Настраиваем (создаём конфиг drsk.xml, содержащий стили, логин/пароль по доступу к базе) его на доступ к базе drsk_gis.
  5. Устанавливаем mod_tile, настраиваем его на наш конфиг drsk.xml. Теперь mod_tile будет генерировать тайлы по нашему конфигу и отдавать их через apache.
  6. Подправляем конфиг rails-сервера public/openlayers/OpenStreetMap.js, заменяя
  7. http://a.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png

    на

    http://наш_локальный_сервер_osm/drsk/${z}/${x}/${y}.png

    так, чтобы тайлы брались с mod_tile с секции конфига о drsk.

  8. Пишем скрипт, который будет регулярно "перекидывать" данные с drsk_osm в drsk_gis, генерировать список измённых тайлов (проанализировав изменения между старым срезом базы drsk_osm и новым срезом базы drsk_osm), передавать этот список mod_tile-у для перерисовки этих тайлов.

Первый этап выполнен - теперь мы можем подключаться josm-ом на http://наш_локальный_сервер_osm/api и добавлять туда данные, а потом просматривать их как тайлы на основной странице http://наш_локальный_сервер_osm/ .

Логика настройки подложки osm из данных карты с openstreetmap.org. Т.е. мы хотим брать (регулярно) дамп, к примеру, России и отрисовывать его локально. И пользоваться этим слоем как подложкой для рисования/просмотра своих данных предприятия. При этом данные предприятия и данные свободной карты не смешиваются. Итак, донастройка сервера:

  1. Создаём базу local_osm_gis в postgres с расширением postgis.
  2. Скачиваем дамп России в osm.bz2, заливаем его в эту базу.
  3. Настраиваем конфиг в mapnik для доступа и отрисовки базы local_osm_gis, например local_osm.xml.
  4. Прописываем секцию в конфиг mod_tile для отрисовки по конфигу local_osm.xml.
  5. Подправляем конфиг 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.
  6. Пишем скрипт, который будет регулярно скачивать изменения для России с 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.

Логика такая:

  1. создаём конфиг мой_стиль_карты.mapcss
  2. конвертируем мой_стиль_карты.mapcss в конфиг mapnik-а с помощью kothic
  3. обновляем сконвертированный конфиг до mapnik2 с помощью upgrade_map_xml.py
  4. полученный конфиг мапника прописываем либо в конфиг 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

Правка компонент под себя

Названия слоёв

По умолчанию есть список слоёв:

  1. Mapnik
  2. Osmarender
  3. Карта для велосипедистов
  4. Выделить улицы без названия

Хотелось бы оставить парочку слоёв и назвать их по-своему.

Переименовываем

В директории 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

Полезные ссылки

  1. postgres+разширение postgis
  2. Rails-сервер
  3. mapnik
  4. mod_tile
  5. Tilecache
  6. osmosis
  7. osm2pgsql
  8. openlayers
  9. Примеры кода на базе Openlayers
  10. Создание и поддержка актуальности локальной базы данных ОСМ
  11. Apache как прокси для доступа к rails-серверу
  12. Обсуждение создания локального сервера OSM на форуме openstreetmap
  13. Установка на debian
  14. Исправление проблемы с неуникальными идетификаторами
  15. Mapcss стили для объектов энергетики
  16. Установка локальной копии сайта 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.


Так же в этом разделе:
 
MyTetra Share v.0.59
Яндекс индекс цитирования