You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

pyosmium基于OSM关系构建GeoJSON徒步路线MultiLineString方案

Python+pyosmium 构建徒步路径GeoJSON实现方案

报错原因说明

你遇到的RuntimeError: need at least two points for linestring属于OSM数据的正常情况:部分挂载到路径关系的way是编辑残留的无效数据,仅包含1个节点,本身无法构成线段,处理时直接过滤跳过即可,不会影响最终路径的完整性。

完整实现步骤

OSM的PBF文件不会按关系、way、节点的依赖顺序存储要素,因此标准处理流程是两次遍历PBF文件,不要尝试单次遍历同时收集关系和几何,会出现引用的way/节点还没加载的问题。

1. 第一次遍历:收集目标关系与关联Way ID

这一步和你已写的逻辑基本一致,只需要注意不要用dict、list这类Python内置关键字做变量名,避免污染内置命名空间:

import osmium
import shapely.wkb as wkblib
import shapely
import json
from collections import defaultdict

wkbfab = osmium.geom.WKBFactory()

class RelationCollector(osmium.SimpleHandler):
    def __init__(self):
        super().__init__()
        self.target_rels = {}  # key: 关系ID,value: 关联的way ID集合
        self.rel_tags = {}     # 存储关系的原始标签,后续写入GeoJSON属性

    def relation(self, r):
        # 筛选带sac_scale=hiking标签的徒步路径
        if r.tags.get('sac_scale') != 'hiking':
            return
        # 测试阶段仅处理示例ID 104369,全量处理时删掉这行判断即可
        if r.id != 104369:
            return
        way_ids = set()
        for mem in r.members:
            # 仅收集way类型成员,忽略节点、嵌套子关系
            if mem.type == 'w':
                way_ids.add(mem.ref)
        self.target_rels[r.id] = way_ids
        self.rel_tags[r.id] = {k:v for k,v in r.tags}

# 执行第一次遍历
rel_collector = RelationCollector()
rel_collector.apply_file('../pbf/new-zealand.osm.pbf')

# 汇总所有需要收集几何的way ID
all_target_way_ids = set()
for way_set in rel_collector.target_rels.values():
    all_target_way_ids.update(way_set)

2. 第二次遍历:收集Way几何并过滤无效数据

这一步遍历所有way,匹配到目标ID时尝试生成LineString几何,自动过滤节点数不足2的无效线段,同时注意调用apply_file时必须加locations=True参数,pyosmium才会自动缓存way引用的节点坐标,否则无法生成几何:

class WayGeomCollector(osmium.SimpleHandler):
    def __init__(self, target_way_ids, rel_way_map):
        super().__init__()
        self.target_way_ids = target_way_ids
        self.rel_way_map = rel_way_map
        self.rel_geoms = defaultdict(list)  # key:关系ID,value:对应LineString几何列表

    def way(self, w):
        if w.id not in self.target_way_ids:
            return
        # 过滤节点数不足2的无效way
        if len(w.nodes) < 2:
            return
        try:
            wkb = wkbfab.create_linestring(w)
            line_geom = wkblib.loads(wkb, hex=True)
            # 将当前几何关联到所属的关系
            for rel_id, way_set in self.rel_way_map.items():
                if w.id in way_set:
                    self.rel_geoms[rel_id].append(line_geom)
        except Exception as e:
            # 捕获节点缺失、几何无效等其他异常,避免程序崩溃
            print(f"处理way {w.id} 时跳过,原因:{str(e)}")
            return

# 执行第二次遍历,必须加locations=True参数缓存节点坐标
way_collector = WayGeomCollector(all_target_way_ids, rel_collector.target_rels)
way_collector.apply_file('../pbf/new-zealand.osm.pbf', locations=True)

3. 组装为标准GeoJSON文件

拿到每个关系对应的LineString列表后,直接合并为MultiLineString类型,组装成标准GeoJSON结构写入文件即可,输出的文件可以直接在geojson.io正常加载渲染:

geojson_output = {
    "type": "FeatureCollection",
    "features": []
}

for rel_id, line_list in way_collector.rel_geoms.items():
    if not line_list:
        continue
    # 合并所有线段为单个MultiLineString
    multiline_geom = shapely.MultiLineString(line_list)
    feature = {
        "type": "Feature",
        "geometry": json.loads(shapely.to_geojson(multiline_geom)),
        "properties": rel_collector.rel_tags[rel_id]
    }
    # 补充OSM ID到属性
    feature["properties"]["osm_id"] = f"r{rel_id}"
    geojson_output["features"].append(feature)

# 写入本地文件
with open("hiking_trail_104369.geojson", "w", encoding="utf-8") as f:
    json.dump(geojson_output, f, ensure_ascii=False, indent=2)

OSM官网的路径渲染逻辑说明

OSM官网展示关系路径时,比上面的基础逻辑多做了两步处理,所以能呈现连续的完整路线:

  • 按照关系成员的存储顺序,结合成员的role值(forward/backward)判断线段方向,必要时反转LineString的坐标顺序
  • 按线段端点的坐标匹配相邻线段,把首尾相连的线段拼接为连续的单条LineString,同时过滤和主路径不连通的孤立碎段

如果只需要正常展示路径,直接输出MultiLineString就足够,渲染效果和官网没有肉眼差异;如果需要得到连续的单条路线,可以在拿到LineString列表后补充端点匹配、方向反转的拼接逻辑即可。

补充说明

你提到的osmium export命令行工具,内部实现逻辑和上述流程完全一致,本质也是先筛选目标要素、再过滤无效几何、最后组装输出格式,不存在特殊的黑魔法处理。
处理大区域PBF文件时,两次遍历的内存占用极低,不需要全量加载所有节点和way数据,只需要缓存目标ID对应的要素即可,性能远高于一次性加载全量数据的方案。


内容的提问来源于stack exchange,提问作者Ben On Track

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 13:12:23