計算機圖形學之掃描轉換直線-DDA,Bresenham,中點畫線算法


1.DDA算法

DDA(Digital Differential Analyer):數字微分法

DDA算法思想:增量思想

公式推導:

效率:采用了浮點加法和浮點顯示是需要取整

代碼:

void lineDDA(int x0, int y0, int x1, int y1, int color){
    int x;
    float dy, dx, y, m;
    dx = x1 - x0;
    dy = y1 - y0;
    m = dy / dx;
    y = y0;
    for (x = x0; x <= x1; x++){
        putpixel(x, (int)(y + 0.5), color);
        y += m;
    }
}

2.中點畫線法

采用了直線的一般式:Ax+By+C=0

當k在(0,1]中時,每次在x方向上加1,y方向上加1或不變:

當Q在M上方時,取Pu點;

當Q在M下方時,取Pd點。

接下來:

然后中點畫線的計算:

di需要兩個乘法和四個加法算,比DDA差的多,但是di可以用增量法求

當d<0時

當d>=0時

d的初始值d0:

中點算法計算為:

如果將d換成2d,就只有整數運算,優於DDA算法。

最終公式:

代碼:

void lineMidPoint(int x0, int y0, int x1, int y1, int color){
    int x = x0, y = y0;
    int a = y0 - y1, b = x1 - x0;
    int cx = (b >= 0 ? 1 : (b = -b, -1));
    int cy = (a <= 0 ? 1 : (a = -a, -1));

    putpixel(x, y, color);

    int d, d1, d2;
    if (-a <= b)     // 斜率絕對值 <= 1  
    {
        d = 2 * a + b;
        d1 = 2 * a;
        d2 = 2 * (a + b);
        while (x != x1)
        {
            if (d < 0)
                y += cy, d += d2;
            else
                d += d1;
            x += cx;
            putpixel(x, y, color);
        }
    }
    else                // 斜率絕對值 > 1  
    {
        d = 2 * b + a;
        d1 = 2 * b;
        d2 = 2 * (a + b);
        while (y != y1)
        {
            if (d < 0)
                d += d1;
            else
                x += cx, d += d2;
            y += cy;
            putpixel(x, y, color);
        }
    }
}

3.Bresenham算法

DDA使畫直線每步只有一個加法。

中點畫線法使畫直線每步只有一個整數加法。

Bresenham算法提供一個更一般的算法,使適用范圍增大。

該算法的思想是通過各行、各列像素中心構造一組虛擬網格線,按照直線起點到終點的順序,計算直線與各垂直網格線的交點,然后根據誤差項的符號確定該列象素中與此交點最近的象素。

假設每次x+1,y的遞增(減)量為0或1,它取決於實際直線與最近光柵網格點的距離,這個距離的最大誤差為0.5。

誤差項d的初值d 0=0,d=d+k,一旦d≥1,就把它減去1,保證d的相對性,且在0、1之間。

然后有下面計算公式:

怎么提升到整數算法?

答案是讓e=d-0.5

e0=-0.5

每循環一次:e = e+k
if (e>0) then e = e-1

e+k這還是一個浮點加法

因為k=△y/△x

因為用誤差項的符號,可以用e*2*△x來替換 e:

e0=-△x

每循環一次:e = e+2△y
if (e>0) then e = e-2△x

這已經變成為整數加法

算法步驟:

算法步驟為:
1.輸入直線的兩端點P 0(x 0,y 0)和P 1(x 1,y 1)。
2.計算初始值△x、△y、 e=-△x、x=x 0、y=y 0。
3.繪制點(x,y)。
4.e更新為 e+2△y,判斷e的符號。若e>0,則(x,y)更新為
(x+1,y+1),同時將e更新為 e-2△x;否則(x,y)更新為
(x+1,y)。
5.當直線沒有畫完時,重復步驟3和4。否則結束。

代碼:

void lineBresenham1(int x0, int y0, int x1, int y1, long color)
{
    int dx = abs(x1 - x0);
    int dy = abs(y1 - y0);
    int x = x0;
    int y = y0;
    int stepX = 1;
    int stepY = 1;
    if (x0 > x1)  //從右向左畫  
        stepX = -1;
    if (y0 > y1)
        stepY = -1;

    if (dx > dy)  //沿着最長的那個軸前進  
    {
        int e = dy * 2 - dx;
        for (int i = 0; i <= dx; i++)
        {
            putpixel(x, y, color);
            x += stepX;
            e += dy;
            if (e >= 0)
            {
                y += stepY;
                e -= dx;
            }
        }
    }
    else
    {
        int e = 2 * dx - dy;
        for (int i = 0; i <= dy; i++)
        {
            putpixel(x, y, color);
            y += stepY;
            e += dx;
            if (e >= 0)
            {
                x += stepX;
                e -= dy;
            }
        }
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM