1. 程式人生 > >畫線演算法——DDA和Bresenham

畫線演算法——DDA和Bresenham

通過學習《Hearn&Backer.Computer Graphics with OpenGL》 實現畫線演算法

一、直線方程

直線的笛卡爾斜率截距方程:

y=mx+b

斜率為m,截距為b

在端點(x0,y0)和(xend,yend)之間的線段:

這裡寫圖片描述
根據兩個端點的x和y值可以得到計算斜率和截距的公式:
m=yendy0xendx0
b=y0mx0

通過沿直線的x的增量δx,可以計算出對應y的增量δy:

δy=mδx

同理,通過沿直線y的增量δy,可以計算出對應x的增量δx:

δx=δym

二、DDA

DDA(digital differential analyzer)演算法,在一個座標軸上對線段以單位間隔取樣,計算另一座標軸上最靠近線段的對應整數值。

根據斜率m的取值範圍,一共可以分為4種情況:

  1. 斜率為正,且小於等於1 (1>=m>0)

    此時以單位x間隔(δx=1)取樣,並計算每一個y值
    

yk+1=yk+m

  1. 斜率為正,且大於1 (m>1)

    此時以單位x間隔(δy=1)取樣,並計算每一個x值
    

xk+1=xk+1m

  1. 斜率為負,且大於等於-1 (-1<=m<0)

    此時以單位x間隔(δx=-1)取樣,並計算每一個y值
    

yk+1=ykm

  1. 斜率為負,且小於-1 (m<-1)

    此時以單位x間隔(δy=-1)取樣,並計算每一個x值
    

xk+1=xk1m

演算法程式碼

int Round (float a)//將float型別數四捨五入轉化成int型別
{
    int b = (a+0.5);
    return b;
}

void lineDDA(int x0, int y0, int xEnd, int yEnd)
{
    int dx,dy,steps,i;
    float xInc,yInc,x=x0,y=y0;

    dx = xEnd - x0;
    dy = yEnd - y0;

    if
(fabs(dx) > fabs(dy)){ steps = fabs(dx); } else{ steps = fabs(dy); } drawPixel(Round(x), Round(y)); xInc = (float)dx / (float)steps; yInc = (float)dy / (float)steps; for(i=0;i<steps;i++){ x += xInc; y += yInc; drawPixel(Round(x), Round(y)); } }

三、Bresenham

Bresenham演算法是一個只用整數增量進行計算,精確並且有效的光柵線生成演算法。

同DDA演算法一樣Bresenham演算法,根據直線的斜率數值,有著不同的情況

斜率為正且小於1

從端點開始,沿線路徑的畫素位置由以單位x間隔的取樣來確定

比如決定現在顯示的座標是(Xk,yk),下一個畫素的座標位置是(Xk + 1,yk)或者(Xk + 1, yk + 1) 根據哪一個點距離直線的距離更近而決定

使用dlower和dupper分別表示垂直畫素偏移:
這裡寫圖片描述
可以得到計算相關變數的數學表示式:

y=m(xk+1)+b

dlower=yyk=m(xk+1)+byk

dupper=(yk+1)y=yk+1m(xk+1)b

比較兩個垂直畫素偏移,哪個小則下一畫素點在離得近的畫素點

dlowerdupper=2m(xk+1)2yk+2b1

此時建立一個引數pk,代表第k步時畫素偏移之差的正負值,並將m=δy/δx帶入化簡(δx和δy分別是線段兩個端點的水平和垂直移動距離):

pk=dlowerdupper=2δyx