如何通过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
相关产品推荐
相关产品推荐

