如何在 Shapely 中找到 LineString 的第二个最近点
How to find the 2nd nearest point of a LineString in Shapely
给定某LineString
和点p
:
from shapely.ops import nearest_points
from shapely.geometry import Point
p = Point(51.21745162000732, 4.41871738126533)
linestring = LineString([(51.2176008, 4.4177154), (51.21758, 4.4178548), (51.2175729, 4.4179023), (51.21745162000732, 4.41871738126533)])
离p
最近的点的计算公式为:
n_p = nearest_points(linestring, p)[0]
结论是完全相同的点,这是正常的,因为线串中也有完全相同的值,但我需要知道最近的点,除了点本身。
那么如何找到秒最近的点呢?
解决如下。
from shapely.ops import nearest_points
from shapely.geometry import Point
from shapely.geometry import LineString
def second_nearest(p, linestring):
""" Finds nearest point of p in linestring
if p in linestring, finds second nearest"""
# coordinates of p and linestring
p_coords = list(p.coords)[0]
linestring_coords = list(linestring.coords)
if p_coords in linestring_coords:
# form a new linestring if p is in linestring
linestring_coords.remove(p_coords)
linestring = LineString(linestring_coords)
return nearest_points(p, linestring)
p = Point(51.21745162000732, 4.41871738126533)
linestring = LineString([(51.2176008,4.4177154), (51.21758,4.4178548), (51.2175729,4.4179023), (51.21745162000732,4.41871738126533)])
n_p = second_nearest(p, linestring)
print(list(map(str, n_p)))
输出
第一个点是p,第二个点是线流中最接近p的点不等于p(所以第二个最接近的点)
['POINT (51.21745162000732 4.41871738126533)',
'POINT (51.2175729 4.4179023)']
在一般情况下,最简单的解决方案是从您的 LineString
构造一个新的几何对象,但没有最近点,然后用这个新几何获得最近点。:
from shapely.geometry import LineString, MultiPoint, Point
from shapely.ops import nearest_points
point = Point(51.21745162000732, 4.41871738126533)
line = LineString([(51.2176008, 4.4177154), (51.21758, 4.4178548),
(51.2175729, 4.4179023), (51.21745162000732, 4.41871738126533)])
nearest_point = nearest_points(line, point)[0]
line_points_except_nearest = MultiPoint([point for point in linestring.coords
if point != (nearest_point.x, nearest_point.y)])
second_nearest = nearest_points(line_points_except_nearest, point)[0]
或者,如果您不想构造一个新对象,例如,由于内存限制,您可以 运行 在 LineString
中的所有点上使用 heapq.nsmallest
:
import heapq
line_points = map(Point, line.coords)
nearest, second_nearest = heapq.nsmallest(2, line_points, key=point.distance)
在你的具体情况下,当所有点共线时,你还可以计算与最近点的相邻点的距离:
index = list(line.coords).index((point.x, point.y))
if index == 0:
second_nearest = Point(line.coords[1])
elif index == len(line.coords) - 1:
second_nearest = Point(line.coords[-2])
else:
second_nearest = min(Point(line.coords[index - 1]),
Point(line.coords[index + 1]),
key=point.distance)
给定某LineString
和点p
:
from shapely.ops import nearest_points
from shapely.geometry import Point
p = Point(51.21745162000732, 4.41871738126533)
linestring = LineString([(51.2176008, 4.4177154), (51.21758, 4.4178548), (51.2175729, 4.4179023), (51.21745162000732, 4.41871738126533)])
离p
最近的点的计算公式为:
n_p = nearest_points(linestring, p)[0]
结论是完全相同的点,这是正常的,因为线串中也有完全相同的值,但我需要知道最近的点,除了点本身。 那么如何找到秒最近的点呢?
解决如下。
from shapely.ops import nearest_points
from shapely.geometry import Point
from shapely.geometry import LineString
def second_nearest(p, linestring):
""" Finds nearest point of p in linestring
if p in linestring, finds second nearest"""
# coordinates of p and linestring
p_coords = list(p.coords)[0]
linestring_coords = list(linestring.coords)
if p_coords in linestring_coords:
# form a new linestring if p is in linestring
linestring_coords.remove(p_coords)
linestring = LineString(linestring_coords)
return nearest_points(p, linestring)
p = Point(51.21745162000732, 4.41871738126533)
linestring = LineString([(51.2176008,4.4177154), (51.21758,4.4178548), (51.2175729,4.4179023), (51.21745162000732,4.41871738126533)])
n_p = second_nearest(p, linestring)
print(list(map(str, n_p)))
输出
第一个点是p,第二个点是线流中最接近p的点不等于p(所以第二个最接近的点)
['POINT (51.21745162000732 4.41871738126533)',
'POINT (51.2175729 4.4179023)']
在一般情况下,最简单的解决方案是从您的 LineString
构造一个新的几何对象,但没有最近点,然后用这个新几何获得最近点。:
from shapely.geometry import LineString, MultiPoint, Point
from shapely.ops import nearest_points
point = Point(51.21745162000732, 4.41871738126533)
line = LineString([(51.2176008, 4.4177154), (51.21758, 4.4178548),
(51.2175729, 4.4179023), (51.21745162000732, 4.41871738126533)])
nearest_point = nearest_points(line, point)[0]
line_points_except_nearest = MultiPoint([point for point in linestring.coords
if point != (nearest_point.x, nearest_point.y)])
second_nearest = nearest_points(line_points_except_nearest, point)[0]
或者,如果您不想构造一个新对象,例如,由于内存限制,您可以 运行 在 LineString
中的所有点上使用 heapq.nsmallest
:
import heapq
line_points = map(Point, line.coords)
nearest, second_nearest = heapq.nsmallest(2, line_points, key=point.distance)
在你的具体情况下,当所有点共线时,你还可以计算与最近点的相邻点的距离:
index = list(line.coords).index((point.x, point.y))
if index == 0:
second_nearest = Point(line.coords[1])
elif index == len(line.coords) - 1:
second_nearest = Point(line.coords[-2])
else:
second_nearest = min(Point(line.coords[index - 1]),
Point(line.coords[index + 1]),
key=point.distance)