Fastest way to get all the points between two (X,Y) coordinates in python

后端 未结 3 846
星月不相逢
星月不相逢 2020-12-16 07:58

So I have a shapely LineString:

print np.round(shapely_intersecting_lines.coords).astype(np.int) 
>>> array([[ 1520, -1140         


        
相关标签:
3条回答
  • 2020-12-16 08:23

    Bresenham may be smart but I'm pretty sure brute force vectorization is faster. I've written two variants - the first is easier to read, the second is faster (80 us vs 50 us).

    Update Fixed a bug (thanks @Varlor) and added an nd variant.

    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')
    

    Sample output:

    [[ 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
    
    0 讨论(0)
  • 2020-12-16 08:35

    Using generators so that way you will save memory

    import numpy as np
    import math
    
    d = np.array(
        [
            [1520,-1140],
            [1412,-973]
        ],dtype=float);
    rise = d[0,1]-d[1,1];
    run = d[0,0]-d[1,0];
    slope = rise/run;
    print slope
    
    fromPt = d[0];
    sign = 1
    if (slope<0):
        sign = -1;
    points = ([d[0,0]+sign*i,math.floor(d[0,1]+(sign*i*slope))] for i in xrange(1+int(math.ceil(abs(d[0,0]-d[1,0])))))
    for pt in points:
        print pt
    
    0 讨论(0)
  • 2020-12-16 08:40

    Here's Bresenhams line algorithm as a generator. If you want a list just call list() on the output:

    def line(x0, y0, x1, y1):
        deltax = x1-x0
        dxsign = int(abs(deltax)/deltax)
        deltay = y1-y0
        dysign = int(abs(deltay)/deltay)
        deltaerr = abs(deltay/deltax)
        error = 0
        y = y0
        for x in range(x0, x1, dxsign):
            yield x, y
            error = error + deltaerr
            while error >= 0.5:
                y += dysign
                error -= 1
        yield x1, y1
    
    0 讨论(0)
提交回复
热议问题