Brsenham 直線算法

1.Bresenham算法的用途

        電子設備上的圖形是像素化的,也就是說點的座標都是整數,當去繪製一條直線時,採樣點幾乎不可能同時都滿足橫縱座標都是整數,那麼這些點要怎麼去畫,直線要怎麼去畫,Bresenham解決的就是如何在這樣的前提下劃線。

2.Bresenham原理

        取與某點最近的整點代替該點,宏觀上看是這樣的:

        黃色的線是真實的線,而紅色的點是運用Bresenham算法畫出來的點,可能大家會覺得畫出來的不是直線,但從肉眼看就是直線,因爲像素點間的距離太近,根本看不出這種區別,我的電腦屏幕的分辨率是1366*768,長40cm左右,當採用這種分辨率時,相鄰像素點距離爲40/1366=0.29mm,這是人眼無法分辨的,這樣導致最終畫出來的就是一條直線。

 3.Bresenham算法

     繪製(x0,y0),到(x1,y1)的直線,假設直線的斜率小於1(這很重要,保證了當x加1,y只有兩種取值),dx=x1-x0,dy=y1-y0,斜率m=(y1-y0)/(x1-x0),直線上有點(x,y+e),實際取點爲(x,y),e爲誤差,當X變爲x+1時,需要判斷真實值Y=y+e+m與y+0.5的關係,從而取值

e+m<0.5時,實際取值Y=y,

e=e+m;

e+m>0.5時,Y=y+1,

e=e+m-1;

爲了消除小數,省去m的計算(m是小數也比較麻煩),含e和m的所有的式子乘以dx*2,並記2*e*dx=E,上述式子轉化爲:

E+2dy<dx,Y=y,

E=E+2dy;

E+2dy>dx,Y=y+1,

E=E+2dy-2dx。

這樣繼續往下去點,便可把整條直線繪製出來。

對於更一般的直線,當dx或dy是小於零的時候,只需要把對應座標的++,改爲--即可,對於|dy/dx|>1的情況,可以把y看成自變量,這樣可確保每次x只有兩個取值。


僞算法爲:

x=x0;

y=y0;

e=0;

plot(x,y);

for x0->x1

if(e+2dy>dx)

y++;

e=e+2dy-2dx;

else

e=e+2dy;

end if;

plot(x,y);

end for;

4.代碼實現(c++)

void draw_line (int start_x,int start_y,int end_x,int end_y){
int dx, dy,
     dx2,dy2;

int E=0;
dx=end_x-start_x;
dy=end_y-start_y;
int inc_x;
int inc_y;
int mempitch=0;
    lpddprimary ->Lock (NULL,&ddsd,DDLOCK_SURFACEMEMORYPTR |DDLOCK_WAIT ,NULL);
    mempitch=ddsd.lPitch;
    buffer=(char*)(ddsd.lpSurface );
buffer+=start_x+start_y*mempitch;//這些都是爲了在表面畫點,點的位置x加1對應內存加1,y+1對應內存加mempitch
if(dx>0){
inc_x=1;
}
else {
inc_x=-1;
dx=-dx;
}
if(dy>0){
inc_y=mempitch;
}
else {
inc_y=-mempitch;
dy=-dy;
}
dx2=dx<<1;
dy2=dy<<1;


if(dx>dy){
*buffer=0;
    for(int index=0;index<=dx;index++){
   
E+=dy2;
buffer+=inc_x;
if(E>dx){
buffer+=inc_y;
E-=dx2;
}
*buffer=0;
}//end index
lpddprimary ->Unlock (NULL);}
else{
*buffer=0;
    for(int index=0;index<=dy;index++){
    
E+=dx2;
buffer+=inc_y;
if(E>dy){
buffer+=inc_x;
E-=dy2;
}
*buffer=0;
}
lpddprimary ->Unlock (NULL);
}//end else
}







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章