快速体素遍历2D

时间:2016-12-22 19:37:45

标签: python algorithm math geometry raytracing

我正在尝试遍历线路经过的所有单元格。我发现Fast Voxel Traversal Algorithm似乎符合我的需要,但我目前发现它不准确。下面是一个红线和点作为算法给出的体素坐标的图形。正如你所看到的,除了(4,7)点之外它几乎是正确的,因为它应该是(5,6)。我不确定我是否正确实现了算法,所以我把它包含在Python中。所以我想我的问题是我的实现是正确的还是有更好的算法呢?

由于

ref line w/ voxel pts

L  
[[ 125.20560531  292.91525518   92.76132814  141.33797061  282.93586313
   185.71134917  199.48789246   96.04089205  192.11501055  118.68811072]  
 [ 174.72737183  408.77013914  129.45061871  197.24046765  394.84366245
   259.16456278  278.39005349  134.0273274   268.1010231   165.63205458]  
 [ 194.38951303  454.76920678  144.01774873  219.43601655  439.27557808
   288.32845493  309.71739782  149.10947628  298.27053871  184.27069609]]

S  
[[ -25.20560531    0.          252.23867186   -0.            0.
   201.28865083   78.51210754  336.95910795   -0.           34.31188928]  
 [ 125.27262817  238.22986086  115.54938129  228.75953235  494.15633755
   727.83543722   -0.           -0.           26.8989769    -0.        ]  
 [   0.          292.23079322   -0.            0.           49.72442192
    -0.           68.28260218  883.89052372    0.          268.72930391]]

3 个答案:

答案 0 :(得分:1)

你走的体素从0.0开始,即第一个体素从0.0到1.0跨越空间,而不是从-0.5到0.5,正如你所假设的那样。换句话说,它们是用虚线标记的,而不是实线的。

如果您想要自己的体素,则必须修复初始的maxX和maxY计算。

答案 1 :(得分:0)

难道没有人有时间阅读您发布的论文并弄清楚您是否已正确实施。

但这是一个问题。您使用的算法(a)实际上是用于确定线穿过的所有单元格还是(b)形成两点之间直线的体面体素近似值?

我更熟悉执行(b)的Bresenham's line algorithm。以下是它的实际情况:

Bresenham's line algorithm

请注意,细胞的选择是“美学的”,但是省略了细胞经过的某些细胞。包括这些将使这条线“更加丑陋”。

我怀疑你的体素线算法正在发生类似的事情。但是,查看您的数据和Bresenham图像提示了一个简单的解决方案。沿着发现的细胞行走,但是,每当你必须做一个对角线步骤时,考虑两个中间细胞。然后,您可以使用线矩形交集算法(请参阅here)来确定哪些候选单元格应该包含但不包括在内。

答案 2 :(得分:-1)

我想要完成,我决定使用不同的算法。这里引用的那个dtb's answer on another question

这里是实施

def getIntersectPts(strPt, endPt, geom=[0,1,0,0,0,1]):
'''
    Find intersections pts for every half cell size
    ** cell size has only been tested with 1

    Returns cell coordinates that the line passes through
'''

x0 = geom[0]
y0 = geom[3]

(sX, sY) = (strPt[0], strPt[1])
(eX, eY) = (endPt[0], endPt[1])
xSpace = geom[1]
ySpace = geom[5]

sXIndex = ((sX - x0) / xSpace)
sYIndex = ((sY - y0) / ySpace)
eXIndex = ((eX - sXIndex) / xSpace) + sXIndex
eYIndex = ((eY - sYIndex) / ySpace) + sYIndex


dx = (eXIndex - sXIndex)
dy = (eYIndex - sYIndex)
xHeading = 1.0 if dx > 0 else -1.0 if dx < 0 else 0.0
yHeading = 1.0 if dy > 0 else -1.0 if dy < 0 else 0.0

xOffset = (1 - (math.modf(sXIndex)[0]))
yOffset = (1 - (math.modf(sYIndex)[0]))

ptsIndexes = []
x = sXIndex
y = sYIndex
pt = (x, y) #1st pt

if dx != 0:
    m = (float(dy) / float(dx))
    b = float(sY - sX * m )

dx = abs(int(dx))
dy = abs(int(dy))

if dx == 0:
    for h in range(0, dy + 1):
        pt = (x, y + (yHeading *h))
        ptsIndexes.append(pt)

    return ptsIndexes

#print("m {}, dx {}, dy {}, b {}, xdir {}, ydir {}".format(m, dx, dy, b, xHeading, yHeading))
#print("x {}, y {}, {} {}".format(sXIndex, sYIndex, eXIndex, eYIndex))

#snap to half a cell size so we can find intersections on cell boundaries
sXIdxSp = round(2.0 * sXIndex) / 2.0
sYIdxSp = round(2.0 * sYIndex) / 2.0
eXIdxSp = round(2.0 * eXIndex) / 2.0
eYIdxSp = round(2.0 * eYIndex) / 2.0
# ptsIndexes.append(pt)
prevPt = False
#advance half grid size
for w in range(0, dx * 4):
    x = xHeading * (w / 2.0) + sXIdxSp
    y = (x * m + b)
    if xHeading < 0:
        if x < eXIdxSp:
            break
    else:
        if x > eXIdxSp:
            break

    pt = (round(x), round(y)) #snapToGrid
    # print(w, x, y)

    if prevPt != pt:
        ptsIndexes.append(pt)
        prevPt = pt
#advance half grid size
for h in range(0, dy * 4):
    y = yHeading * (h / 2.0) + sYIdxSp
    x = ((y - b) / m)
    if yHeading < 0:
        if y < eYIdxSp:
            break
    else:
        if y > eYIdxSp:
            break
    pt = (round(x), round(y)) # snapToGrid
    # print(h, x, y)

    if prevPt != pt:
        ptsIndexes.append(pt)
        prevPt = pt

return set(ptsIndexes) #elminate duplicates