Bresenham线条,无对角线运动



是否有一种改进的Bresenham算法,其中从一个像素到下一个像素的步长不允许是对角的,只允许是水平的或垂直的?或者任何其他能做到这一点的算法?(首选PHP)

Right:
0 0 0 1
0 0 1 1
0 1 1 0
1 1 0 0
Wrong:
0 0 0 1
0 0 1 0
0 1 0 0
1 0 0 0

James的回答很酷,但正如他所评论的,这有点偏离了底线。对原始Bresenham的另一个简单修改是绘制一条没有对角台阶的线,更接近"真实"线。

这是原始Bresenham算法的实现:

public void line(int x0, int y0, int x1, int y1, int value) {
    int xDist =  Math.abs(x1 - x0);
    int yDist = -Math.abs(y1 - y0);
    int xStep = (x0 < x1 ? +1 : -1);
    int yStep = (y0 < y1 ? +1 : -1);
    int error = xDist + yDist;
    plot(x0, y0, value);
    while (x0 != x1 || y0 != y1) {
        if (2*error > yDist) {
            // horizontal step
            error += yDist;
            x0 += xStep;
        }
        if (2*error < xDist) {
            // vertical step
            error += xDist;
            y0 += yStep;
        }
        plot(x0, y0, value);
    }
}

修改只是简单地执行水平或垂直步进,而不是两者都执行,这取决于错误指示器是更接近水平还是垂直步进:

public void lineNoDiag(int x0, int y0, int x1, int y1, int value) {
    int xDist =  Math.abs(x1 - x0);
    int yDist = -Math.abs(y1 - y0);
    int xStep = (x0 < x1 ? +1 : -1);
    int yStep = (y0 < y1 ? +1 : -1);
    int error = xDist + yDist;
    plot(x0, y0, value);
    while (x0 != x1 || y0 != y1) {
        if (2*error - yDist > xDist - 2*error) {
            // horizontal step
            error += yDist;
            x0 += xStep;
        } else {
            // vertical step
            error += xDist;
            y0 += yStep;
        }
        plot(x0, y0, value);
    }
}

这有效地选择了将误差最小化的步骤,从而产生更接近实际直线的直线。

代码是用Java编写的,但应该可以很容易地移植到PHP。我还没有彻底测试过,但它应该和最初的布雷森汉姆一样好用。它甚至可能会快一点。

应该是一个微不足道的修改-假设您在象限I中,即向上和向右。与其做对角线,不如做向上。。。然后是一个权利。

代替:

  for x from x0 to x1
             plot(x,y)
             error := error + deltaerr
             if error ≥ 0.5 then
                 y := y + 1
                 error := error - 1.0

类似这样的东西:

for x from x0 to x1
         plot(x,y)
         error := error + deltaerr
         if error ≥ 0.5 then
             y := y + 1
             plot(x,y)
             error := error - 1.0

我发现Franz D的答案在接近水平或垂直时会产生与原始不完全匹配的线条。虽然下面的函数并不完美,但我发现它能产生更好的结果。

Function BresenhamLineNew : Void( x0 : Int, y0 : Int, x1 : Int, y1 : Int )
    Local dx : Int = Abs( x1 - x0 )
    Local dy : Int = Abs( y1 - y0 )
    Local sx : Int = -1
    Local sy : Int = -1
    If x0 < x1 Then sx = 1
    If y0 < y1 Then sy = 1
    Local err : Int = dx - dy
    Local e2 : Int
    While True
        DrawRect x0, y0, 1, 1
        If x0 = x1 And y0 = y1 Then Exit
        e2 = 2 * err
        If dy > dx
            If e2 > -dy
                err = err - dy
                x0 = x0 + sx
            Elseif e2 < dx
                err = err + dx
                y0 = y0 + sy
            Endif
        Else
            If e2 < dx
                err = err + dx
                y0 = y0 + sy
            Elseif e2 > -dy
                err = err - dy
                x0 = x0 + sx
            Endif
        Endif
    Wend
End Function

最新更新