Раскрасим домики

Итак, после предыдущих упражнений здания на нашей карте обзавелись номерами и высотой. Что дальше? Дальше можно, например, раскрасить здания в разные цвета. Можно раскрасить дома в зависимости от основного их предназначения (то есть, в зависимости от содержимого тэгов amenity и building). Можно — в зависимости от принадлежности здания.

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

Достичь подобного результат с картами OpenStreetMap, рисуемыми через библиотеку Leaflet, можно разными путями: можно, взяв какую-либо карту, не трогать её растровый слой, оставить его без изменений, добавив свой векторный слой, куда нанести контуры зданий. Пример — usjeans.ru/map. Другой подход — сделать собственный растровый слой, на котором сразу и отметить необходимое. Так как предыдущие эксперименты касались как раз собственного растрового слоя — продолжим опыты в том же направлении.

Отметить принадлежность зданий в OpenStreetMap можно разными путями: первый, очевидный — задать у каждого нужного нам здания какой-нибудь новый тэг. Тэг может быть практически любым — даже при существующих ограничениях на имена можно придумать что-нибудь. То множество тэгов, что применяется в OSM — результат не жёсткого диктата разработчиков, а договорённости сообщества участников и множество это легко расширяемо. Другой путь, который мне представляется более верным — создать отношение. Для группировки объектов, представляющих собой что-то общее, предназначено отношение с типом site. Как выяснилось, нужное мне отношение уже́ существовало — надо было лишь проверить его корректность и внести необходимые изменения (например, добавить здания, в отношение не попавшие).

На следующем этапе, импорте данных, выяснилось, что в imposm не предусмотрен способ сохранить в базе данных информацию о принадлежности к отношению. Во всяком случае, в документации он не описан. Не беда — эту информацию можно внести и после импорта, напрямую обратившись к базе данных. Для хранения информации о принадлежности нужно создать дополнительное поле. Так как нам нужен только признак принадлежности здания конкретному отношению, достаточно будет типа Bool. После всех изменений описание сопоставления данных для зданий в файле imposm-mapping.py стало выглядеть так:

buildings = Polygons(
    name = 'buildings',
    fields = (
        ('area', PseudoArea()),
        ('addr:housenumber',String()),
        ('building:levels',Integer()),
        ('height',Integer()),
        ('belongs_to_susu',Bool()),
    ),
    mapping = {
        'building': (
            '__any__',
        ),
        'railway': (
            'station',
        ),
        'aeroway': (
            'terminal',
        ),
    }
)

Выставить флаг принадлежности можно выполнением SQL-запроса

UPDATE osm_buildings
SET belongs_to_susu=1
WHERE osm_id IN (список_id, через запятую);

Чтоб не перечислять объекты вручную, был написан перловый скрипт. Попутно выяснилось, что, несмотря на то, что отношение может в себе содержать другие отношения, нет смысла устраивать рекурсивный обход: в поле osm_buildings.osm_id хранится первый попавшийся номер: он может быть как номером линии (для большинства зданий), так и номером отношения.

Задача определения роли здания после всех предыдущих манипуляций кажется не такой уж и сложной: во-первых, тип здания (точнее, его предназначение) может хранится в тэге building — его содержимое при импорте попадает в поле osm_buildings.type. Среди допустимых типов есть и dormitory — общежития (кстати, не надо путать с tourism:hostel — это совсем разные тэги). Тип «учебные корпуса» (например, academic_building) среди часто применяемых не встречается — есть лишь university, который не совсем подходит: университет — это не только учебные корпуса. Можно, конечно, прямо у самих зданий указывать building=academic, но мне более правильным показался вариант указания роли здания внутри отношения — там и поле для роли есть, и оно не используется совсем. Больше шансов, что данные спокойно сохранятся именно тогда, когда они лежат внутри отношения. А вот в базу данных роль вносится в поле osm_buildings.type:

UPDATE osm_buildings
SET type='academic'
WHERE osm_id IN (список_id, через, запятую);

Как и прежде, для упрощения назначения ролей, написан ещё один перловый скрипт.

Стилевые правила для зданий (в OSM Bright он лежат в файле base.mss) начинаются так:

#buildings[zoom>=12] {
  polygon-fill:@building;
  // Our buildings
  [belongs_to_susu=1] {
    polygon-fill: @susu_building;
    [type='dormitory'] {
     polygon-fill: @susu_dormitory;
    }
    [type='academic'] {
     polygon-fill: @susu_academic;
    }
  }

Определение цветов @susu_building, @susu_dormitory, @susu_academic добавлено в файл palette.mss — там для них самое подходящее место.

@susu_building:     saturate(darken(@building, 15%), 10);
@susu_dormitory:    mix(@susu_building, #f60, 95%);
@susu_academic:     mix(@susu_building, #06f, 93%);

Результат:
Карта с разноцветными домами

Раскрасим домики: 2 комментария

  1. Уведомление: Karta ne po-russki | shoorick.ru