我有以下问题:我有一条路线(作为 LineString,从 A 到 B)。该路线经过点C1附近。我想知道从 A 点到 C1 点的路径有多长(见图)。在 JS-Package 中,有一个函数 nearest-point-on-line 正是这样做的(它也计算直线上的长度)。但是Python中有类似的东西吗?
这是我尝试过的两次尝试。
在 = C2 线上找到 C1 的下一个点。然后通过将 LineString 与点 C2 相交来生成新的 LineString。这条新线的长度是线上 A 和 C2 之间的长度。
from shapely.ops import nearest_points, split
# Snap to line
c2 = nearest_points(line, c1)[0]
# Split line at point
splitted_line = split(line, c2)
该线永远不会被切断,因为 c2 不在线上,即使它已被折断。它们相差几位小数。
在此变体中,我尝试将 LineString 与第二条线相交。与之前一样,搜索到 C1 的直线上的下一个点 (=C2)。现在我从 C1 和 C2 生成一个 LineString。我将这个 LineString 在 C2 方向上增加一个固定值。然后路线与新的 LineString 相交。
import cmath
import geopandas as gpd
from shapely.ops import nearest_points, split, LineString
# This function expands the line in given direction.
def expandLineInDirection(x1, y1, x2, y2, dist):
# calculate the x,y change between the points
difference = complex(x2,y2) - complex(x1,y1)
# convert the difference to polar coordinates
(distance, angle) = cmath.polar(difference)
#calculate a new x,y change based on the angle and desired distance
displacement = cmath.rect(dist, angle)
# add the displacement to the start and end point
xy3 = displacement + complex(x2,y2)
x3 = xy3.real
y3 = xy3.imag
return (x3, y3)
# This function will split the line with a line that is build with two points and extended
def getLineLengthFromPointOnLine(line, p1, p2):
# p1 = unsnapped
# p2 = snapped
# p3 = will be calculated. Expand the line so that it cross the original line on all cases
cuttingLine = LineString([p1, expandLineInDirection(p1.x, p1.y, p2.x, p2.y, 2)])
result = split(line, cuttingLine)
if len(result.geoms) < 2:
#print("Split hat nicht funktioniert, nicht zwei Linien")
return -1
return result.geoms[0].length
point_length = getLineLengthFromPointOnLine(line, c1, c2)
这在大多数情况下都有效——但并非总是如此。 在极少数情况下,新线可能不与 LineString 相交(见图)。
有没有更简单的方法来解决这个问题?
尝试沿着各个线段寻找最近的点,并使用匹配点来指示分割位置。
import shapely as shp
import itertools as it
line_coords = [[0, 0], [0, -2], [5, -2], [7, -4]]
line = shp.LineString(line_coords)
pt = shp.Point(4, -1)
closest_pt = shp.ops.nearest_points(line, pt)[0]
segments = [shp.LineString([a,b]) for a,b in it.pairwise(line_coords)]
closest_segment_pts = [shp.ops.nearest_points(seg, pt)[0] for seg in segments]
match = closest_segment_pts.index(closest_pt[0])
split_line = shp.LineString(line_coords[0:match+2])