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), он имеет два узла, а не один. Видно здесь на момент этого ответа.

Зная это, я могу придумать две причины, по которым вы получите эту ошибку:

  1. Вы не проходите в аргументеlocation=Trueкapply_fileметод, предложенный документацией :

    Из-за того, как структурированы данные OSM, osmium необходимо внутренне кэшировать геометрию узла, когда обработчик хочет обработать геометрию путей и областей. Метод apply_file() не может сам определить, нужен ли этот кеш. Поэтому местоположения необходимо явно включить, установив для параметра местоположения значение True:

    h.apply_file("test.osm.pbf", locations=True, idx='flex_mem')

    Глядя на ваш код выше, метод apply_file имеет только входной файл в качестве аргумента, поэтому я думаю, что это, вероятно, ваша проблема.

  2. Это может быть ссылка на узел, который отсутствует в вашем извлечении 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.

Другие вопросы по тегам