【问题标题】:Shortest path between many 2D points (travelling salesman within Shapely LineString?)许多 2D 点之间的最短路径(Shapely LineString 中的旅行推销员?)
【发布时间】:2017-05-21 01:35:09
【问题描述】:

我试图根据点地面测量创建河流横截面剖面。当尝试从具有公共 ID 的一系列点创建 Shapely LineString 时,我意识到给定点的顺序确实很重要,因为 LineString 只会将给定点“按索引”连接(连接点在列表给定的顺序)。下面的代码说明了默认行为:

from shapely.geometry import Point, LineString
import geopandas as gpd
import numpy as np
import matplotlib.pyplot as plt

# Generate random points
x=np.random.randint(0,100,10)
y=np.random.randint(0,50,10)
data = zip(x,y)

# Create Point and default LineString GeoSeries
gdf_point = gpd.GeoSeries([Point(j,k) for j,k in data])
gdf_line = gpd.GeoSeries(LineString(zip(x,y)))

# plot the points and "default" LineString
ax = gdf_line.plot(color='red')
gdf_point.plot(marker='*', color='green', markersize=5,ax=ax)

这将产生图像:

问题: Shapely 中是否有任何内置方法可以自动创建最合乎逻辑的(又名:最短、最不复杂、最不交叉,...) 穿过给定的随机二维点列表?

您可以在下面找到与默认行(红色)相比所需的行(绿色)。

【问题讨论】:

  • 假设您事先不知道顺序或邻居,您可以尝试构建一个将每个节点连接到每个其他节点的图,然后搜索“简单路径”并选择带有与节点数相同的步数,然后选择其中最短的?这将需要 networkX 中的 all_simple_paths 之类的东西。
  • 哇,看起来很有希望!将对此进行调查。
  • 小修正:路径长度为节点 - 1

标签: python shapely geopandas multilinestring


【解决方案1】:

这就是解决我的横截面LineString 简化问题的方法。但是,我的解决方案没有正确解决计算上更复杂的任务,即找到通过给定点的最终最短路径。正如评论者所建议的那样,有许多库和脚本可用于解决该特定问题,但如果有人想保持简单,您可以使用对我有用的方法。随意使用和评论!

def simplify_LineString(linestring):

    '''
    Function reorders LineString vertices in a way that they each vertix is followed by the nearest remaining vertix.
    Caution: This doesn't calculate the shortest possible path (travelling postman problem!) This function performs badly
    on very random points since it doesn't see the bigger picture.
    It is tested only with the positive cartesic coordinates. Feel free to upgrade and share a better function!

    Input must be Shapely LineString and function returns Shapely Linestring.

    '''

    from shapely.geometry import Point, LineString
    import math

    if not isinstance(linestring,LineString):
        raise IOError("Argument must be a LineString object!")

    #create a point lit
    points_list = list(linestring.coords)

    ####
    # DECIDE WHICH POINT TO START WITH - THE WESTMOST OR SOUTHMOST? (IT DEPENDS ON GENERAL DIRECTION OF ALL POINTS)
    ####
    points_we = sorted(points_list, key=lambda x: x[0])
    points_sn = sorted(points_list, key=lambda x: x[1])

    # calculate the the azimuth of general diretction
    westmost_point = points_we[0]
    eastmost_point = points_we[-1]

    deltay = eastmost_point[1] - westmost_point[1]
    deltax = eastmost_point[0] - westmost_point[0]

    alfa = math.degrees(math.atan2(deltay, deltax))
    azimut = (90 - alfa) % 360

    if (azimut > 45 and azimut < 135):
        #General direction is west-east
        points_list = points_we
    else:
        #general direction is south-north
        points_list = points_sn

    ####
    # ITERATIVELY FIND THE NEAREST VERTIX FOR THE EACH REMAINING VERTEX
    ####

    # Create a new, ordered points list, starting with the east or southmost point.
    ordered_points_list = points_list[:1]

    for iteration in range(0, len(points_list[1:])):

        current_point = ordered_points_list[-1]  # current point that we are looking the nearest neighour to
        possible_candidates = [i for i in points_list if i not in ordered_points_list]  # remaining (not yet sortet) points

        distance = 10000000000000000000000
        best_candidate = None
        for candidate in possible_candidates:
            current_distance = Point(current_point).distance(Point(candidate))
            if current_distance < distance:
                best_candidate = candidate
                distance = current_distance

        ordered_points_list.append(best_candidate)

    return LineString(ordered_points_list)

【讨论】:

  • 在末尾添加一个if ordered_point_list[-1] is None: ordered_point_list.pop() 应该允许它通过return type(linestring)(ordered_points_list) 处理LinearRings。
【解决方案2】:

没有内置函数,但 shapely 有一个distance 函数。

您可以轻松地遍历这些点并计算它们之间的最短距离并构建“最短”路径。

官方 github 仓库中有一些 examples

【讨论】:

  • 我自己已经做了一个类似的函数,但它只从最西或最南的点开始,并迭代地为每个剩余点找到最近的邻居。但这实际上并不意味着最短的路径。如果我想出一个体面的解决方案,我会发布更多。无论如何,谢谢!
【解决方案3】:

Google 的 OR-Tools 提供了一种解决旅行推销员问题的好方法:https://developers.google.com/optimization/routing/tsp

遵循他们网站上的教程将为您提供解决方案(基于您的示例代码):

到这里:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-07
    • 2011-09-08
    • 1970-01-01
    • 2014-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-22
    相关资源
    最近更新 更多