Bresenham算法是一种精确而有效的光栅线生成算法,该算法仅仅使用增量计算。

为了说明该算法,我们先考虑斜率小于1的直线的绘制过程。沿线路径的像素为止由以单位x间隔的取样来确定。从给定线段的左端点(x0,y0)(x_0,y_0)开始,逐步处理每个后继列(xx位置),并在其扫描线y值最接近线段的像素上绘出一点。

假如已经决定要显示的像素在(xk,yk)(x_k,y_k),那么下一步需要确定在列xk+1=xk+1x_{k+1}=x_k+1上绘制哪个像素,是位置(xk+1,yk)(x_k+1,y_k)还是(xk+1,yk+1)(x_k+1, y_k+1)

为了确定下一个点的位置,我们需要分别计算出yky_kyk+1y_{k+1}与y(就是xk+1x_k+1对应的y值)的距离。我们分别使用dlowerd_{lower}dupperd_{upper}
来表示这两个距离。

xk+1x_k+1处y的坐标可计算为:
y=m(xk+1)+b y=m(x_k+1)+b

所以dlower=d_{lower}=
yyk=m(x+k+1)+byk y-y_k =m(x+k+1)+b-y_k
dupper=d_{upper}=
(y+k+1)y=yk+1m(xk+1)b (y+k+1)-y =y_k+1-m(x_k+1)-b

若要确定两个像素哪一个离直线更近,我们需要测试dlowerd_lowerdupperd_upper的差:

dlowerdupper=(yk+1)y=yk+1m(xk+1)b d_{lower}-d_{upper}=(y_k+1)-y=y_k+1-m(x_k+1)-b

设线的两端点的竖直和水平偏移量分别为ΔyΔyΔxΔx,将上面的距离差两边同时乘于ΔxΔx,我们便可以得到画线算法第k步的决策参数p

pk=Δx(dlowerdupper)=2ΔyΔx2Δxyk+c p_k=Δx(d_{lower}-d_{upper})=2Δy·Δx-2Δx·y_k+c

经过推导后:
pk+1=pk+2Δy2Δx(yk+1yk) p_{k+1}=p_k+2Δy-2Δx(y_{k+1}-y_k)

p0=2ΔyΔx p_0=2Δy-Δx

总结:

  1. 输入线段两个端点,并将左端点存储在(x0,y0)(x_0,y_0)中。
  2. 将左端点画出
  3. 计算常量ΔxΔxΔyΔy2Δy2Δx2Δy-2Δx,并得到决策参数的第一个值p0p_0
    p0=2ΔyΔx p_0=2Δy-Δx
  4. 从k=0开始,在沿线段路径的每个x处,进行如下检测
    如果pk<0p_k<0,下一个要绘制的点是(xk+1,yk)(x_k+1,y_k),并且
    pk+1=pk+2Δy p_{k+1}=p_k+2Δy
    否则,下一个要绘制的点是(xk+1,yk+1)(x_k+1,y_k+1),并且
    pk+1=pk+2Δy2Δx p_{k+1}=p_k+2Δy-2Δx
  5. 重复步骤4,共Δx1Δx-1次。

最终实现结果:
Bresenham画线算法(Three.js实现)

截图中效果实现代码放在Github

相关文章: