如何在Shapely中区分多边形自相交与自接触?
区分自接触与自相交多边形,及Shapely实现方法
几何定义区分
- 自接触(self-touching)多边形:多边形的非相邻边仅在顶点处重合接触,没有边互相穿过的情况,整体无内部交叉区域。比如你提供的蓝色多边形,边
[0,100]->[50,80]和[0,60]->[50,30]在顶点(0,60)处接触。 - 自相交(self-intersecting)多边形:多边形的非相邻边穿过彼此(交点为线段内部点),形成交叉区域,属于复杂多边形。比如你提供的红色多边形,边
[0,100]->[50,80]和[-10,60]->[50,30]交叉于非顶点位置。
Shapely中的区分方法
核心思路
通过检查非相邻边的交点类型来区分:
- 遍历多边形所有非相邻的边对
- 对每对边计算交点
- 判断交点是顶点(端点)还是线段内部点:
- 存在内部点交点 → 自相交多边形
- 仅存在端点重合的交点 → 自接触多边形
- 无交点 → 简单多边形
代码实现
结合你提供的示例代码,添加区分逻辑:
from shapely.geometry import Polygon, LineString from shapely.affinity import translate import pylab def classify_polygon(poly): # 获取多边形外边界顶点(闭合结构,去除重复的首尾点) coords = list(poly.exterior.coords)[:-1] edges = [] # 生成所有边的LineString对象 for i in range(len(coords)): start = coords[i] end = coords[(i+1)%len(coords)] edges.append(LineString([start, end])) has_internal_intersection = False has_vertex_contact = False # 遍历所有非相邻边对 for i in range(len(edges)): for j in range(i+2, len(edges)): # 跳过相邻边或首尾边 if (j == i+1) or (i == 0 and j == len(edges)-1): continue edge1 = edges[i] edge2 = edges[j] intersection = edge1.intersection(edge2) if not intersection.is_empty: if intersection.geom_type == 'Point': pt_coords = (intersection.x, intersection.y) # 判断是否为两边的端点重合 if (pt_coords == edge1.coords[0] or pt_coords == edge1.coords[1]) and \ (pt_coords == edge2.coords[0] or pt_coords == edge2.coords[1]): has_vertex_contact = True else: # 交点为线段内部点,属于自相交 has_internal_intersection = True else: # 交点为线段(边重合),属于自接触 has_vertex_contact = True if has_internal_intersection: return "自相交(self-intersecting)" elif has_vertex_contact: return "自接触(self-touching)" else: return "简单多边形(simple)" # 测试蓝色多边形 points = [[0, 0], [0, 100], [50, 80], [0, 60], [50, 30]] blue_poly = Polygon(points) print("蓝色多边形类型:", classify_polygon(blue_poly)) # 测试红色多边形 points = [[0, 0], [0, 100], [50, 80], [-10, 60], [50, 30]] red_poly = Polygon(points) red_poly = translate(red_poly, xoff=70) print("红色多边形类型:", classify_polygon(red_poly)) # 保留原有绘图代码 pylab.figure() x,y = blue_poly.exterior.xy pylab.plot(x,y, 'b') pylab.plot(0, 60, 'ko') x,y = red_poly.exterior.xy pylab.plot(x,y, 'r') pylab.axis('equal') pylab.grid(True) pylab.show()
关键说明
- Shapely的
is_simple属性无法区分两者:自接触和自相交的多边形is_simple都会返回False,必须通过交点类型进一步判断。 - 交点判断是核心:通过
intersection方法获取边的交点,再根据几何类型和坐标判断是顶点重合还是内部交叉,以此区分两种情况。
内容的提问来源于stack exchange,提问作者nickponline
相关产品推荐
相关产品推荐

