如何处理两线段相交时的重叠场景(不返回交点)
解决共线重叠线段的交点判断问题
首先明确核心需求:当两条共线线段存在长度大于0的重叠部分时,不返回任何交点;仅当两线段仅在单个端点处接触时,才返回该端点。
修改思路
- 先通过叉积判断两线段是否共线;
- 共线时,将线段投影到合适的坐标轴上(非垂直的轴,比如x轴非垂直就用x,否则用y),得到线段的区间范围;
- 计算两个区间的交集:
- 若交集是单点(区间首尾数值相等,考虑浮点误差),说明仅端点相交,返回该点;
- 若交集是长度大于0的区间,说明线段重叠,返回
None;
- 非共线场景按常规线段相交逻辑处理。
修改后的代码
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
相关产品推荐
相关产品推荐

