Shapely中两个几何体最近点的坐标
有一条折线,它的顶点坐标列表是 = [(x1,y1), (x2,y2), (x3,y3),...],还有一个点(x,y)。在Shapely这个库里,geometry1.distance(geometry2)
可以用来计算这两个几何形状之间的最短距离。
>>> from shapely.geometry import LineString, Point
>>> line = LineString([(0, 0), (5, 7), (12, 6)]) # geometry2
>>> list(line.coords)
[(0.0, 0.0), (5.0, 7.0), (12.0, 6.0)]
>>> p = Point(4,8) # geometry1
>>> list(p.coords)
[(4.0, 8.0)]
>>> p.distance(line)
1.4142135623730951
但是我还需要找到在这条线上的一个点,这个点离(x,y)最近。在上面的例子中,这个点就是在LineString
对象上,距离Point(4,8)
有1.4142135623730951单位远的那个点。这个distance()
方法在计算距离的时候应该能返回这个点的坐标。有没有办法让这个方法返回这个坐标呢?
2 个回答
3
如果你只有一个段落(比如说一条线,正如标题所提到的),而不是一系列段落,这里有我做的事情,还有一个简单的测试案例。请注意,这个页面上的一些用户可能只是想要这个内容,因为他们是通过谷歌搜索找到这个标题的。
Python代码:
def sq_shortest_dist_to_point(self, other_point):
dx = self.b.x - self.a.x
dy = self.b.y - self.a.y
dr2 = float(dx ** 2 + dy ** 2)
lerp = ((other_point.x - self.a.x) * dx + (other_point.y - self.a.y) * dy) / dr2
if lerp < 0:
lerp = 0
elif lerp > 1:
lerp = 1
x = lerp * dx + self.a.x
y = lerp * dy + self.a.y
_dx = x - other_point.x
_dy = y - other_point.y
square_dist = _dx ** 2 + _dy ** 2
return square_dist
def shortest_dist_to_point(self, other_point):
return math.sqrt(self.sq_shortest_dist_to_point(other_point))
一个测试案例:
def test_distance_to_other_point(self):
# Parametrize test with multiple cases:
segments_and_point_and_answer = [
[Segment(Point(1.0, 1.0), Point(1.0, 3.0)), Point(2.0, 4.0), math.sqrt(2.0)],
[Segment(Point(1.0, 1.0), Point(1.0, 3.0)), Point(2.0, 3.0), 1.0],
[Segment(Point(0.0, 0.0), Point(0.0, 3.0)), Point(1.0, 1.0), 1.0],
[Segment(Point(1.0, 1.0), Point(3.0, 3.0)), Point(2.0, 2.0), 0.0],
[Segment(Point(-1.0, -1.0), Point(3.0, 3.0)), Point(2.0, 2.0), 0.0],
[Segment(Point(1.0, 1.0), Point(1.0, 3.0)), Point(2.0, 3.0), 1.0],
[Segment(Point(1.0, 1.0), Point(1.0, 3.0)), Point(2.0, 4.0), math.sqrt(2.0)],
[Segment(Point(1.0, 1.0), Point(-3.0, -3.0)), Point(-3.0, -4.0), 1],
[Segment(Point(1.0, 1.0), Point(-3.0, -3.0)), Point(-4.0, -3.0), 1],
[Segment(Point(1.0, 1.0), Point(-3.0, -3.0)), Point(1, 2), 1],
[Segment(Point(1.0, 1.0), Point(-3.0, -3.0)), Point(2, 1), 1],
[Segment(Point(1.0, 1.0), Point(-3.0, -3.0)), Point(-3, -1), math.sqrt(2.0)],
[Segment(Point(1.0, 1.0), Point(-3.0, -3.0)), Point(-1, -3), math.sqrt(2.0)],
[Segment(Point(-1.0, -1.0), Point(3.0, 3.0)), Point(3, 1), math.sqrt(2.0)],
[Segment(Point(-1.0, -1.0), Point(3.0, 3.0)), Point(1, 3), math.sqrt(2.0)],
[Segment(Point(1.0, 1.0), Point(3.0, 3.0)), Point(3, 1), math.sqrt(2.0)],
[Segment(Point(1.0, 1.0), Point(3.0, 3.0)), Point(1, 3), math.sqrt(2.0)]
]
for i, (segment, point, answer) in enumerate(segments_and_point_and_answer):
result = segment.shortest_dist_to_point(point)
self.assertAlmostEqual(result, answer, delta=0.001, msg=str((i, segment, point, answer)))
注意:我假设这个函数是在一个 Segment
类里面。如果你的线是无限的,不要只把 lerp
限制在0到1之间,但至少要提供两个不同的 a
和 b
点。
65
你提到的GIS术语叫做线性定位,而Shapely库里有这些方法。
# Length along line that is closest to the point
print(line.project(p))
# Now combine with interpolated point on line
p2 = line.interpolate(line.project(p))
print(p2) # POINT (5 7)
另一种方法是使用nearest_points
:
from shapely.ops import nearest_points
p2 = nearest_points(line, p)[0]
print(p2) # POINT (5 7)
这个方法和线性定位技术得到的结果是一样的,但它可以从更复杂的几何形状中找出最近的两个点,比如两个多边形。