Php 不带对角线运动的Bresenham线

Php 不带对角线运动的Bresenham线,php,algorithm,line,bresenham,Php,Algorithm,Line,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 应该是一个很小的修改——假设你在象限I——即向上和向右。不是做对角线,而是做向上。。。然后右转 而不是: for x from x0 to x1 plot(x,

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

应该是一个很小的修改——假设你在象限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

应该是一个很小的修改——假设你在象限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

詹姆斯的回答很酷,但正如他评论的那样,这有点偏离了底线。对原始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一样好用。这甚至可能快一点。

詹姆斯的回答很酷,但正如他所评论的,这有点偏离了底线。对原始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一样好用。甚至可能快一点。

我发现弗兰兹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

我发现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

事实上,这会使你的思路有点歪。视在中心的平均值比预期的高出半个像素。如果这很重要,你可能不得不修改错误计算。实际上,这会使你的线有点歪斜。视在中心的平均值比预期的高出半个像素。如果这很重要,您可能必须修改错误计算。