Bresenham算法是DDA算法画线算法的一种改进算法。本质上它也是采取了步进的思想。不过它比DDA算法作了优化,避免了步进时浮点数运算,同时为选取符合直线方程的点提供了一个好思路。首先通过直线的斜率确定了在x方向进行单位步进还是y方向进行单位步进:当斜率k的绝对值|m|<1时,在x方向进行单位步进;当斜率k的绝对值|m|>1
时,在y方向进行单位步进。
下面以|m|<1
时推导Bresenham算法的数学依据:
Bresenham-draw-line-a
请看上图,已知有一直线y=mx+b,|m|<1
。我们通过斜率确定了x方向为单位步进。当x=xk时,y=yk。那么当x执行一个单位步进时(即x=xk+1时),y等于yk还是等于yk+1更符合这个直线方程呢?单凭肉眼我们很难得出结论,最好的办法当然是比较yk和yk+1和真实的方程的y值的差是多少(即yreal=m∗(xk+1)+b
),看看哪一个更靠近真实的方程的y值。
算法的具体过程,其实就是在每次画点的时候选取与实际直线的交点y坐标的差最小的那个点。这里假设:
dupper=(yk+1)−yrealddown=yreal−yk
要确定两像素中哪一个更接近线路径,需测试两个像素偏移的差:
dupper−ddown=2yk−2mxk−2m−2b+1
由于m=ΔyΔx,我们有:
pm=Δx(dupper−ddown)=2Δxyk−2Δyxk+Δx−2Δy−2bΔx
则:
pm+1=2Δxyk+1−2Δyxk+1+Δx−2Δy−2bΔx
相减可得到:
pm+1−pm=2Δx(yk+1−yk)−2Δy(xk+1−xk)
因为xk+1=xk+1,所以有:
pk+1−pk=2Δx(yk+1−yk)−2Δy
其中,yk+1−yk取0还是1,取决于pm
的符号。
明白了数学原理,我们很快能确定算法步骤:
1、输入线段的两个端点,并将左端点存储在(xBegin,yBegin)
中;
2、将(xBegin,yBegin)
装入帧缓存,画出第一个点;
3、计算Δx,Δy
,并得到决策参数的第一个值:
p0=2Δxy0−2Δyx0+Δx−2Δy−2bΔx
因为y0=mx0+b=ΔyΔxx0+b,所以代入可得:
p0=Δx−2Δy
4、从k=0开始,在沿线路径的每个xk
处,进行下列检测:
如果pk<0
,下一个要绘制的点是(xk+1,yk+1),并且:
pk+1=pk+2Δx−2Δy
否则,下一个要绘制的点是(xk+1,yk),并且:
pk+1=pk−2Δy
5、重复步骤4,共Δx−1
次
上面是完整严谨的数学推导。当然,也可以用直观的递推方式来实现算法。如图所示,我们可以假设在(xk,yk)
时误差为ε,即实际直线上的点为(xk,yk+ε),那么下一个位于直线上的点应该为(xk+1,yk+ε+m)。可以看出,当ε+m<0.5时,绘制(xk+1,yk)点,否则绘制(xk+1,yk+1)点。每次绘制后,ε
将更新为新值:
ε=ε+m
, 如果ε+m<0.5
ε=ε+m−1
, 其他情况
将上述公式都乘以Δx
, 并将ε∗Δx用新符号ξ
表示,可得
ξ=ξ+Δy
, 如果2∗(ξ+Δy)<Δx
ξ=ξ+Δy–Δx
, 其他情况