Python使用shapely、geopandas查找3条及以上线交点并合并线的方法
实现方案
步骤1:查找3条及以上LineString交汇的接触点
核心逻辑是统计每个空间点关联的LineString数量,筛选出关联数≥3的点,需要优先处理坐标浮点误差问题:
- 先给你的GeoDataFrame新增唯一标识列,方便后续关联线段:
import geopandas as gpd import shapely from shapely.geometry import Point from collections import defaultdict from shapely.ops import linemerge # 替换为你自己的GeoDataFrame变量名 line_gdf = your_geodataframe # 坐标保留小数位数,根据你的数据精度调整,避免浮点误差导致同点异坐标 PRECISION = 6 line_gdf['line_id'] = line_gdf.index
- 构建点与关联线段的映射表,统计每个点的关联线段数:
point_line_map = defaultdict(list) for idx, row in line_gdf.iterrows(): line = row.geometry # 兼容MultiLineString格式 line_list = list(line.geoms) if isinstance(line, shapely.MultiLineString) else [line] for l in line_list: # 提取线段两端点,做精度统一 start_coord = (round(l.coords[0][0], PRECISION), round(l.coords[0][1], PRECISION)) end_coord = (round(l.coords[-1][0], PRECISION), round(l.coords[-1][1], PRECISION)) # 记录当前线段和两个端点的关联关系 point_line_map[start_coord].append(idx) point_line_map[end_coord].append(idx) # 筛选出关联≥3条不同线段的交汇点 junction_points = [Point(coord) for coord, line_ids in point_line_map.items() if len(set(line_ids)) >= 3]
如果你存在线段非端点接触的情况(比如某线段端点落在另一条线段中间),需要额外加一步:遍历所有点,判断点是否在线段边界上,更新
point_line_map的关联关系即可。如果所有线段都是端点相接,可跳过该步骤。
步骤2:按要求合并交汇线段
假设你的线段属性表中存在color字段,可区分pink/purple/green三类线段,处理逻辑如下:
# 遍历所有交汇点处理,单交汇点可直接取junction_points[0] for junc_p in junction_points: # 筛选出和当前交汇点接触的所有线段 related_lines = line_gdf[line_gdf.geometry.touches(junc_p)].copy() # 提取三类线段 pink_line = related_lines[related_lines['color'] == 'pink'].iloc[0].geometry purple_line = related_lines[related_lines['color'] == 'purple'].iloc[0].geometry green_line = related_lines[related_lines['color'] == 'green'].iloc[0].geometry # 合并线段,允许重叠,合并不连续的情况会自动返回MultiLineString new_line_pink_purple = linemerge([pink_line, purple_line], directed=False) new_line_green_purple = linemerge([green_line, purple_line], directed=False) # 后续操作:删除原有的三条线段,把两条新线段插入原GeoDataFrame即可 line_gdf = line_gdf.drop(related_lines.index) new_rows = gpd.GeoDataFrame( {'color': ['pink_purple', 'green_purple'], 'geometry': [new_line_pink_purple, new_line_green_purple]}, crs=line_gdf.crs ) line_gdf = gpd.concat([line_gdf, new_rows], ignore_index=True)
注意事项
- 如果你的原始数据存在线段交叉的情况,先调用
line_gdf.geometry = shapely.ops.unary_union(line_gdf.geometry).geoms将所有线段在交叉点处打断,再执行上述步骤即可。 - 坐标精度参数
PRECISION需要根据你的数据坐标系调整,比如WGS84坐标系下保留6位小数对应约10cm的精度,足够大多数场景使用。
内容的提问来源于stack exchange,提问作者Nolan Cardozo
相关产品推荐
相关产品推荐

