1

是否有改进的 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
4

3 回答 3

6

詹姆斯的回答很酷,但正如他评论的那样,它有点歪曲了这条线。对原始 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。我还没有彻底测试过它,但它应该和原来的 Bresenham 一样好用。它甚至可能会快一点。

于 2015-02-28T20:31:41.077 回答
3

应该是一个微不足道的修改 - 假设你在第一象限 - 即向上和向右。不要做对角线,而是做一个向上......然后向右。

代替:

  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
于 2012-01-20T02:52:29.827 回答
1

我发现 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
于 2017-10-01T14:52:12.397 回答