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

И хотя в OpenStreetMap существует возможность на каждом доме указывать в какой он стране, области и далее ниже по иерархии, в России используется сокращённый способ — т.е. только улица и номер дома. Весь мартышкин труд по структурировании адреса будет делать за нас компьютер. Он это сделает быстрее и правильней, если конечно, все необходимые данные будут в его распоряжении.

Подготовка

Экспериментировать буду на Саранске, вернее, на его городском округе — вырезав его прямоугольником, с таким охватом: нижняя граница (45 54), верхняя (45.5 54.3). Вырезку из дампа сохраняю в формате pbf, потому, что следующий инструмент работают именно с ним:

osmconvert -b=45,54,45.5,54.3 RU-local.o5m -o=SaranskGO.pbf

Теперь вся идея в том, чтобы всем зданиям с адресом дописать в теги в каком населённом пункте они находятся. Вычислено это будет по вхождению геометрии дома в контур населённого пункта. Для это нам понадобится плагин OsmAreaTag для osmosis (более детальное описание плагина от автора). Скомпилированную версию плагина автор выложил тут. Сам osmosis можно забрать с гитхаба. Это Java приложение, так что понятно, без чего оно не будет работать.

Установка плагина

Чтобы osmosis увидел плагин osmareatag он должен располагаться в папке plugins текущего каталога, что несколько не удобно. Поэтому его можно разместить в домашнем каталоге пользователя, для windows это будет c:\Users\<Пользователь>\.openstreetmap\osmosis\plugins либо в c:\Users\<Пользователь>\AppData\Roaming\openstreetmap\osmosis\plugins. Туда и распаковываем содержимое архива плагина, папка osmareatag-1.3.zip должна лежать в папке plugins.

Настройка правил

Тут расскажу немного теории о том как с этим плагином работать. Вот пример базового файла конфига:

<?xml version="1.0" encoding="UTF-8"?>
<tag-processing>  
  <area id="national-boundary" cache-file="national-boundary.idx">
    <match type="relation">
      <tag k="boundary" v="administrative"/>
      <tag k="admin_level" v="2"/>
    </match>
  </area>

  <transform>
    <name>Country</name>
    <match>
      <tag k="building" v=".*"/>
      <tag k="addr:housenumber" v=".*"/>
      <inside area="national-boundary"/>
    </match>
    <output>
      <add-tag k="addr:country" v="${ISO3166-1}" context-area="national-boundary"/>
    </output>
  </transform>
</tag-processing>

Первое — это задаём области с которыми будем работать. У тега area есть атрибут id, где задаётся имя, чтобы в дальнейшем взаимодействовать с этим контуром. Далее в match указываем, какую геометрию выбрать из OSM, чтобы построить контур. В данном примере это отношения границ второго уровня, т.е. границы государств. Атрибут cache-file позволяет сохранить контур в файл и в дальнейшем использовать его не строя его из данных OSM заново. Во-первых построить контур страны это долго, а во-вторых в данных его может и не быть вовсе, если у нас вырезан например только отдельный регион. Если файл уже был создан, контур будет доступен для проверки вхождения в него объектов.

Второе — это трансформация объекта, тег transform. В теге match описываем какие объекты нас интересуют, а именно: здания с адресом и тег inside для проверки на вхождение в контур, где в атрибуте area указываем с каким контуром осуществляется проверка.

И если все условия выполняются, то в output описываем, что нужно делать, а именно добавим к объекту, прошедшему проверку, тег с адресом страны, значение которого возьмём из контура national-boundary ключа ISO3166-1. Если добавляемый тег уже задан, то он заменяться не будет.

Так же стоит иметь ввиду, что объекты, не попавшие под выше указанный фильтр, никуда не пропадают. Они так же остаются в результирующем файле. Поэтому если нужны только адреса, то логично предварительно отфильтровать всё не нужное, это ускорит обработку.

Наш код для дополнения адреса названием населённого пункта будет выглядеть так:

<?xml version="1.0" encoding="UTF-8"?>
<tag-processing>
  <area id="place">
    <match>
      <tag k="place" v="city|town|village|hamlet|isolated_dwelling|allotments"/>
    </match>
  </area>

  <transform>
    <name>Place</name>
    <match>
      <tag k="building" v=".*"/>
      <tag k="addr:housenumber" v=".*"/>
      <inside area="place"/>
    </match>
    <output>
      <add-tag k="addr:city-auto" v="${name}" context-area="place"/>
    </output>
  </transform>
</tag-processing>

Я специально назвал добавляемый тег addr:city-auto, чтобы посмотреть его отличия с тем, как он вручную внесён в OSM. Так же я будут сохранять в формате osm-xml, чтобы глазами увидеть добавленный тег. Команда будет выглядит так:

call osmosis-0.48.3\bin\osmosis.bat --read-pbf SaranskGO.pbf --lp --tag-area-content file=tag-building-addr-place.xml --write-xml SaranskGO.place.osm

tag-building-addr-place.xml - это как раз тот файл с правилами преобразования данных, представленный выше.

Анализ результатов

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

  <way id="103738775" version="2" timestamp="2019-09-20T18:28:15Z" uid="10124028" user="MarinaAR" changeset="74731679">
    <nd ref="1197639591"/>
    <nd ref="1197639690"/>
    <nd ref="1197639206"/>
    <nd ref="1197639237"/>
    <nd ref="1197639591"/>
    <tag k="building" v="yes"/>
    <tag k="addr:city" v="саранак"/>
    <tag k="addr:street" v="улица Лодыгина"/>
    <tag k="addr:housenumber" v="5"/>
    <tag k="addr:city-auto" v="Саранск"/>
  </way>

Но давайте воспользуемся мощностями ГИС, а не текстового редактора. Чтобы увидеть это на карте, как и в первой части, конвертируем всё в точки, фильтруем только здания с адресами и сохраняем в CSV, чтобы затем добавить эти данные в QGIS. И хотя он понимает нативные форматы OSM, для этого нужно создавать файл привязки тегов OSM к атрибутам в ГИС, т.к. по-умолчанию адреса там не отображаются. Поэтому мне всё же удобней с текстовым CSV.

Рис.1 addr:city не совпадает с addr:city-auto
Рис.1 addr:city не совпадает с addr:city-auto

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

Сейчас присвоили название только населённого пункта. Так же по аналогии можно сделать и для привязки к поселениям и регионам стран.