如何处理 Shapely 中的舍入误差

Posted

技术标签:

【中文标题】如何处理 Shapely 中的舍入误差【英文标题】:How to deal with rounding errors in Shapely 【发布时间】:2015-01-19 16:10:44 【问题描述】:

我有一个案例,它基于在一条线上投影一个点,然后将这条线分开。我的用例稍微复杂一些,但我的问题可以用以下代码重现:

from shapely import *
line1 = LineString([(1,1.2), (2,2), (3, 2.), (4,1.2)])
pt = Point(2.5, 1.2)
pr = line1.interpolate(line1.project(pt))

通过构造,“pr”应该在 line1 和它们的交点上:

line1.contains(pr)
line1.intersects(LineString([pt, pr]))

打印两次“True”。但是更改输入坐标会稍微影响工作流程:

from shapely import *
line1 = LineString([(1,1.2), (2,2), (3, 2.3), (4,1.2)])
pt = Point(2.5, 1.2)
pr = line1.interpolate(line1.project(pt))
line1.contains(pr)
line1.intersects(LineString([pt, pr]))

打印“假”。

我了解这背后的浮动精度问题,但这是否意味着我可以永远测试在线上的点?当我根据点列表构造一条线时,我是否可以确定至少所有“构造”点都在线上?

【问题讨论】:

您是否可以选择更精细的单位,比如说毫米而不是米? @PauloScardine:谢谢。是的,如果我获得稳定性,我可以很容易地放弃精度。将我的值乘以 10 就可以了。但它适用于所有情况吗? Shapely 继续在内部使用花车。 【参考方案1】:

基本上,precision model 是必需的,并且有各种计划在某个时候将其实施到 GEOS 中(不要屏住呼吸,因为这已经讨论了好几年了)。

否则,选项是基于距离的测试(推荐)或更昂贵的基于缓冲区的技术,只需稍作调整(请参阅machine epsilon):

from shapely.geometry import LineString, Point

line1 = LineString([(1, 1.2), (2, 2), (3, 2.3), (4, 1.2)])
pt = Point(2.5, 1.2)
pr = line1.interpolate(line1.project(pt))

# Distance based
print(line1.distance(pr) == 0.0)  # True

# Buffer based
EPS = 1.2e-16
print(line1.buffer(EPS).contains(pr))  # True
print(line1.buffer(EPS).intersects(LineString([pt, pr])))  # True

您还可以使用or operator 链接更便宜和更昂贵的测试,例如:

print(line1.contains(pr) or line1.buffer(EPS).contains(pr))

只有在第一个返回 False 时才会运行第二个更昂贵的测试。

【讨论】:

嗨@MikeT,感谢您的回答,这就是我所害怕的。我真的希望我们有一个精确的模型。或者使用整数而不是浮点数的技巧(参见上面保罗的评论)会确保稳定性吗?我的用例更复杂,并且基于联合:shapely.ops.polygonize(LinearRing(line1).union(LineString([pt, pr]))) 如果两条线相交或不相交,则返回不同的多边形...... (我希望我能支持你的答案,但我对此没有足够的声誉;) /i> 能否使用这些距离测试来查看两条线串何时接触——即一个线串的最后一个点是另一个线串的第一个点?我遇到了线串,其中的点与那些特征 0.0000000001 不同(由于浮动不准确)

以上是关于如何处理 Shapely 中的舍入误差的主要内容,如果未能解决你的问题,请参考以下文章

准确预测任意浮点格式之间转换的舍入误差

如何处理多元线性回归中的误差维度?

数学库中的除法函数如何处理除法运算符无法做到的精度误差?

C语言程序设计,谭浩强老师第三版里面的一个关于浮点型数据的舍入误差问题

openjdk8中的舍入问题

滚动时 UIBezierPath 问题的舍入