计算铁路网沿线两点之间的最短路径

问题描述 投票:0回答:1

我想计算沿铁路网从矿山到港口的最短路径。由于矿山和港口不直接在网络上,所以我首先计算出每个矿山和港口最近的铁路点。

但是,我现在正在努力将铁路网络转换为 NetworkX 图,并从那里计算每个矿山和港口之间的最短距离。当我运行代码时,它无法计算出最近的路径,因为所有距离都为零。请参阅下面我迄今为止编写的代码。铁路网络可以从这里下载。如果您能提供任何帮助,我将不胜感激。谢谢你。

# Ports
ports = 
[{'port_name': 'Geraldton', 'geometry': POINT (114.59786 -28.77688)},
{'port_name': 'Bunbury', 'geometry': POINT(115.673447 -33.318797)},
{'port_name': 'Albany', 'geometry': POINT(117.895025 -35.032831)}, 
{'port_name': 'Esperance', 'geometry': POINT(121.897114 -33.871834)}]  

# Mine sites
mines = 
[{'mine_name': 'Gold', 'geometry': POINT (117.94568 -34.93467), 
{'mine_name': 'Silver', 'geometry': POINT (115.16923 -29.65613)},
{'mine_name': 'Bronze', 'geometry': POINT (115.11039 -29.51287)}, 
{'mine_name': 'Platinum', 'geometry': POINT (115.11130 -29.42621)}]

# Convert to GeoDataFrame
crs = 'EPSG:4326'
ports = gpd.GeoDataFrame(ports, crs=crs, geometry = 'geometry')
mine_sites = gpd.GeoDataFrame(ports, crs=crs, geometry = 'geometry')

# Column for nearest rail point
ports['nearest_rail_point'] = None
mine_sites['nearest_rail_point'] = None

# Nearest rail point
for index, row in ports.iterrows():
    port_point = row['geometry']
    nearest_point = nearest_points(port_point, rail_network.unary_union)[1] 
    ports.at[index, 'nearest_rail_point'] = nearest_point

for index, row in mine_sites.iterrows():
    mine_site_point = row['geometry']
    nearest_point = nearest_points(mine_site_point, rail_network.unary_union)[1] 
    mine_sites.at[index, 'nearest_rail_point'] = nearest_point

G = momepy.gdf_to_nx(rail_network)

shortest_distances = {}

# Calculate shortest path
for mine_index, mine_row in mines.iterrows():
    mine_name = mine_row['mine_name']
    mine_point = mine_row['geometry']
    
    shortest_distances[mine_name] = {}
    
    for port_index, port_row in ports.iterrows():
        port_name = port_row['port_name']
        port_point = port_row['geometry']

        try:
            shortest_distance = nx.shortest_path_length(G, 
                                                        source=(mine_point.x, mine_point.y), 
                                                        target=(port_point.x, port_point.y), 
                                                        weight='length')
            shortest_distances[mine_name][port_name] = shortest_distance
        except nx.NetworkXNoPath:
            shortest_distances[mine_name][port_name] = float('inf')  # No path found

python pandas networkx geopandas shapely
1个回答
0
投票

尚不清楚您是否需要每个矿井与其相应端口(同一索引)之间或所有端口之间的最短路径。无论哪种方式,一个选择是使用原始方法(使用

momempy
)来创建图形并计算
shortest_path_length
(或
shortest_path
,具体取决于您的预期输出)。然而,在此之前,您需要将地雷捕捉到最近的铁路边界:

spots = (pd.concat([
    ports.rename(columns={"port_name": "spot_name"}),
    mine_sites.rename(columns={"mine_name": "spot_name"})])
             .to_crs("EPSG:3857"))

import momepy
G = (momepy.gdf_to_nx(
    rail_network[["name", "geometry"]].explode(),
    approach="primal", multigraph=False, length="dis"))

def nearest_bnd(p, ls, shp=False):
    sp, *_, ep = ls.coords
    nb = min(map(Point, [sp, ep]), key=p.distance)
    return nb if shp else (nb.x, nb.y)
        
coos = (spots.rename_geometry("geom_sp")
        .sjoin_nearest(rail_network.assign(geom_rn=rail_network["geometry"]))
        .set_geometry("geom_rn").assign(coo=lambda x: [nearest_bnd(p, ls)
        for p, ls in x[["geom_sp", "geom_rn"]].to_numpy()])
        .set_index("spot_name")["coo"])

all_spl = {}
for mn in mine_sites["mine_name"]:
    for pn in ports["port_name"]:
        try:
            uv = map(coos.get, [mn, pn])
            spl = nx.shortest_path_length(G, *uv, weight="dis")
            spl = round(spl / 1000, 2)
        except nx.NetworkXNoPath:
            spl = float("inf")
        all_spl.setdefault(mn, []).append({pn: spl})

{mn: min(d, key=lambda x: list(x.values())[0]) for mn, d in all_spl.items()}

# {
#     "Gold": {"Albany": 0.0},
#     "Silver": {"Geraldton": 117.85},
#     "Bronze": {"Geraldton": 117.85},
#     "Platinum": {"Geraldton": 117.85},
# }

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.