如何处理 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 中的舍入误差的主要内容,如果未能解决你的问题,请参考以下文章