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