@@ -0,0 +1,2583 @@
+%22%22%22%0ACalculate path distance from an ArcGIS least cost backlink raster%0A%0AI wrote this before I discovered the flow length tool does the same thing if you convert the backlink raster%0Ato a flow direction raster %60flowdir = Int(0.5 * 2 ** backlink)%60%0A%0ALicense is Apache 2.0%0A%0A%22%22%22%0Aimport rasterio, numpy, numba%0A%0A%0A@numba.jit(nopython=True, nogil=True, parallel=True, fastmath=True)%0Adef _path_distance(arr, output, nodata, multiplier=1.0):%0A    for row in range(arr.shape%5B0%5D):%0A        for col in range(arr.shape%5B1%5D):%0A            idx = start_idx = row, col%0A            path = arr%5Bidx%5D.item()%0A            i = 0%0A            dist = 0.0%0A            # print(i, path, dist)%0A            while i %3C 10000:%0A                if path == 0:%0A                    break%0A                elif path == nodata:%0A                    dist = -1.0%0A                    break%0A                elif path %25 2 == 1:  # Odd = up/down/left/right%0A                    dist += (1 * multiplier)%0A                    if path == 1:  # Right (1)%0A                        idx = idx%5B0%5D, idx%5B1%5D + 1%0A                    elif path == 3:  # Down%0A                        idx = idx%5B0%5D + 1, idx%5B1%5D%0A                    elif path == 5:  # Left%0A                        idx = idx%5B0%5D, idx%5B1%5D - 1%0A                    elif path == 7:  # Up%0A                        idx = idx%5B0%5D - 1, idx%5B1%5D%0A%0A                else:  # Even = diagonal%0A                    dist += (2.0 ** 0.5 * multiplier)%0A                    if path == 2:  # LR%0A                        idx = idx%5B0%5D + 1, idx%5B1%5D + 1%0A                    elif path == 4:  # LL%0A                        idx = idx%5B0%5D + 1, idx%5B1%5D - 1%0A                    elif path == 6:  # UL%0A                        idx = idx%5B0%5D - 1, idx%5B1%5D - 1%0A                    elif path == 8:  # UR%0A                        idx = idx%5B0%5D - 1, idx%5B1%5D + 1%0A%0A                path = arr%5Bidx%5D.item()%0A                i += 1%0A            output%5Bstart_idx%5D = dist%0A%0A        if row %25 100 == 0:%0A            print(row)%0A%0A%0Adef path_distance(backlink_raster, output_raster):%0A%0A    with rasterio.open(backlink_raster) as ras:%0A        md = ras.profile%0A        arr = ras.read().squeeze()%0A        nodata = md%5B'nodata'%5D%0A        res = ras.res%5B0%5D  # Cellsize, assumes square pixels%0A%0A    md%5B'dtype'%5D = 'float32'%0A    md%5B'nodata'%5D = -1%0A    output = numpy.zeros(arr.shape, dtype=md%5B'dtype'%5D)%0A%0A    _path_distance(arr, output, nodata, res)%0A%0A    with rasterio.open(output_raster, mode='w', **md) as ras:%0A        ras.write(output%5Bnumpy.newaxis%5D)%0A%0A%0Aif __name__ == '__main__':%0A    import sys%0A    path_distance(sys.argv%5B1:))  #Expects sys.argv%5B1:%5D == backlink_raster, output_raster%0A

Create path_distance.py