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

如何在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中的区分方法

核心思路

通过检查非相邻边的交点类型来区分:

  1. 遍历多边形所有非相邻的边对
  2. 对每对边计算交点
  3. 判断交点是顶点(端点)还是线段内部点:
    • 存在内部点交点 → 自相交多边形
    • 仅存在端点重合的交点 → 自接触多边形
    • 无交点 → 简单多边形

代码实现

结合你提供的示例代码,添加区分逻辑:

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 23:35:26