在多个点打断一个匀称的线串
Break a shapely Linestring at multiple points
下面的代码是根据我发现的 here 的代码修改而来的,该代码在沿线定义的点处将形状优美的线串分成两段。我还检查了其他问题,但它们没有直接解决我的查询。但是我想扩展它以将线分成多个段(在多个点),到目前为止我所做的所有尝试都失败了。如何修改以将字符串拆分为任意给定数量的段或在多个点((4,5),(9,18)和(6,5))。
input:
line = LineString([(1,2),(8,7),(4,5),(2,4),(4,7),(8,5),(9,18),(1,2),(12,7),(4,5),(6,5),(4,9)])
breakPoint = Point(2,4)
from shapely.geometry import Point,LineString
def make_line_segment(line_string, breakPoint):
geoLoc = line_string.coords
j = None
for i in range(len(geoLoc) - 1):
if LineString(geoLoc[i:i + 2]).intersects(breakPoint):
j = i
break
assert j is not None
# Make sure to always include the point in the first group
if Point(geoLoc[j + 1:j + 2]).equals(breakPoint):
return geoLoc[:j + 2], geoLoc[j + 1:]
else:
return geoLoc[:j + 1], geoLoc[j:]
line1,line2 = make_line_segment(line,breakPoint)
line1 = LineString(line1)
line2 = LineString(line2)
print line1, line2
output: `LINESTRING (1 2, 8 7, 4 5, 2 4) LINESTRING (2 4, 4 7, 8 5, 9 18, 1 2, 12 7, 4 5, 6 5, 4 9)`
projection
和 interpolate
lineString 方法通常对这种操作很方便。
from shapely.geometry import Point, LineString
def cut(line, distance):
# Cuts a line in two at a distance from its starting point
# This is taken from shapely manual
if distance <= 0.0 or distance >= line.length:
return [LineString(line)]
coords = list(line.coords)
for i, p in enumerate(coords):
pd = line.project(Point(p))
if pd == distance:
return [
LineString(coords[:i+1]),
LineString(coords[i:])]
if pd > distance:
cp = line.interpolate(distance)
return [
LineString(coords[:i] + [(cp.x, cp.y)]),
LineString([(cp.x, cp.y)] + coords[i:])]
def split_line_with_points(line, points):
"""Splits a line string in several segments considering a list of points.
The points used to cut the line are assumed to be in the line string
and given in the order of appearance they have in the line string.
>>> line = LineString( [(1,2), (8,7), (4,5), (2,4), (4,7), (8,5), (9,18),
... (1,2),(12,7),(4,5),(6,5),(4,9)] )
>>> points = [Point(2,4), Point(9,18), Point(6,5)]
>>> [str(s) for s in split_line_with_points(line, points)]
['LINESTRING (1 2, 8 7, 4 5, 2 4)', 'LINESTRING (2 4, 4 7, 8 5, 9 18)', 'LINESTRING (9 18, 1 2, 12 7, 4 5, 6 5)', 'LINESTRING (6 5, 4 9)']
"""
segments = []
current_line = line
for p in points:
d = current_line.project(p)
seg, current_line = cut(current_line, d)
segments.append(seg)
segments.append(current_line)
return segments
if __name__ == "__main__":
import doctest
doctest.testmod()
在这种方法中,首先我在开头拆分点列表并形成线列表,如下所示,
# List of coordinates
coords = [(1,2),(8,7),(4,5),(2,4),(4,7),(8,5),(9,18),(1,2),(12,7),(4,5),(6,5),(4,9)]
no_seg = 3 #Number of segments, you need from 'coords'
coords_sub = np.array_split(coords, no_seg)
list_lines = [] # empty list
for i in range(len(X_sub)):
list_lines.append(LineString(X_sub[i]))
list_lines[1] # Displays the second line of the list
下面的代码是根据我发现的 here 的代码修改而来的,该代码在沿线定义的点处将形状优美的线串分成两段。我还检查了其他问题,但它们没有直接解决我的查询。但是我想扩展它以将线分成多个段(在多个点),到目前为止我所做的所有尝试都失败了。如何修改以将字符串拆分为任意给定数量的段或在多个点((4,5),(9,18)和(6,5))。
input:
line = LineString([(1,2),(8,7),(4,5),(2,4),(4,7),(8,5),(9,18),(1,2),(12,7),(4,5),(6,5),(4,9)])
breakPoint = Point(2,4)
from shapely.geometry import Point,LineString
def make_line_segment(line_string, breakPoint):
geoLoc = line_string.coords
j = None
for i in range(len(geoLoc) - 1):
if LineString(geoLoc[i:i + 2]).intersects(breakPoint):
j = i
break
assert j is not None
# Make sure to always include the point in the first group
if Point(geoLoc[j + 1:j + 2]).equals(breakPoint):
return geoLoc[:j + 2], geoLoc[j + 1:]
else:
return geoLoc[:j + 1], geoLoc[j:]
line1,line2 = make_line_segment(line,breakPoint)
line1 = LineString(line1)
line2 = LineString(line2)
print line1, line2
output: `LINESTRING (1 2, 8 7, 4 5, 2 4) LINESTRING (2 4, 4 7, 8 5, 9 18, 1 2, 12 7, 4 5, 6 5, 4 9)`
projection
和 interpolate
lineString 方法通常对这种操作很方便。
from shapely.geometry import Point, LineString
def cut(line, distance):
# Cuts a line in two at a distance from its starting point
# This is taken from shapely manual
if distance <= 0.0 or distance >= line.length:
return [LineString(line)]
coords = list(line.coords)
for i, p in enumerate(coords):
pd = line.project(Point(p))
if pd == distance:
return [
LineString(coords[:i+1]),
LineString(coords[i:])]
if pd > distance:
cp = line.interpolate(distance)
return [
LineString(coords[:i] + [(cp.x, cp.y)]),
LineString([(cp.x, cp.y)] + coords[i:])]
def split_line_with_points(line, points):
"""Splits a line string in several segments considering a list of points.
The points used to cut the line are assumed to be in the line string
and given in the order of appearance they have in the line string.
>>> line = LineString( [(1,2), (8,7), (4,5), (2,4), (4,7), (8,5), (9,18),
... (1,2),(12,7),(4,5),(6,5),(4,9)] )
>>> points = [Point(2,4), Point(9,18), Point(6,5)]
>>> [str(s) for s in split_line_with_points(line, points)]
['LINESTRING (1 2, 8 7, 4 5, 2 4)', 'LINESTRING (2 4, 4 7, 8 5, 9 18)', 'LINESTRING (9 18, 1 2, 12 7, 4 5, 6 5)', 'LINESTRING (6 5, 4 9)']
"""
segments = []
current_line = line
for p in points:
d = current_line.project(p)
seg, current_line = cut(current_line, d)
segments.append(seg)
segments.append(current_line)
return segments
if __name__ == "__main__":
import doctest
doctest.testmod()
在这种方法中,首先我在开头拆分点列表并形成线列表,如下所示,
# List of coordinates
coords = [(1,2),(8,7),(4,5),(2,4),(4,7),(8,5),(9,18),(1,2),(12,7),(4,5),(6,5),(4,9)]
no_seg = 3 #Number of segments, you need from 'coords'
coords_sub = np.array_split(coords, no_seg)
list_lines = [] # empty list
for i in range(len(X_sub)):
list_lines.append(LineString(X_sub[i]))
list_lines[1] # Displays the second line of the list