如何处理Shapely中的舍入错误

时间:2015-01-19 16:10:44

标签: python shapely

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

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"应该在第1行和它们的交叉点上:

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]))

打印"错误"。

我理解这背后的浮动精度问题,但这是否意味着我永远不会测试线上的点?当我根据点列表构建一条线时,我能否确定至少所有"构造"积分会在线?

1 个答案:

答案 0 :(得分:5)

从根本上说,需要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,则仅运行第二个且更昂贵的测试。