如何修复Python线段相交函数在共享端点时的失效问题
问题描述
现有两条水平线段:线段1端点为(1,1)、(4,1),线段2端点为(4,1)、(8,1),二者共享端点(4,1)。
调用自定义的线段相交函数时,输出为0,因为div的值为0,函数判定两条线段为平行线并返回0。需要修改该函数,使其能识别这种共享端点的情况,并返回该公共端点作为交点。
我的Python相交函数如下:
def line_intersection (line1, line2): line1 = eval(str(line1)) line2 = eval(str(line2)) x1,x2,x3,x4 = float(line1[0][0]),float(line1[1][0]),float(line2[0][0]),float(line2[1][0]) y1,y2,y3,y4 = float(line1[0][1]),float(line1[1][1]),float(line2[0][1]),float(line2[1][1]) xdiff = (x1- x2, x3 - x4) ydiff = (y1 - y2, y3 - y4) def det(a, b): i = a[0] * b[1] j = a[1] * b[0] return i - j div = det(xdiff, ydiff) if div == 0: # print("lines do not intersect") return 0 d = (det(*line1), det(*line2)) x = det(d, xdiff) x = x/ div y = det(d, ydiff) y = y /div point = (x, y) x1, x2 = sorted([x1, x2]) y1, y2 = sorted([y1, y2]) if x < x1 or x > x2 or y < y1 or y > y2: # print("intersection point not within line segment") return 0 x1, x2 = sorted([x1, x2]) y1, y2 = sorted([y1, y2]) if x < x1 or x > x2 or y < y1 or y > y2: # print("intersection point not within line segment") return 0 return point line1 = ((1, 1), (4, 1)) line2 = ((4, 1), (8, 1)) print(line_intersection(line1, line2))
解决方案
当div == 0时,两条线段要么平行要么共线。此时需要额外检查线段的端点是否重合,或线段是否存在重叠区间。以下是修改后的函数:
def line_intersection(line1, line2): # 直接解析线段端点,移除不安全的eval调用 (x1, y1), (x2, y2) = line1 (x3, y3), (x4, y4) = line2 x1, x2, x3, x4 = float(x1), float(x2), float(x3), float(x4) y1, y2, y3, y4 = float(y1), float(y2), float(y3), float(y4) xdiff = (x1 - x2, x3 - x4) ydiff = (y1 - y2, y3 - y4) def det(a, b): return a[0] * b[1] - a[1] * b[0] div = det(xdiff, ydiff) if div != 0: # 非平行线段,计算交点 d = (det((x1, y1), (x2, y2)), det((x3, y3), (x4, y4))) x = det(d, xdiff) / div y = det(d, ydiff) / div point = (x, y) # 检查交点是否在线段1范围内 min_x1, max_x1 = sorted([x1, x2]) min_y1, max_y1 = sorted([y1, y2]) if not (min_x1 <= x <= max_x1 and min_y1 <= y <= max_y1): return 0 # 检查交点是否在线段2范围内 min_x2, max_x2 = sorted([x3, x4]) min_y2, max_y2 = sorted([y3, y4]) if not (min_x2 <= x <= max_x2 and min_y2 <= y <= max_y2): return 0 return point else: # 平行或共线情况,检查端点是否在线段上 def point_on_segment(px, py, seg_x1, seg_y1, seg_x2, seg_y2): min_x = min(seg_x1, seg_x2) max_x = max(seg_x1, seg_x2) min_y = min(seg_y1, seg_y2) max_y = max(seg_y1, seg_y2) # 先判断坐标区间,再验证共线 return (min_x <= px <= max_x and min_y <= py <= max_y) and \ (det((px - seg_x1, py - seg_y1), (seg_x2 - seg_x1, seg_y2 - seg_y1)) == 0) intersections = [] # 检查线段1的端点是否在seg2上 if point_on_segment(x1, y1, x3, y3, x4, y4): intersections.append((x1, y1)) if point_on_segment(x2, y2, x3, y3, x4, y4): intersections.append((x2, y2)) # 检查线段2的端点是否在seg1上,避免重复添加 if point_on_segment(x3, y3, x1, y1, x2, y2) and (x3, y3) not in intersections: intersections.append((x3, y3)) if point_on_segment(x4, y4, x1, y1, x2, y2) and (x4, y4) not in intersections: intersections.append((x4, y4)) # 返回第一个有效交点(如共享端点),无交点则返回0 return intersections[0] if intersections else 0 line1 = ((1, 1), (4, 1)) line2 = ((4, 1), (8, 1)) print(line_intersection(line1, line2)) # 输出:(4.0, 1.0)
关键修改点
- 移除了不安全的
eval调用,直接解构传入的线段元组,提升代码安全性与效率。 - 新增
point_on_segment辅助函数,用于判断点是否在线段上(含端点)。 - 在平行/共线分支中,检查所有端点是否属于另一条线段,收集并返回有效交点。
- 修正原函数中
return point的缩进错误,确保非平行情况能正确返回交点。
内容的提问来源于stack exchange,提问作者amit
相关产品推荐
相关产品推荐

