在Shapely中查找多边形上最近点的坐标

32

假设我有以下的多边形和点:

>>> poly = Polygon([(0, 0), (2, 8), (14, 10), (6, 1)])
>>> point = Point(12, 4)

enter image description here

我可以计算点到多边形的距离...

>>> dist = point.distance(poly)
>>> print(dist)
2.49136439561

...但我希望知道多边形边界上最短距离对应的点的坐标。

我的初始方法是通过将该点缓冲到多边形的距离,并找到圆与多边形相切的点:

>>> buff = point.buffer(dist) 

图片描述 然而,我不确定如何计算那个点。两个多边形不相交,所以list(poly.intersection(buff))无法给我那个点。

我这样做是对的吗?有更简便的方法吗?


2
重复的问题? https://dev59.com/GGgu5IYBdhLWcg3w6bOo - Oleg Sklyar
1
@Oleg,我不认为这是重复的。正如我上面提到的,我没有问题计算到多边形的最小距离。我正在尝试找到多边形边界上测量最小距离的点。 - AJG519
可能是Shapely中两个几何图形最近点的坐标的重复问题。 - Georgy
4个回答

61

尽管 eguaio 的答案可以胜任,但使用 shapely.ops.nearest_points 函数可以更自然地获取最接近的点:

from shapely.geometry import Point, Polygon
from shapely.ops import nearest_points

poly = Polygon([(0, 0), (2, 8), (14, 10), (6, 1)])
point = Point(12, 4)
# The points are returned in the same order as the input geometries:
p1, p2 = nearest_points(poly, point)
print(p1.wkt)
# POINT (10.13793103448276 5.655172413793103)

结果与其他答案相同:

from shapely.geometry import LinearRing
pol_ext = LinearRing(poly.exterior.coords)
d = pol_ext.project(point)
p = pol_ext.interpolate(d)
print(p.wkt)
# POINT (10.13793103448276 5.655172413793103)
print(p.equals(p1))
# True

2
现在这应该是正确的答案了。当我写原始答案时,这个函数还没有可用。看来我现在应该重新阅读库文档了。 - eguaio
1
我应该更仔细地阅读文档!@Georgy感谢您的贡献。 - eguaio
4
如果您的点在多边形内部,您可以使用以下代码:p1, p2 = nearest_points(poly.boundary, point) - Nils
1
@ZeeshanEqbal 这应该能回答你的问题:查找点和多边形之间最长的“直线”路径 - Georgy
1
注意:如果点在多边形内部,nearest_points 将简单地返回该点的值。将 nearest_points 应用于多边形的边界 (poly.boundary) 似乎无论点是内部还是外部都可以工作。 - SoHei
显示剩余4条评论

35

请不要给这个答案点赞,正确的答案在下面的@Georgy答案中。

我的回答供参考:

有一种简单的方法可以依靠Shapely函数完成此操作。首先,您需要获取多边形的外环,并将点投影到环上。必须将外部作为LinearRing获取,因为多边形没有投影函数。与直觉相反,这会给出一个距离,即环的第一个点到最靠近给定点的环中点的距离。然后,您只需使用该距离使用插值函数获得点。请参见下面的代码。

from shapely.geometry import Polygon, Point, LinearRing

poly = Polygon([(0, 0), (2,8), (14, 10), (6, 1)])
point = Point(12, 4)

pol_ext = LinearRing(poly.exterior.coords)
d = pol_ext.project(point)
p = pol_ext.interpolate(d)
closest_point_coords = list(p.coords)[0]

需要说明的是,这种方法只适用于您知道点位于多边形外部。如果点在其内部环之一中,则需要针对该情况修改代码。

如果多边形没有内部环,则即使点在多边形内部,该代码也可以运行。这是因为实际上我们正在使用外部环作为线串,并忽略线串是否来自多边形。

很容易将此代码扩展到计算任何点(在多边形内部或外部)到多边形边界最近点的一般情况。您只需要计算点到所有线环(外环和多边形的每个内环)的最近点(和距离),然后仅保留其中的最小值。

enter image description here


这太完美了。我之前不熟悉那些Shapely函数。如果外部点是一个多边形,这个方法也能用吗?我试过对多边形和线串都使用pol_ext.project(),但是出现了错误信息“GEOSProject_r的第三个参数必须是Point*”。你有什么建议吗? - AJG519
我不知道。我认为你别无选择,只能自己实现一些东西。Tome Karzes的答案可以很容易地适应这种情况(但使用其中一个多边形作为“点”,因为你已经有了上述方法)。 - eguaio
在问题的答案http://stackoverflow.com/questions/38514607/find-shortest-path-from-one-geometry-to-other-on-shapely/38997756#38997756中,您可以找到Tom Karze建议的算法的实现,以获取两个不交叉linestrings之间的距离。那里的代码可以很容易地适应于获取linestring和point之间的距离,并且不依赖于shapely函数。 - eguaio
谢谢,这很有帮助。您能否详细说明一下为什么当点在多边形内部时它不起作用?我用不同的点运行了几次此代码,结果“看起来”是正确的。 - xandermonkey
当然,我会完成回答。我假设你的多边形没有内部环,那么这段代码确实可以工作。 - eguaio

0

我喜欢将多边形 poly 与圆心为点 point 的圆形 buff 相交的想法,就像你在问题中写的那样。 我建议使用以下代码:

poly.boundary.intersection(buff.boundary)

0
有两种情况要考虑:(1)最近点在一条边上,(2)最近点是一个顶点。情况(2)很容易检查-只需计算到每个顶点的距离并找到最小值。情况(1)涉及更多的数学知识,但仍然不太难。您需要为情况(1)做两件事:(a)找到从该点到边缘的法线与边相交的位置,以及(b)验证它是否位于线段内(而不是延伸到端点之一)。如果它不在线段上,请忽略它(该边上的一个顶点将是最接近的那个点)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接