【问题标题】:My implementation of Bresenham's algorithm fails for lines at certain angles对于某些角度的线,我对 Bresenham 算法的实现失败了
【发布时间】:2010-09-15 00:12:42
【问题描述】:

我在 Python 中编写了 Bresenham 算法的实现(遵循 Wikipedia article),除了某些角度的线条外,它可以正常工作。所有应该在 45 到 90 度之间或 135 到 270 度之间延伸的线都将沿着 y = x 线延伸。

这是我的代码:

def bresenham(origin, dest):
    # debug code
    print origin
    print dest
    # end debug code
    x0 = origin[0]; y0 = origin[1]
    x1 = dest[0]; y1 = dest[1]
    steep = abs(y1 - y0) > abs(x1 - x0)
    backward = x0 > x1

    if steep:
        x0, y0 = y0, x0
        x1, y1 = y1, x1
    if backward:
        x0, x1 = x1, x0
        y0, y1 = y1, y0

    dx = x1 - x0
    dy = abs(y1 - y0)
    error = dx / 2
    y = y0

    if y0 < y1: ystep = 1 
    else: ystep = -1

    result = []
    #if x0 > x1: xstep = -1
    #else: xstep = 1
    # debug code
    print "x0 = %d" % (x0)
    print "x1 = %d" % (x1)
    print "y0 = %d" % (y0)
    print "y1 = %d" % (y1)
    for x in range(x0, x1):
        if steep: result.append((y,x))
        else: result.append((x,y))
        error -= dy
        if error < 0:
            y += ystep
            error += dx 
    # ensure the line extends from the starting point to the destination
    # and not vice-versa
    if backward: result.reverse()
    print result
    return result

有人知道我在搞砸什么吗?


编辑:

我在函数中添加了一些打印代码。

(0,0) 位于显示屏的左上角。

我的测试框架非常简单。这是一个独立的函数,所以我只传递两点:

原点 = (416, 384)
目的地 = (440, 347)
布雷森汉姆(起点,终点)
(416, 384)
(440, 347)
x0 = 384
x1 = 347
y0 = 416
y1 = 440
[]

【问题讨论】:

  • @aaa 鲤鱼:不。不过,感谢您的回答。
  • 除了if x0 &gt; x1: xstep = -1 是不必要的之外,我认为您的代码没有任何问题,因此您的问题可能出在其他地方。您需要发布实际结果,以便我们了解发生了什么。
  • @Gabe: xstep 是必需的,因为如果没有它,如果 x0 &gt; x1,那么 for 循环将立即终止,因为 Python for 循环的默认步骤是 1。除此之外,还有什么你想要什么样的结果?当它出错时,它会返回一个点列表,其中每个点都高于或低于它之前的点 (1,1)。
  • Max:请发布一些示例输入以及它们产生的错误输出。您无需检查if x0 &gt; x1,因为您在该行运行之前交换了x0x1
  • 傻问:你能展示你的测试框架(我的 Python-fu 完全扭曲了)以及它工作和不工作的示例调用(这只是两行代码)。我认为数据并不重要。

标签: python bresenham


【解决方案1】:

我不知道您为什么要使用 xstep 变量。你真的不需要一个你正在使用的算法。

@Gabe: xstep 是必需的,因为没有它,如果 x0 > x1,那么 for 循环将立即终止,因为 Python for 循环的默认步长是 1。

您不需要 xstep 变量的原因是,如果它向后移动,坐标已经切换(在开头的 if backward: 条件中),因此终点现在是起点,并且反之亦然,这样我们现在仍然从左到右。

你只需要这个:

result = []

for x in range(x0, x1):
    if steep: result.append((y, x))
    else: result.append((x, y))
    error -= dy
    if error < 0:
        y += ystep
        error += dx

return result

如果你想要坐标列表从开始到结束的顺序,那么你可以在最后做检查:

if backward: return result.reverse()
else: return result

编辑:问题是backward 布尔值在之前被评估。如果steep 条件执行,那么值会改变,但到那时你的backward 条件是不同的。要解决此问题,请不要使用 backward 布尔值,而是将其设为显式表达式:

if x0 > x1:
    # swapping here

再一次,由于您稍后会使用布尔值,您可以在条件之前定义它:

backward = x0 > x1

if backward:

【讨论】:

  • 最初我就像你建议的那样,但是当我试图在我的问题中提到的角度画一条线时,该函数不会返回任何内容,因为 for 循环会立即终止。 xstep 对此进行了修复。也许这表明我的实施存在其他问题?
  • 循环不应该失败,因为请记住,我们交换了坐标,使得它仍然从左到右(例如 x0,x1 = x1,x0)。也许你应该在循环之前打印出 x0 和 x1 来验证。
  • 我做了,x0 确实大于 x1。
  • @Max:您在此处的评论表明范围设置不正确。您是否打印了最终得到的 x0、x1、y0、y1 值?该算法的重点在于它可以随着 x 值的增加而工作。如果在执行范围时 x0 > x1,那么您最终会得到一个空范围 - 和一个快速循环。
  • 是的。想想看。顶部的条件检查是否 x0 > x1,如果是,则交换它们。因此,循环的范围决不应该考虑 x0 > x1,你看到这里的断开了吗?也许您的交换不起作用。照乔纳森说的做,打印出要验证的值。
【解决方案2】:

问题是您在交换xy 之前计算x0 &gt; x1

代替:

backward = x0 > x1 

if steep: 
    x0, y0 = y0, x0 
    x1, y1 = y1, x1 
if backward: 
    x0, x1 = x1, x0 
    y0, y1 = y1, y0 

你应该有:

if steep: 
    x0, y0 = y0, x0 
    x1, y1 = y1, x1 

backward = x0 > x1 
if backward: 
    x0, x1 = x1, x0 
    y0, y1 = y1, y0 

【讨论】:

  • 我认为我所做的所有工作都不值得一点点赞,除了我在他面前发布了解决方案;_;加布的道具虽然也发现了它:)
  • @Blaenk。对不起,你是对的。整整一分钟前就知道了。已修复,并支持启动。谢谢你的帮助。 :)
猜你喜欢
  • 1970-01-01
  • 2015-06-10
  • 1970-01-01
  • 1970-01-01
  • 2017-11-24
  • 1970-01-01
  • 1970-01-01
  • 2021-04-15
  • 1970-01-01
相关资源
最近更新 更多