本模塊內容絕大部分是在慕課上看中國農業大學網客時的筆記,因此算作轉載,在此鳴謝趙明、李振波兩位老師,感謝他們錄製該門課程供大家學習!
Bresenham算法
前兩種算法把效率提高到了整數加法級別,只講效率,基本已經可以說是最快了。但是,兩者均嚴重依賴直線方程,那麼,有沒有算法在保證算法效率的同時能夠擴大使用範圍,將畫線算法適用的範圍變得更加廣泛呢?(曲線等)——即是下面要介紹的Bresenham算法。
算法思想
Bresenham早在1962年就發表了該算法,該算法結合DDA與中點畫線法的優勢,它的思路是構造一個由各行各列象素中心構造一組虛擬的網格線,按照直線起點到終點的順序,計算直線與各垂直網格線的交點,然後根據誤差項的符號確定該列像素中與此交點最近的像素。
假設按照如下圖的方向步進、判斷,x每次++,y是否遞增取決於直線與最近像素點中心的距離,也即以0.5爲界,與d=d+k比較,判斷直線具體在哪個像素點內。另外,一旦d>=1,就執行d-=1操作,以保證d的相對性,使它在0,1之間
基於該算法的改進
改進1
改進2
改進後的算法步驟
- 讀取兩點座標
- 計算初始值△x=x2-x1,△y=y2-y1,e=-△x,x=x1,y=y1......依然假設x2>x1,在實際編程中需要判斷一下
- 繪製點(x,y)
- e+=2*△y,判斷e的正負決定要描的像素點
- 循環3,4直到繪製完成
程序如下
public class Bresenham extends JFrame {
private int x1 , x2 , y1 , y2 , e;
public Bresenham( int x1 , int y1 , int x2 , int y2 ){
super();
setTitle("Bresham直線繪製算法");
setSize(800,600);
setVisible(true);
this.x1 = x1;
this.x2 = x2;
this.y1 = y1;
this.y2 = y2;
bresenhamDrawLine(x1 , y1 , x2 , y2 );
}
private void bresenhamDrawLine(int x1 , int y1 , int x2 , int y2){
if (abs(x2-x1)>abs(y2-y1)){ //按x方向遞增
if (x1 > x2){
int temp = x1;
x1 = x2;
x2 = temp;
temp = y1;
y1 = y2;
y2 = temp;
}
e = x1 - x2;
drawPixel(x1,y1);
for (int i = x1 , j = y1 ; i < x2 ; i++){
e += 2*(y2 - y1);
if (e > 0){
j++;
drawPixel(i,j);
}
else {
drawPixel(i,j);
}
}
}else {
if (y1 > y2){
int temp = y1;
y1 = y2;
y2 = temp;
temp = x1;
x1 = x2;
x2 = temp;
}
e = y1 - y2;
drawPixel(x1,y1);
for (int j = y1 , i = x1 ; j < y2 ; j++){
e += 2*(y2 - y1);
if (e>0){
i++;
drawPixel(i,j);
}else {
drawPixel(i,j);
}
}
}
}
通過以上我們可以看出,Bresenham算法並沒有去求k,b亦或是A,B,C,僅僅是通過兩點座標去繪製直線,不限定直線方程類型,集合DDA與中點畫線法優勢,應用更廣泛。