pyosmium — построить линейную строку Geojson на основе отношения OSM
У меня есть скрипт python для анализа данных OSM, и цель состоит в том, чтобы построить с конкретными данными, полученными из отношения OSM .
В настоящее время я сосредоточен на отношении OSM, которое представляет собой «походную» тропу, подобную этой.
Согласно документу:
элементы
(только для чтения) Упорядоченный список членов отношения. См. osmium.osm.RelationMemberList.
объект отношения имеет атрибутmembers
который собирает все члены отношения.
Следовательно, первая часть скрипта извлекает все отношения, имеющие тег, и собирает все их пути.
Следующий скрипт намеренно фокусируется только на одном конкретном отношении: r104369
class HikingWaysfromRelations(osmium.SimpleHandler):
def __init__(self):
super(HikingWaysfromRelations, self).__init__()
self.dict = {}
def _getWays(self, elem, elem_type):
# tag
if 'sac_scale' in elem.tags and elem.tags['sac_scale']=='hiking' and elem.id==104369:
list=[]
for mem in elem.members:
if mem.type=="w":
list.append(str(mem.ref))
self.dict["r"+str(elem.id)]=list
else:
pass
def relation(self,r):
self._getWays(r, "relation")
ml = HikingWaysfromRelations()
ml.apply_file('../pbf/new-zealand.osm.pbf')
Результатом является словарь, содержащий ожидаемое отношение в качестве единственного ключа и его пути:
{"r104369": ["191668175", "765285136", "765285135", "765285138", "765285139", "191668225", "765542429", "765542430", "765542432", "765542431", "765542435", "765542436", "765542434", "765542433", "765542437", "765542438", "765542439", "765542440", "765542441", "765542442", "765548983", "271277386", "765548985", "765548984", "684295241", "684295239", "464603363", "464603364", "464607430", "299788481", "178920047", "155711655", "155711646", "684294192", "259362037", "684294189", "259362038", "259362041", "259362036", "259362043", "259362039", "259362040"]}
Теперь вопрос: как построить содержащую одну функциюMultiLineString
что соединяет все эти пути и восстанавливает предполагаемую пешеходную тропу?
Основываясь на том, что я нашел в сети, я должен повторно запуститьsimpleHander
в полном файле .pbf , и каждый раз, когда я сталкиваюсь с тем, что ищу, - на основе значений приведенного выше словаря - я могу восстановитьLineString
с:
import shapely.wkb as wkblib
wkbfab = osmium.geom.WKBFactory()
def getRelationGeometry(elem):
wkb=wkbfab.create_linestring(elem)
return wkb
Проблема в том, что некоторые пути имеют только 1 узел, поэтому возникает следующая ошибка:
RuntimeError: need at least two points for linestring (way_id=155711655)
Итак, каким было бы решение восстановитьGeoJson
особенность -multiLineString
- несколькими способами, чтобы иметь возможность отображать результат на https://geojson.io/#map=2/20.0/0.0 ?
Как, например, openstreetmap удается перестроить дорожку отношения, когда я нажимаю ссылку, если не путем соединения всех узлов (со всех сторон), выданных из отношения?
Большое спасибо за вашу помощь
Я знаю, что есть способ с bash, где вы сначала фильтруете начальный pbf, сохраняя только связь с тегомsac_scale=hiking
, а затем преобразовать этот отфильтрованный результат в GeoJson, но я действительно хочу иметь возможность генерировать то же самое с помощью python, чтобы понять, как хранятся данные OSM. Я просто не могу найти простой способ сделать это, зная, что пиосмий эквивалентен (предположительно) осмию, я считаю, что и здесь должен быть простой способ.
osmium export output/output_food-drinks.pbf -f geojson
1 ответ
Глядя на путь с идентификатором, показанным в ошибке в вашем посте (155711655), он имеет два узла, а не один. Видно здесь на момент этого ответа.
Зная это, я могу придумать две причины, по которым вы получите эту ошибку:
Вы не проходите в аргументе
location=True
кapply_file
метод, предложенный документацией :Из-за того, как структурированы данные OSM, osmium необходимо внутренне кэшировать геометрию узла, когда обработчик хочет обработать геометрию путей и областей. Метод apply_file() не может сам определить, нужен ли этот кеш. Поэтому местоположения необходимо явно включить, установив для параметра местоположения значение True:
h.apply_file("test.osm.pbf", locations=True, idx='flex_mem')
Глядя на ваш код выше, метод apply_file имеет только входной файл в качестве аргумента, поэтому я думаю, что это, вероятно, ваша проблема.
Это может быть ссылка на узел, который отсутствует в вашем извлечении pbf. Это легко проверить с помощью инструмента osmium cli:
osmium check-refs <your pbf file>
Это результат, который я получаю, запуская это на действительном собственном pbf
There are 6702885 nodes, 431747 ways, and 2474 relations in this file. Nodes in ways missing: 0
Обратите внимание
Nodes in ways missing: 0
.