【发布时间】:2016-07-05 06:38:59
【问题描述】:
我写了一个代码测试平面中两条线段的交点。我不会用所有的细节来打扰你。
代码采用两条线段,每条线段由两个端点描述,然后通过在y = a*x + b 中拟合a 和b 将每个线段拟合为一条线。然后通过x = (b2 - b1) / (a2 - a1)找到两条线的交点。最后,它会测试交点x 是否包含在两条线段内。
相关部分如下所示:
# line parameterization by a = Delta y / Delta x, b = y - a*x
a1 = (line1.edge2.y - line1.edge1.y) / (line1.edge2.x - line1.edge1.x)
b1 = line1.edge1.y - a1 * line1.edge1.x
a2 = (line2.edge2.y - line2.edge1.y) / (line2.edge2.x - line2.edge1.x)
b2 = line2.edge1.y - a2 * line2.edge1.x
# The intersection's x
x = - (b2 - b1) / (a2 - a1)
# If the intersection x is within the interval of each segment
# then there is an intersection
if (isininterval(x, line1.edge1.x, line1.edge2.x) and
isininterval(x, line2.edge1.x, line2.edge2.x)):
return True
else:
return False
为简洁起见,我放弃了很多处理特定情况的测试,例如当边缘相互平行时 (a1==a2),当它们在同一条线上时,当边缘长度为 0 时,当边缘沿着垂直轴(然后a 变为无限)等。
函数isininterval很简单
def isininterval(x0, x1, x2):
"""Tests if x0 is in the interval x1 to x2"""
if x1 <= x0 <= x2 or x2 <= x0 <= x1:
return True
else:
return False
现在的问题:我发现由于舍入误差,当交点与段边缘重合时,测试会给出错误的结果。
例如,线 1 介于 (0,0) 和 (3,5) 之间,线 2 介于 (3,5) 和 (7,1) 之间,生成的交点 x 为2.9999999999999996,给出错误答案。应该是 3。
您能提出一个解决方案吗?
【问题讨论】:
-
使用十进制类:
from decimal import Decimal。 stackoverflow.com/questions/2986150/python-floating-number 。您的isininterval函数也可以简单地返回:return x1 <= x0 <= x2 or x2 <= x0 <= x1 -
编写涉及浮点数的布尔条件的标准方法是在条件中包含一些容错。例如,将
x1 <= x0 <= x1替换为x1 - eps <= x0 <= x2+ eps,其中eps类似于0.000001 -
首先,你有充分的理由担心 2.9999999999999996 不是 3 吗?
-
@YvesDaoust,好吧,我唯一担心的是它不符合条件......
-
是否有充分的理由让一个段的顶点正好落在另一段上?这些段是孤立的还是形成链或图?
标签: python floating-point precision