【问题标题】:Speed up shapely buffer加速匀速缓冲
【发布时间】:2019-09-02 08:38:22
【问题描述】:

我有不同的shapely.LineStrings,如下所示:

然后我 buffer 创建一个多边形,如下所示:

我玩了一会儿,发现缓冲每个线段稍微unary_union-ing 所有线串然后将整个东西缓冲在一起要快。但是,我确实需要缓冲线的总面积作为一个匀称的多边形,因为我稍后将它用于交叉点检测。所以我最终不得不unary_union缓冲的多边形来获得整个多边形,这需要一些时间(不是针对这个特定示例,而是针对其他具有更多绿线的示例)。

那么有没有更快的方法来获取我不知道的缓冲多边形?

这是一个可重现的例子:

import numpy as np
from shapely.geometry import MultiLineString, LineString, Polygon
from shapely import ops, affinity
import matplotlib.pyplot as plt
from math import atan2, degrees
from descartes.patch import PolygonPatch

if __name__ == '__main__':
    Coords = np.array([
        [0, 0, 0, 0, 'N', 0, 0],
        [0, 1, 0, 'BRANCH', 'N', 0, 0],
        [0, 0, 0, 'BRANCH', 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0],
        [-0.85, -0.51, 0, 'BRANCH', 'Y', 45, 0],
        [-0.85, -0.51, 0, 'NODE', 'Y', 45, 0],
        [-1.71, -1.03, 0, 0, 'Y', 45, 0],
        [-1.66, -2.02, 0, 'BRANCH', 'Y', 45, 0],
        [-1.66, -2.02, 0, 'NODE', 'Y', 45, 0],
        [-1.60, -3.02, 0, 'BRANCH', 'Y', 45, 0],
        [0, 0, 0, 0, 0, 0, 0],
        [0.90, -0.42, 0, 'BRANCH', 'Y', 45, 0],
        [0.90, -0.42, 0, 'NODE', 'Y', 45, 0],
        [1.81, -0.84, 0, 'BRANCH', 'Y', 45, 0],
        [0, 0, 0, 'BRANCH', 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0],
        [0.10, -0.99, 0, 0, 'Y', 45, 0],
        [-0.69, -1.59, 0, 0, 'Y', 45, 0],
        [-0.53, -2.58, 0, 'BRANCH', 'Y', 45, 0],
        [-0.53, -2.58, 0, 'NODE', 'Y', 45, 0],
    ], dtype=object)

    for ind, coord in enumerate(Coords):
        if coord[3] == 'BRANCH':
            if (coord[0:3] == Coords[ind + 1, 0:3]).all():
                np.delete(Coords, ind, 0)

    lines = []

    j = 0
    for i in range(len(Coords)):
        if (Coords[i, 3] == 'BRANCH') or (i == (len(Coords) - 1)):
            lines.append(Coords[j:i+1].tolist())
            j = i+1

    if not lines:
        Lines = [Coords[:]]
    else:
        Lines = [line for line in lines if len(line) > 1]

    fig, ax = plt.subplots()

    patches = []
    lines = []
    Vs = []
    all_r_lines = []
    texts = []


    for num, line in enumerate(Lines):
        line = np.asarray(line, dtype=object)
        num_coords = line[:, 0:2]
        cumm = 0

        indi_coords = []

        for i, joint in enumerate(line):

            if joint[4] == 'Y' and joint[3] != 'BRANCH':

                """ --------------- BODY -------------------------------- """
                indi_coords.append((joint[0], joint[1]))

                new_coords = ((line[i+1][0]), (line[i+1][1]))
                angle = degrees(atan2(
                    (new_coords[1] - joint[1]),
                    (new_coords[0] - joint[0])
                ))

                if cumm > 0:
                    Lines[num][i][6] = cumm

                cumm += 1

            else:
                indi_coords.append((joint[0], joint[1]))
                cumm = 0

        lines.append(np.asarray(indi_coords))

    linestring = MultiLineString(lines)

    for num, line_coords in reversed(list(enumerate(Lines))):
        for i, joint in reversed(list(enumerate(line_coords))):

            if joint[4] == 'Y' and i < (len(Coords)-1) and joint[3] != 'BRANCH':

                if joint[6] > 0:
                    """ --------------- PATCH -------------------------------- """
                    lineA = LineString([(joint[0], joint[1]),
                                        ((line_coords[i+1][0]), (line_coords[i+1][1]))])
                    left_line = affinity.rotate(
                        lineA, joint[5]/2, (joint[0], joint[1]))
                    rigt_line = affinity.rotate(
                        lineA, -joint[5]/2, (joint[0], joint[1]))

                    try:
                        Vs[-1] = ops.unary_union([MultiLineString(
                            [lineA, left_line, rigt_line])] + all_r_lines[-1])
                    except:
                        Vs.append(MultiLineString([lineA, left_line, rigt_line]))

                    """ --------------- ANGLE LINES -------------------------------- """

                    rotate_angle = line_coords[i-1][5]/2
                    r_lines = [affinity.rotate(
                        Vs[-1],
                        j,
                        (line_coords[i-1][0], line_coords[i-1][1])
                    ) for j in np.linspace(-rotate_angle, rotate_angle, num=3)
                    ]

                    all_r_lines += [r_lines]

                    Vs[-1] = ops.unary_union([Vs[-1]] + r_lines)

                else:
                    """ --------------- PATCH -------------------------------- """
                    lineA = LineString([(joint[0], joint[1]),
                                        ((line_coords[i+1][0]), (line_coords[i+1][1]))])
                    left_line = affinity.rotate(
                        lineA, joint[5]/2, (joint[0], joint[1]))
                    rigt_line = affinity.rotate(
                        lineA, -joint[5]/2, (joint[0], joint[1]))

                    Vs.append(MultiLineString([lineA, left_line, rigt_line]))

                    all_r_lines = []

    all_lines = Vs

    a = ops.unary_union(all_lines)

    creature = (Vs + [a] + [linestring])

    polies = []
    for l in creature:
        polies.append(Polygon(l.buffer(0.5)))

    creature_poly = ops.unary_union(polies)
    creature_patch = PolygonPatch(creature_poly, fc='BLUE', alpha=0.1)

    absorbA = creature_poly
    moves = Vs

    for c_l in linestring:
        x, y = c_l.xy
        ax.plot(x, y)

    for m in all_lines:
        for line in m:
            x, y = line.xy
            ax.plot(x, y, 'g--', alpha=0.25)

    ax.axis('equal')

    ax.add_patch(creature_patch)

    ax.axis('equal')
    plt.show()

【问题讨论】:

  • 有趣的问题,但我认为代码包含太多不相关的内容。你能提供一个minimal and reproducible example吗?或者,您也可以在codereview.stackexchange.com 上发布完整代码,我认为这是一个更好的选择。如果您这样做,请删除该问题的副本。
  • 已经把它移过来了。我正在探索可能会在此处发布的其他一些方法,所以我现在将问题留下

标签: python shapely


【解决方案1】:

你试过 shapelys cascaded_union 吗?

    polygons = [Point(i, 0).buffer(0.7) for i in range(5)]

    cascaded_union(polygons)

或者在你的情况下是线而不是点?

https://shapely.readthedocs.io/en/stable/manual.html#shapely.ops.cascaded_union

【讨论】:

  • 是的,我用过这个,但是它比一行一行地做需要稍长的时间
  • hmm,但是使用这种方法,您仍然会一一缓冲线条,然后将这些多边形合并。如果没有联合,您就不能将所有线条都放在一个几何图形中(小心不同的几何类型变成几何集合)。
  • 是的,这是我的问题。如果有某种方法可以得到最终“补丁”的轮廓,而无需将它们全部组合起来,也无需进行某种图像处理
  • 如果线条相互接触,您可以先将它们溶解,然后得到一条大线条,然后尝试缓冲? gis.stackexchange.com/a/150001
  • 我认为这不是问题所在。当缓冲匀称时,必须将重叠部分融合在一起,我认为这是完成大部分计算的地方
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多