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

如何处理两线段相交时的重叠场景(不返回交点)

解决共线重叠线段的交点判断问题

首先明确核心需求:当两条共线线段存在长度大于0的重叠部分时,不返回任何交点;仅当两线段仅在单个端点处接触时,才返回该端点。

修改思路

  1. 先通过叉积判断两线段是否共线;
  2. 共线时,将线段投影到合适的坐标轴上(非垂直的轴,比如x轴非垂直就用x,否则用y),得到线段的区间范围;
  3. 计算两个区间的交集:
    • 若交集是单点(区间首尾数值相等,考虑浮点误差),说明仅端点相交,返回该点;
    • 若交集是长度大于0的区间,说明线段重叠,返回None;
  4. 非共线场景按常规线段相交逻辑处理。

修改后的代码

def ccw(A, B, C):
    # 计算叉积,判断三点的转向
    return (B[0]-A[0])*(C[1]-A[1]) - (B[1]-A[1])*(C[0]-A[0])

def segment_intersection(line1, line2):
    A, B = line1
    C, D = line2

    # 判断两线段是否共线
    if ccw(A, B, C) == 0 and ccw(A, B, D) == 0:
        # 处理共线情况:提取线段的坐标区间
        def get_interval(p1, p2, axis):
            # axis=0是x轴,axis=1是y轴
            return (min(p1[axis], p2[axis]), max(p1[axis], p2[axis]))
        
        # 选择投影轴:如果线段不是竖线,用x轴,否则用y轴
        if abs(B[0] - A[0]) > 1e-9:
            axis = 0
        else:
            axis = 1
        
        # 获取两个线段的区间
        a_start, a_end = get_interval(A, B, axis)
        c_start, c_end = get_interval(C, D, axis)
        
        # 计算区间交集
        intersect_start = max(a_start, c_start)
        intersect_end = min(a_end, c_end)
        
        # 判断交集类型:单点则返回对应坐标,重叠则返回None
        if abs(intersect_start - intersect_end) < 1e-9:
            # 找到单点对应的坐标
            if axis == 0:
                return (intersect_start, A[1])
            else:
                return (A[0], intersect_start)
        else:
            # 存在长度大于0的重叠,返回None
            return None
    else:
        # 非共线场景的常规判断
        ccw1 = ccw(A,B,C)
        ccw2 = ccw(A,B,D)
        ccw3 = ccw(C,D,A)
        ccw4 = ccw(C,D,B)
        
        # 判断线段是否跨立相交
        if (ccw1 * ccw2 < 0) and (ccw3 * ccw4 < 0):
            denom = ( (B[0]-A[0])*(D[1]-C[1]) - (B[1]-A[1])*(D[0]-C[0]) )
            t = ( (A[0]-C[0])*(D[1]-C[1]) - (A[1]-C[1])*(D[0]-C[0]) ) / denom
            x = A[0] + t*(B[0]-A[0])
            y = A[1] + t*(B[1]-A[1])
            return (x, y)
        # 判断端点是否在另一线段上(非共线情况)
        def on_segment(p, seg):
            s, e = seg
            return (min(s[0], e[0]) - 1e-9 <= p[0] <= max(s[0], e[0]) + 1e-9 and
                    min(s[1], e[1]) - 1e-9 <= p[1] <= max(s[1], e[1]) + 1e-9)
        
        if on_segment(C, line1):
            return C
        if on_segment(D, line1):
            return D
        if on_segment(A, line2):
            return A
        if on_segment(B, line2):
            return B
        return None

测试验证

  • 重叠场景测试:
    line1 = ((0, 0), (2, 0))
    line2 = ((1, 0), (2, 0))
    print(segment_intersection(line1, line2))  # 输出:None
    
  • 端点相交场景测试:
    line1 = ((0, 0), (2, 0))
    line2 = ((2, 0), (3, 0))
    print(segment_intersection(line1, line2))  # 输出:(2, 0)
    
  • 普通相交场景测试:
    line1 = ((0, 0), (2, 2))
    line2 = ((0, 2), (2, 0))
    print(segment_intersection(line1, line2))  # 输出:(1.0, 1.0)
    

内容的提问来源于stack exchange,提问作者amit

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 15:25:21