生成直線的Bresenham算法

從上面介紹的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個象素點座標爲(xiyi),它是直線上點(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)

  我們來分析公式(2-10):
  (1)當此值爲正時,d1>d2,說明直線上理論點離(xi+1,yi+1)象素較近,下一個象素點應取(xi+1,yi+1)。
  (2)當此值爲負時,d1<d2,說明直線上理論點離(xi+1,yi)象素較近,則下一個象素點應取(xi+1,yi)。
  (3)當此值爲零時,說明直線上理論點離上、下兩個象素點的距離相等,取哪個點都行,假設算法規定這種情況下取(xi+1,yi+1)作爲下一個象素點。

  因此只要利用(d1-d2)的符號就可以決定下一個象素點的選擇。爲此,我們進一步定義一個新的判別式:

pi=x×(d1-d2)=2y·xi-2x·yi+c (2-11)


  式(2-11)中的x=(x2-x1)>0,因此pi與(d1-d2)有相同的符號;

  這裏y=y2-y1m=y/x;c=2y+x(2b-1)。

  下面對式(2-11)作進一步處理,以便得出誤差判別遞推公式並消除常數c。

  將式(2-11)中的下標i改寫成i+1,得到:

pi+1=2y·xi+1-2x·yi+1+c (2-12)

  將式(2-12)減去(2-11),並利用xi+1=xi+1,可得:

pi+1= pi+2y-2x·(yi+1-yi) (2-13)

  再假設直線的初始端點恰好是其象素點的座標,即滿足:

y1=mx1+b (2-14)

  由式(2-11)和式(2-14)得到p1的初始值:

p1=2y-x (2-15)

  這樣,我們可利用誤差判別變量,得到如下算法表示:

初始     p1=2y-x (2-16)
當pi≥0時: yi+1=yi+1,
      xi+1=xi+1,
      pi+1=pi+2(y-x)

否則:   yi+1=yi,
      xi+1=xi+1,
      pi+1=pi+2y

 

  從式(2-16)可以看出,第i+1步的判別變量pi+1僅與第i步的判別變量pi、直線的兩個端點座標分量差x和y有關,運算中只含有整數相加和乘2運算,而乘2可利用算術左移一位來完成,因此這個算法速度快並易於硬件實現。

  三、直線Bresenham算法思想之二:

  由於象素座標的整數性,數學點(xi,yi)與所取象素點(xi,yir)間會引起誤差(εi),當xi列上已用象素座標(xi,yir)表示直線上的點(xi,yi),下一直線點B(xi+1,yi+1),是取象素點C(xi+1,yir ),還是D(xi+1,y(i+1)r)呢?

  設ACD邊的中點,正確的選擇:

  若B點在A點上方,選擇D點; 否則,選C點。

 

  用誤差式描述爲:

ε(xi+1)=BC-AC=(yi+1-yir)-0.5 (2-8')

  求遞推公式:

ε(xi+2)=(yi+2-y(i+1)r)-0.5 = yi+1+m-y(i+1)r-0.5 (2-9')

  當ε(xi+1)≥0時,選D點,y(i+1)r = yir+1

ε(xi+2)= yi+1+m-yir-1-0.5=ε(xi+1)+m-1 (2-10')

  當ε(xi+1)﹤0時,選C點,y(i+1)r = yir

ε(xi+2)= yi+1+m-yir-0.5=ε(xi+1)+m (2-11')

  初始時:

ε(xs+1)=BC-AC=m-0.5 (2-12')

  爲了運算中不含實型數,同時不影響不等式的判斷,將方程兩邊同乘一正整數。

  令方程兩邊同乘2·Δx,即d=2·Δx·ε,則:

  初始時:

d = 2·Δy-Δx (2-13')

  遞推式:

當d≥0時:{ d=d+2·(Δy-Δx);
      y++;
      x++;
     }
否則:  { d=d+2·Δy;
      x++;
     }
(2-14')

  

  四、直線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=x1x<=x2;x++)
   { putpixel(x,y,color) ;
    if(p>=0)
     { y=y+1;
      p=p+2·(Δy-Δx);
     }
    else
     { p=p+2·Δy;
     }

   }

  五、直線Bresenham算法完善:

  現在我們修正(2-16)公式,以適應對任何方向及任何斜率線段的繪製。如下圖所示,線段的方向可分爲八種,從原點出發射向八個區。由線段按圖中所示的區域位置可決定xi+1和yi+1的變換規律。

  容易證明:當線段處於①、④、⑧、⑤區時,以|x|和|y|代替前面公式中的x和y,當線段處於②、③、⑥、⑦區時,將公式中的|x|和|y|對換,則上述兩公式仍有效。

在線段起點區分線段方向

  六、直線Bresenham算法演示:

     
斜率小於1   斜率大於1

  七、直線Bresenham算法特點:

  由於程序中不含實型數運算,因此速度快、效率高,是一種有效的畫線算法。

  八、直線Bresenham算法程序:

void Bresenhamline (int x1,int y1,int x2,int y2,int color)
{
 int x, y, dx, dy, s1, s2, p, temp, interchange, i;
 x=x1;
 y=y1;
 dx=abs(x2-x1);
 dy=abs(y2-y1);

 if(x2>x1)
  s1=1;
 else
  s1=-1;

 if(y2>y1)
  s2=1;
 else
  s2=-1;

 if(dy>dx)
 {
  temp=dx;
  dx=dy;
  dy=temp;
  interchange=1;
 }
 else
  interchange=0;

 p=2*dy-dx;
 for(i=1;i<=dx;i++)
 {
  putpixel(x,y,color);
  if(p>=0)
  {
   if(interchange= =0)
    y=y+s2;
   else
    x=x+s1;
   p=p-2*dx;
  }
  if(interchange= =0)
   x=x+s1;
  else
   y=y+s2;
  p=p+2*dy;
 }
}
 
發佈了0 篇原創文章 · 獲贊 10 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章