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

如何通过OSMnx准确获取坐标点间路径的米制距离

问题根源

你当前输出的长度单位为度,不是米,代码存在4个核心错误:

  • nearest_nodes参数顺序传反:该函数要求输入顺序为(图对象, 经度x, 纬度y),你调用时先传纬度再传经度,匹配到的最近节点位置错误,对应的起终点到节点的距离计算结果也不准。
  • 输入坐标系EPSG编码写错:OSMnx默认拉取的路网使用WGS84坐标系,对应EPSG编号为4326,你写的4236为无效编码。
  • 坐标转换代码被注释:geom.Transform(coordTransform)行被注释,几何始终停留在经纬度坐标系,直接调用Length()得到的是经纬度差值的度数,不具备米制长度意义。
  • 最短路径计算未加长度权重:调用nx.shortest_path时没有指定weight="length",默认返回经过节点数最少的路径,不是实际距离最短的路径。
修正方法

方案1:修复原有自定义坐标转换逻辑

修正所有错误点后的代码如下,最终输出单位为米:

def nodes_to_linestring(path):
    coords_list = [(G.nodes[i]['x'], G.nodes[i]['y']) for i in path ]
    line = LineString(coords_list)
    return(line)

def shortestpath(o_lat, o_long, d1_lat, d1_long):
    # 调整经纬度传参顺序,匹配nearest_nodes的x(经度)/y(纬度)要求
    nearestnode_origin, dist_o_to_onode = ox.nearest_nodes(G, o_long, o_lat, return_dist=True)
    nearestnode_dest, dist_d_to_dnode = ox.nearest_nodes(G, d1_long, d1_lat, return_dist=True)
    
    dist_to_network = dist_o_to_onode + dist_d_to_dnode
    
    # 增加length权重,计算实际最短路径
    shortest_p = nx.shortest_path(G, nearestnode_origin, nearestnode_dest, weight="length") 
    
    route = nodes_to_linestring(shortest_p)
    
    inSpatialRef = osr.SpatialReference()
    inSpatialRef.ImportFromEPSG(4326) # 修正为正确的WGS84 EPSG编号
    outSpatialRef = osr.SpatialReference()
    outSpatialRef.ImportFromEPSG(32614) # 该投影覆盖Grand Forks,单位为米,选择正确
    coordTransform = osr.CoordinateTransformation(inSpatialRef, outSpatialRef)
    
    geom = ogr.CreateGeometryFromWkt(route.wkt)
    geom.Transform(coordTransform) # 取消注释,执行投影转换
    length = geom.Length()
    
    total_length = length + dist_to_network
    return(route, total_length)

另外你当前对DataFrame做apply时,同一行数据会调用两次shortestpath,重复计算浪费性能,可以调整为单次计算后拆分结果,运行速度能提升一倍:

start_time = time.time()
# 单次计算同时拿到几何和长度
res = df.apply(lambda x: shortestpath(x['o_lat'], x['o_long'], x['d1_lat'], x['d1_long']), axis=1)
df['osmnx_geometry'] = res.apply(lambda x: x[0])
df['osmnx_length'] = res.apply(lambda x: x[1])
print("Time taken: ", (time.time() - start_time), "seconds")

方案2:使用OSMnx内置能力,代码更简洁

OSMnx拉取的路网边属性中已经自带单位为米的length字段,不需要手动做坐标转换,直接调用NetworkX的带权路径长度计算即可,能避免坐标转换相关的错误:

def shortestpath(o_lat, o_long, d1_lat, d1_long):
    nearestnode_origin, dist_o_to_onode = ox.nearest_nodes(G, o_long, o_lat, return_dist=True)
    nearestnode_dest, dist_d_to_dnode = ox.nearest_nodes(G, d1_long, d1_lat, return_dist=True)
    
    dist_to_network = dist_o_to_onode + dist_d_to_dnode
    # 直接读取边属性的length计算路径总长度,单位为米
    network_length = nx.shortest_path_length(G, nearestnode_origin, nearestnode_dest, weight="length")
    shortest_p = nx.shortest_path(G, nearestnode_origin, nearestnode_dest, weight="length")
    route = nodes_to_linestring(shortest_p)
    
    total_length = network_length + dist_to_network
    return(route, total_length)

内容的提问来源于stack exchange,提问作者Josh Canfield

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 17:15:41