在python中获取两个(X,Y)坐标之间的所有点的最快方法

Jus*_*ang 3 python gis interpolation numpy vectorization

所以我有一个shapely LineString

print np.round(shapely_intersecting_lines.coords).astype(np.int) 
>>> array([[ 1520, -1140],
           [ 1412,  -973]])
Run Code Online (Sandbox Code Playgroud)

这可以解释为numpy数组以及上面看到的。

我想获得中间的所有点,也就是说,我想获得中间线的点作为整数值。输出应该是这样的:

array([[ 1520, -1140],
       [ 1519, -1139],
       [ 1519, -1138],
       ..., 
       [ 1413,  -975],
       [ 1412,  -974],
       [ 1412,  -973]], dtype=int32)
Run Code Online (Sandbox Code Playgroud)

我早些时候在gis.stackexchange 中发布了这个,希望有一个shapely有效的解决方案。该解决方案起初很好,但是,由于我在代码中运行了 50000 多次,该解决方案现在太慢了。在我的电脑上,每个循环大约需要 0.03 秒,导致运行超过一天。对于我在这里需要的东西来说太慢了,希望看看是否有人知道对此的矢量化解决方案。

Pau*_*zer 5

Bresenham 可能很聪明,但我很确定蛮力矢量化更快。我写了两个变体——第一个更容易阅读,第二个更快(80 us vs 50 us)。

更新修复了一个错误(感谢@Varlor)并添加了一个 nd 变体。

import numpy as np
from timeit import timeit

def connect(ends):
    d0, d1 = np.abs(np.diff(ends, axis=0))[0]
    if d0 > d1: 
        return np.c_[np.linspace(ends[0, 0], ends[1, 0], d0+1, dtype=np.int32),
                     np.round(np.linspace(ends[0, 1], ends[1, 1], d0+1))
                     .astype(np.int32)]
    else:
        return np.c_[np.round(np.linspace(ends[0, 0], ends[1, 0], d1+1))
                     .astype(np.int32),
                     np.linspace(ends[0, 1], ends[1, 1], d1+1, dtype=np.int32)]


def connect2(ends):
    d0, d1 = np.diff(ends, axis=0)[0]
    if np.abs(d0) > np.abs(d1): 
        return np.c_[np.arange(ends[0, 0], ends[1,0] + np.sign(d0), np.sign(d0), dtype=np.int32),
                     np.arange(ends[0, 1] * np.abs(d0) + np.abs(d0)//2,
                               ends[0, 1] * np.abs(d0) + np.abs(d0)//2 + (np.abs(d0)+1) * d1, d1, dtype=np.int32) // np.abs(d0)]
    else:
        return np.c_[np.arange(ends[0, 0] * np.abs(d1) + np.abs(d1)//2,
                               ends[0, 0] * np.abs(d1) + np.abs(d1)//2 + (np.abs(d1)+1) * d0, d0, dtype=np.int32) // np.abs(d1),
                     np.arange(ends[0, 1], ends[1,1] + np.sign(d1), np.sign(d1), dtype=np.int32)]


def connect_nd(ends):
    d = np.diff(ends, axis=0)[0]
    j = np.argmax(np.abs(d))
    D = d[j]
    aD = np.abs(D)
    return ends[0] + (np.outer(np.arange(aD + 1), d) + (aD>>1)) // aD


ends = np.array([[ 1520, -1140],
                 [ 1412,  -73]])

ends_4d = np.array([[  100, -302, 101, -49],
                    [ -100,  -45, 112, 100]])

print(connect(ends))
print(connect_nd(ends_4d))


assert np.all(connect(ends)==connect2(ends))
assert np.all(connect(ends)==connect_nd(ends))
assert np.all(connect(ends)==connect(ends[:, ::-1])[:, ::-1])
assert np.all(connect(ends)==connect(ends[::-1])[::-1])

print(timeit('f(ends)', globals={'f': connect, 'ends': ends}, number=10000)*100, 'us')
print(timeit('f(ends)', globals={'f': connect2, 'ends': ends}, number=10000)*100, 'us')
print(timeit('f(ends)', globals={'f': connect_nd, 'ends': ends}, number=10000)*100, 'us')
Run Code Online (Sandbox Code Playgroud)

示例输出:

[[ 1520 -1140]
 [ 1520 -1139]
 [ 1520 -1138]
 ..., 
 [ 1412   -75]
 [ 1412   -74]
 [ 1412   -73]]
[[ 100 -302  101  -49]
 [  99 -301  101  -48]
 [  98 -300  101  -48]
 ..., 
 [ -98  -47  112   99]
 [ -99  -46  112   99]
 [-100  -45  112  100]]
78.8237597000034 us
48.02509490000375 us
62.78072760001123 us
Run Code Online (Sandbox Code Playgroud)