В самой первой части, мы из большого набора данных вырезали условный город и оставили в нём только данные с адресом. Адреса интерпретировались, как принадлежащие этому городу. Т.е. точно знали в какой стране они находятся, в каком регионе и так далее. Но что, если нам нужны адреса не одного населённого пункта, а целого региона или может быть даже нескольких стран? Как узнать откуда он?
И хотя в 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Видно, что целые посёлки обозначают не верно. Это и просто мусор в названии населённого пункта. Это и путаница города Саранск и одноимённого муниципального образования, в которое входят несколько населённых пунктов. Или наоборот в место названия посёлка вписывают туда название сельского поселения. На территории самого города видно несколько десятков точек, где допущены опечатки в названии. Как я и говорил раньше: оставьте это дело машинам, там где можно ошибиться, человек обязательно ошибётся.
Сейчас присвоили название только населённого пункта. Так же по аналогии можно сделать и для привязки к поселениям и регионам стран.