声明:此文是作者学习计算机图形学的学习记录,欢迎对计算机图形学感兴趣的朋友交流经验。另外此文在写作过程中借鉴以下链接的文章:点击打开链接。转载请注明出处。
DDA算法由于在循环中涉及实型数据的加减运算,因此直线的生成速度较慢。
在生成直线的算法中,Bresenham算法是最有效的算法之一。Bresenham算法是一种基于误差判别式来生成直线的方法。
一、直线Bresenham算法描述:
它也是采用递推步进的办法,令每次最大变化方向的坐标步进一个象素,同时另一个方向的坐标依据误差判别式的符号来决定是否也要步进一个象素。
我们首先讨论m=△y/△x,当0≤m≤1且x1<x2时的Bresenham算法。从DDA直线算法可知这些条件成立时,公式(2-2)、(2-3)可写成:
xi+1=xi+1 | (2-6) |
yi+1=yi+m | (2-7) |
有两种Bresenham算法思想,它们各自从不同角度介绍了Bresenham算法思想,得出的误差判别式都是一样的。
二、直线Bresenham算法思想之一:
由于显示直线的象素点只能取整数值坐标,可以假设直线上第i个象素点坐标为(xi,yi),它是直线上点(xi,yi)的最佳近似,并且xi=xi(假设m<1),如下图所示。那么,直线上下一个象素点的可能位置是(xi+1,yi)或(xi+1,yi+1)。
由图中可以知道,在x=xi+1处,直线上点的y值是y=m(xi+1)+b,该点离象素点(xi+1,yi)和象素点(xi+1,yi+1)的距离分别是d1和d2:
d1=y-yi=m(xi+1)+b-yi | (2-8) |
d2=(yi+1)-y=(yi+1)-m(xi+1)-b | (2-9) |
这两个距离差是
d1-d2=2m(xi+1)-2yi+2b-1 | (2-10) |
因此只要利用(d1-d2)的符号就可以决定下一个象素点的选择。为此,我们进一步定义一个新的判别式:
pi=△x×(d1-d2)=2△y·xi-2△x·yi+c | (2-11) |
式(2-11)中的△x=(x2-x1)>0,因此pi与(d1-d2)有相同的符号;
这里△y=y2-y1,m=△y/△x;c=2△y+△x(2b-1)。
下面对式(2-11)作进一步处理,以便得出误差判别递推公式并消除常数c。
将式(2-11)中的下标i改写成i+1,得到:
pi+1=2△y·xi+1-2△x·yi+1+c | (2-12) |
将式(2-12)减去(2-11),并利用xi+1=xi+1,可得:
pi+1= pi+2△y-2△x·(yi+1-yi) | (2-13) |
再假设直线的初始端点恰好是其象素点的坐标,即满足:
y1=mx1+b | (2-14) |
由式(2-11)和式(2-14)得到p1的初始值:
p1=2△y-△x | (2-15) |
这样,我们可利用误差判别变量,得到如下算法表示:
初始 p1=2△y-△x | (2-16) | |
当pi≥0时: yi+1=yi+1, xi+1=xi+1, pi+1=pi+2(△y-△x) |
||
否则: yi+1=yi, |
从式(2-16)可以看出,第i+1步的判别变量pi+1仅与第i步的判别变量pi、直线的两个端点坐标分量差△x和△y有关,运算中只含有整数相加和乘2运算,而乘2可利用算术左移一位来完成,因此这个算法速度快并易于硬件实现。
三、直线Bresenham算法实现:
条件:0≤m≤1且x1<x2
1、输入线段的两个端点坐标和画线颜色:x1,y1,x2,y2,color;
2、设置象素坐标初值:x=x1,y=y1;
3、设置初始误差判别值:p=2·Δy-Δx;
4、分别计算:Δx=x2-x1、Δy=y2-y1;
5、循环实现直线的生成:
for(x=x1;x<=x2;x++)
{ SetPixel(dc,x,y,color) ;
if(p>=0)
{ y=y+1;
p=p+2·(Δy-Δx);
}
else
{ p=p+2·Δy;
}
}
四,Bresenham算法程序实现
依然在vs2010环境下用基于MFC的对话框实现
void CBresenhamDlg::Bresham(int x1, int y1, int x2, int y2, int color) { CPaintDC dc(this); int dx,dy,d; int x=x1,y=y1; dx = abs(x2-x1); dy = abs(y2-y1); d = 2*dy-dx; for (x1;x<=x2;x++) { SetPixel(dc,x,y,color); if (d>0) { y++; d=d+2*(dy-dx); } else{ d=d+2*dy; } } }在Onpaint()函数里调用Bresham()函数即可。
不过这个程序局限性太大,只有在满足条件:0≤m≤1且x1<x2时才能画线,所以我们要对它做一些改进。