OSM и карта лежачих полицейских в навигаторах

    imageТак как начинать с начала неинтересно, начну с конца.
    Мы ее-таки сделали. Достали из данных OpenStreetMap лежачих полицейских, скрестили их со страшной коммерческой программой Навител, сделали веб-просмотрщик этих самых лежачих полицейских, и интерфейс для их добавления для новичков на http://latlon.org/tc/. И даже написали небольшой пресс-релизик, ссылку на который можно разослать друзьям и знакомым-автомобилистам.
    Но для хабра можно рассказать и кое-что особенное: как это всё устроено внутри, и как оно делалось.

    Главное правило OpenStreetMap — Have fun. Всё описанное делалось не ради денег или ещё каких-то плюшек, и даже не для собственного удобства.

    На одной из Минских мини-OSMовок (мини, потому что нигде, кроме IRC-канала они не объявляются) меня наградили заданием: «хочешь сделать полезное дело? достань из осма лежекопы в навител». Потом всё как-то забылось, и через пару месяцев таки вспомнилось, благодаря героическому труду товарища stas_symba c форума 4pda.ru. Он уже несколько месяцев в одиночку собирал и выкладывал обновления по лежачим полицейским по Беларуси. «Но ведь такие данные проще собирать сразу в OSM», — подумалось мне, и я засел за экспорт.

    Формат


    Так как ни навигатора, ни Навитела, ни автомобиля у меня нет, делать всё пришлось вслепую, читая форумы и думая мозгами. Для начала и понимания масштаба бедствия — вкратце про то, что удалось добыть про формат данных из форумов.

    Файл cops.txt (и/или speedcam.txt) — обычный csv, в первой строчке — заголовок, во всех последующих — данные. Заголовок:

    idx,x,y,type,speed,dirtype,direction
    где:
    • idx — уникальный номер объекта;
    • x,y — координаты, в проекции долгота-широта EPSG:4326;
    • speed — разрешенная скорость для объекта;
    • dirtype — тип направления действия — в 1 или 2 стороны;
    • direction — нправление действия;


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

    Инструменты для решения задачи обычно выбираются из того, что есть под рукой. Под рукой было множество скриптов для поточной обработки OSM XML, и база PostGIS. Несмотря на то, что привычнее работать как раз с поточными скриптами, последнее поле файла спидкамов намекало, что придётся поработать с геометрией объектов, чем и славится PostGIS.

    Для начала на домашнем сервере при помощи osm2pgsql была импортирована обычная база для Mapnik. Первый запрос написался быстро и просто:
    select * from planet_osm_point where traffic_calming is not NULL;
    В ответ на это мне вернулось множество полей, в том числе геометрия в формате WKB, закодированная в hex. Совсем не годится.

    Пришлось залезть в мауал по PostGIS, в котором нашлись функции ST_X и ST_Y. Показалось, то, что надо. Переписываем:
    gis=> select st_x(way), st_y(way) from planet_osm_point where traffic_calming is not NULL limit 1;
    st_x | st_y
    ------------------+------------------
    3085590.21426068 | 7159526.18035388
    (1 запись)


    Неожиданно? Ожиданно, но надо сделать пояснение.

    В веб-картографии широко используются две проекции: для передачи и показа пользователю — широта-долгота, она же EPSG:4326, и «гугловская», она же «меркатор на сфере», она же EPSG:3857, она же EPSG:900913, она же EPSG:3785 (почему так много кодов? долгая история споров больших корпораций, любителей и регистраторов, достойная отдельного поста). Проекция хороша тем, что переход из нее в 4326 на любом языке занимает от силы две строчки математики. Именно она, метрическая, а не в угловых координатах, используется при выводе карт на экран. И для облегчения рассчётов, именно в ней хранится база Mapnik.

    Хорошо, ладно. Перепроецируем.
    gis=> select ST_X(transform(p.way,94326)) as X, ST_Y(transform(p.way,94326)) as Y from planet_osm_point p where traffic_calming is not NULL limit 1;
    x | y
    ------------+------------
    27.7183285 | 53.9438334
    (1 запись)


    Что там дальше? Скорость.

    Никто в OSM на лежачие полицейские скорость не проставляет. Надо придумывать, откуда ее брать. Спрашиваем первого попавшегося человека (им оказался wildMan), получаем ответ — по ПДД разрешенная скорость 60 в городе, 90 вне города. А ещё может быть ограничение по скорости на самой дороге, где ее занесут в соответствющий тег — maxspeed. Ну, заодно можно из тега oneway достать признак односторонности — зря, что ли, в формате поле под него отведено?

    Объединяем с таблицей полигонов — в ней хранятся административные границы, и таблицей линий — в ней хранятся линии дорог.

    select ST_X(transform(p.way,94326)) as X,
    ST_Y(transform(p.way,94326)) as Y, '102' as TYPE,
    case when l.maxspeed is not NULL then l.maxspeed else case when t.admin_level = '8' then '60' else '90' end end as SPEED,
    case when l.oneway = 'yes' then '1' else '2' end as DirType

    from (planet_osm_point p
    join planet_osm_line l on (l.highway is not NULL and ST_DWithin(p.way,l.way,.1)))
    LEFT OUTER JOIN planet_osm_polygon t on (t.admin_level = '8' and ST_Within(p.way, t.way))
    where p.traffic_calming is not NULL;


    При помощи стандартного SQL join мы сопоставляем все три таблицы — каждому лежачему полицейскому находим в пару линию дороги в не дальше, чем десяти сантиметрах от нее, и полигон города, ее окружающий, если получится. Далее, поле speed мы пытаемся заполнить по тегу maxspeed линии, а если его не заполнили, то смотрим, попала ли точка в административную границу города: если да, ставим 60, если нет — 90.

    idx — порядковый номер — был соблазн взять из osm_id. Но потом стало понятно, что полицейский, нахолящийся на стыке двух линий, будет встречаться в обоих линиях в обе стороны, и id у него получится один и тот же при разном направлении, в связи с чем лучшим вариантом показалось — пронумеровать их все по порядку.

    Страх и отсутствие документации


    Так как Навител — продукт коммерческий, и ни исходных текстов, ни нормальной демо-версии у него нет, осталась без комментариев последняя цифра — направление. Никаких намёков о том, как оно считается, найти не удалось, кроме того, что это явно — цифра в градусах.
    «Ну, раз все карты в меркаторовской проекции, и она сохраняет углы и направления, то, значит, они посчитаны в ней!»

    Чтобы посчитать азимут, PostGIS требует две точки. Очевидно, они должны лежать на той же самой дороге, на которой установлен лежачий полицейский, на некотором расстоянии в обе стороны от него.
    Метод ST_Line_Locate_Point позволил найти длину вдоль линии от ее начала до заданной точки, а ST_Line_Interpolate_Point — наоборот, по длине вдоль линии найти точку.

    Но psql рисует в ответ на запросы мне табличку в псевдографике, когда мне нужен CSV! Неужели писать обёртку?
    Оказалось, что всё намного проще. Функция COPY позволяет доставить результат запроса сразу в CSV — как раз то, что нужно. Вот такая маленькая кошачья радость.

    Выгоняю первый результат, нахожу обладателя Навитела, заставляю проверить… и упс. Направления не параллельны дорогам. Возникает мысль «неужели...», и лапы сам пишут перепроецирование в 4326 при расчёте азимута.

    Да, доблестные разработчики Навитела считают направление в проекции, не сохраняющей направления. Честь им, хвала и почёт.

    Квазиитог


    В итоге, запросом стал вот такой вот монстрик, добывающий из данных OpenStreetMap то, чего в них изначально как будто бы и нет — лежачих полицейских в формате Навител. Запрос, достающий из них камеры контроля скорости, можете написать в качестве домашнего задания. :)
    CREATE TEMP SEQUENCE idx ;
    COPY (

    select nextval('idx') as idx,
    ST_X(transform(p.way,94326)) as X,
    ST_Y(transform(p.way,94326)) as Y, '102' as TYPE,
    case when l.maxspeed is not NULL then l.maxspeed else case when t.admin_level = '8' then '60' else '90' end end as SPEED,
    case when l.oneway = 'yes' then '1' else '2' end as DirType,
    floor(ST_Azimuth(
    transform(ST_Line_Interpolate_Point(l.way,
    case when (ST_Line_Locate_Point(l.way,p.way)-0.01 < 0) then 0 else ST_Line_Locate_Point(l.way,p.way)-0.0000001 end),94326),
    transform(ST_Line_Interpolate_Point(l.way,
    case when (ST_Line_Locate_Point(l.way,p.way)+0.01 > 1) then 1 else ST_Line_Locate_Point(l.way,p.way)+0.0000001 end)
    ,94326))/(2*pi())*360) as Direction
    from (planet_osm_point p
    join planet_osm_line l on (l.highway is not NULL and ST_DWithin(p.way,l.way,.1)))
    LEFT OUTER JOIN planet_osm_polygon t on (t.admin_level = '8' and ST_Within(p.way, t.way))
    where p.traffic_calming is not NULL
    ) TO STDOUT WITH CSV HEADER;


    Но Котяра не был бы Котярой, если бы отовсюду не торчали его кошачьи уши. Потому в качестве разминки кроме ежепятиминутной выгрузки обновлённых лежачих полицейских и камер для СНГ был организован рендеринг всего этого безобразия в тайлы, чтобы на него могли полюбоваться те, у кого нет навигатора с Навителом.

    Ближе к выходным товарищ andrewsh (думаю, ему тоже есть о чём рассказать, если его попросить :) написал удобный интерфейс для сообщения о новых лежачих полицейских без регистрации — latlon.org/tc, и все сервисы было решено пустить в народ. Надеюсь, вам понравится.

    Have fun! ;)
    Поделиться публикацией
    Похожие публикации
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 32
    • 0
      Пардон за возможно глупый вопрос, а как это все в навител попадает?
      • 0
        Файл cops.txt копируется во соответствующий каталог неподалёку от программы, и при следующем запуске, если всё пройдёт удачно, она его подхватит и покажет на экране, и озвучит голосовыми предупреждениями.
        • 0
          А иконки уже зашиты?.. Может было проще сделать на основе Яндекс.Карты?!
          • +1
            не у всех в пути есть интернеты
            • 0
              «На основе яндекс-карты» сделать что именно?

              Яндекс-карты не предоставляют просым смертным информацию о лежачих полицейских.

              Показывать данные из OSM поверх карты Яндекса, на мой взгляд, моветон. :)

              Ну и рендеринг всего этого чуда в png-тайлы является тем же самым sql-запросом + пара строчек стиля «повесить вот эту иконку» и «написать цифру циферкой в красной обводке». Выгонку в kml пришлось бы писать отдельно, руками.
        • +1
          > Никто в OSM на лежачие полицейские скорость не проставляет. Надо придумывать, откуда ее брать.
          Не очень понял про скорость. По идее на любом «полежае» скорость ограничене 20 км/ч (изредка 30 км/ч).
          • +1
            В Минске чаще 40 км/ч
            • +1
              тогда можно везде поставить 40
          • +1
            Скажите, пожалуйста, а зачем в навигаторе карта лежачих полицейских?
            • +5
              Разве не понятно — чтобы совсем не смотреть ни на знаки, ни на дорогу :)
              Ну а если серьезно, если поздно вечером едешь по незнакомому неосвещенному городу в дождь или снег, такая инфа может оказаться очень полезной.
              • 0
                если едешь по «незнакомому неосвещенному городу в дождь или снег», то тем более надо смотреть на дорогу, а не на иконки на навигаторе :)
                • +2
                  навигатор может пищать или свистеть перед такого рода препятствием. Не обязательно в него смотреть вообще.

                  Вообще я бы в такую карту еще особо крупные ямы вносил ;)
                  • +3
                    На полицаи не всегда ненесена соответствующая разметка.
                    Ставить соответсвующие знаки часто забывают (например у нас в городе на одной улице штук 6 полицаев, дорожники чтобы не ставить все необходимые знаки, поставили знак прочие опасности и успокоились).
                    Знаки иногда банально не видны (например на участке по которому я часто езжу есть полицай, который находится через 10 метров после начала спуска. Тоесть пока ты не начнешь спуск, ты его в принципе не увидишь. А за эти 10 метров ты особо скорость сбросить не успеешь)
                    • +1
                      У меня навигатор с ОСМ картой, подающий сигнал о лежащих полицейских.

                      И как минимум пару-раз он меня уберег от неожиданного подпрыга на бетонном бугре замаскированным под цвет дороги, без разметки и знаков. %)) Не забывайте что лежекопы тут бывают очень разными. )

                      Мало того, правильный маршрутопрокладчик должен учитывать потери скорости на лежекопах, и при наличии маршрута без них — прокладывать в обход.
                    • –1
                      Лежачие полицейские и так устанавливаются обычно в таких местах, где знаки и разметка предписывают снизить скорость и повысить бдительность, и главная функция навигатора в таком месте — предупредить о превышении скорости, а не о том, что через 100 метров расположен лежачий полицейский.
                      • НЛО прилетело и опубликовало эту надпись здесь
                  • +1
                    Чтобы получать предупреждение о том, что по пути лежекоп.
                    • +2
                      А можно еще карту ям и пешеходных переходов? А то совсем неинтересно на дорогу смотреть :)
                      • 0
                        А для ям и пешеходных переходов есть тип у Навитела?
                      • +1
                        даешь карту светофоров!
                        • +1
                          + точное время их переключения на зеленый свет
                          • 0
                            Запросто.
                            Машинно-читаемый тег http://wiki.openstreetmap.org/wiki/RU:Key:opening_hours применим к любым подобным периодически-расписанным вещам.
                            Правда, у меня нет подобной информации, и в OSM ее никто пока тоже не вносил. Если она у вас есть, вы можете внести и попробовать сделать что-то подобное :)
                          • 0
                            Давайте. Светофоры наносятся как highway=traffic_signals.
                            http://wiki.openstreetmap.org/wiki/RU:Tag:highway%3Dtraffic_signals
                            Это открытый проект, достаточно подробное описание, как сделать выгрузку, написано выше. Хотите попробовать сами?)
                          • 0
                            А как можно для навитела выдернуть часть точек, например для Москвы и МО?
                            • НЛО прилетело и опубликовало эту надпись здесь
                              • 0
                                нет. для гармина будет отдельная генерация точек. в форматах *.gpx и возможно в *.gpi
                              • 0
                                глянул Ростов-на-Дону, в «родных» навителовских картах, «лежачих полицейских» на порядок больше, и почему то судя по карте половина города с ограничением 90 км/час.
                                • +1
                                  помогайте наполнять — будет и здесь немало! :)
                                  • +1
                                    Вспомнить лежекопы в своем районе и нанести на карту — 15-20 мин работы, просто покликать точки на карте. :)
                                  • 0
                                    travelgps.com.ua вроде как успешно и спидкамы и лежекопы и направления для навитела в своей карте Украины делает.
                                    Причём не только для Навитела.
                                    И на ихнем форуме всё расписано, где, как и зачем.
                                    • 0
                                      А они согласованы как нибудь с проектом от stas_symba? У него вроде побольше объем файла, а если оставить оба, боюсь будут дубли.
                                      • 0
                                        На данный момент я написал ему письмо по поводу согласований/сотрудничества. Ждём реакции. :)

                                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.