如何处理 Shapely 中的舍入误差
How to deal with rounding errors in 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]))
打印 "False"。
我理解这背后的浮动精度问题,但这是否意味着我可以永远 测试线上的点?当我根据点列表构造一条线时,我可以 确定 至少所有 "construction" 点都在这条线上吗?
从根本上说,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))
如果第一个 returns False
.
只运行第二个且更昂贵的测试
我有一个案例是基于在一条线上投影一个点,然后将这条线分开。我的用例稍微复杂一些,但是我的问题可以用下面的代码重现:
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]))
打印 "False"。
我理解这背后的浮动精度问题,但这是否意味着我可以永远 测试线上的点?当我根据点列表构造一条线时,我可以 确定 至少所有 "construction" 点都在这条线上吗?
从根本上说,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))
如果第一个 returns False
.