【问题标题】:Find overlaps between many LineStrings查找许多 LineStrings 之间的重叠
【发布时间】:2021-11-26 11:01:39
【问题描述】:

我有一长串 shapely.geometry.LineStrings 部分重叠(准确地说,它们是德国高速公路网络上的行驶路线)。每个 LineString 都有一个关联的值(在我的例子中是延迟和走那条路线的汽车数量)。我的目标是找到这些不同的LineStrings 之间的重叠部分,并将它们对应的值相加。最终结果应该类似于下图所示:

我目前的方法大致如下(代码在帖子末尾):

  • 维护已检查路线的列表
  • 对于每条新路线:检查新路线和已检查的路线之间是否有重叠
  • 如果是,则将组合值分配给重叠部分并仅对剩余的非重叠部分继续检查

这种方法有效并产生了预期的结果。然而,问题在于,如果要检查的路由数量非常多,算法的运行时间就会变得过长。原因是越来越多的 LineStrings 必须检查交叉点。是否有人知道可用于解决此问题的现有算法、程序包等?或者您对如何加速算法有好的建议?

在代码中,实现如下(诚然尚未完善):

def intersects_rectangles(bounds, other_bounds):
    return not (bounds[2] < other_bounds[0] or bounds[0] > other_bounds[2] or bounds[3] < other_bounds[1] or bounds[1] > other_bounds[3])

def main_function(route_df) -> Dict[tuple, List[Union[LineString, float]]]:
    # The index of route_df contains ids that lead to files that contain the LineStrings
    # The columns contain the relevant values associated with each route
    table_merged: Dict[tuple, List[Union[LineString, float]]] = {}
    routes_covered = 0
    tot_routes = len(route_df)
    print(f'Creating a merged view of all routes. Nr. routes: {tot_routes}')
    for (route_name, car_name), line in route_df.iterrows():
        with open('buffer_data/' + route_name + '/' + BufferFileHierarchy.route.value, 'rb') as f:
            linestring: LineString
            linestring, _ = pickle.load(f)
        current_cum_delay = line['sum']
        current_count = line['count']
        if len(table_merged) == 0:
            table_merged[(route_name, )] = [linestring, linestring.buffer(0.001).buffer(0), current_cum_delay, current_count] # The buffer is necessary to also include LineStrings describing the opposite side of the road
            continue
        for other_contained_routes in list(table_merged.keys()):
            [other_linestring, other_linestring_buffer, other_cum_delay, other_cum_count] = table_merged[other_contained_routes]
            if route_name in other_contained_routes:
                continue
            seg_intersects = linestring.intersection(other_linestring_buffer)
            if seg_intersects.is_empty:
                continue
            if not intersects_rectangles(linestring.bounds, other_linestring.bounds):
                continue
            if seg_intersects.length > 0.0002:
                seg_intersects_buffer = seg_intersects.buffer(0.001).buffer(0)
                linestring_remainder = linestring.difference(seg_intersects_buffer)
                other_linestring_remainder = other_linestring.difference(seg_intersects_buffer)
                table_merged[(*other_contained_routes, route_name)] = [seg_intersects, seg_intersects_buffer, current_cum_delay + other_cum_delay, current_count + other_cum_count]
                if other_linestring_remainder.is_empty:
                    del table_merged[other_contained_routes]
                else:
                    table_merged[other_contained_routes] = [other_linestring_remainder, other_linestring_remainder.buffer(0.001).buffer(0), other_cum_delay, other_cum_count]
                linestring = linestring_remainder
                if linestring.is_empty:
                    break
        if not linestring.is_empty:
            table_merged[(route_name, )] = [linestring, linestring.buffer(0.001).buffer(0), current_cum_delay, current_count]
        routes_covered += 1
        if routes_covered % 100 == 0:
            progress_bar.print_progress_bar(routes_covered, tot_routes)
    progress_bar.print_progress_bar(routes_covered, tot_routes)
    return table_merged

【问题讨论】:

    标签: python gis shapely


    【解决方案1】:

    我遇到了同样的问题。

    我不知道你是否可以加快算法。但是您可以使用 osm2po 获得德国高速公路系统的图表。这样,您可以通过计算每条路线与每条图边的交叉点来更快地完成相同的工作。

    例如:

    import geopandas as gpd
    
    graph.geometry= graph.geometry.buffer(0.001) # Add some leeway for intersections
    graph['nCars'] = gpd.sjoin(graph, routes, op='intersects').value_counts('edge_id')
    

    graph 是一个填充了高速公路边缘的 geopandas 数据框。

    routes 是一个包含所有驱动路线的 geopandas 数据框。

    【讨论】:

    • 感谢您的评论。我实际上最终做了类似的事情,但只是选择了所有 OSM 对象 ID,因为这些通常只覆盖交叉点之间的延伸。然后,您可以创建一个带有 OSM id 和路由的大型二进制矩阵,以指示哪个路由沿着哪个 OSM id。它不像我正在寻找的那样灵活,所以我不会将问题标记为已回答,但给予了支持
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-29
    • 2014-11-07
    • 1970-01-01
    • 2021-01-09
    • 1970-01-01
    • 2020-02-19
    相关资源
    最近更新 更多