画直线算法

画直线算法

原文地址:
画直线算法

         前段时间做了一下光栅直线生成算法的研究,并且在VC下实现了DDA算法、Bresenham算法、对称算法、两步算法、及四步算法。这里给个总结,希望和大家交流。

总述

       主要研究的算法主要有DDA算法、Bresenham算法、对称算法、两步算法、及四步算法,此外还对自适应多步位移码画线算法进行了一定研究。其中,DDABresenham算法都是单步画线算法,其它是多步画线算法。

算法介绍

   DDA算法和Bresenham算法是经典的画线算法,并且业已证明Bresenham画线算法使用了最小的计算量,是最高效的单步画线算法,这里不再对其进行说明。以下对其余各个算法进行必要的说明。

1 对称直线生成算法

       对称直线生成算法基于这样一个事实:直线以中点位界,其两边是对称的。因而可以利用这个对称性,对Bresenham算法进行改进,使得每进行一次判断就可以生成相对于直线中点的两个对称点。如此以来,直线就由两端向中间生成。算法用C++语言描述如下:

       int x1 = m_start.m_x;  // 起点x

    int y1 = m_start.m_y;  // 起点y

    int x2 = m_end.m_x;    // 终点x

    int y2 = m_end.m_y;    // 终点y

    int dx = m_end.m_x - m_start.m_x;

    int dy = m_end.m_y - m_start.m_y;

    int dx2 = dx << 1;

    int dy2 = dy << 1;

    int e  = dy2 - dx;  // 决策量

    int half = (dx+1) >> 1;

    for (int i=0; i<half; i++)

    {

       pDC->SetPixel(x1, y1, color);

       pDC->SetPixel(x2, y2, color);

       if (e > 0)  // e>0时,始端y向加1,末端y向减1

       {

           y1++;

           y2--;

           e -= dx2;

       }

       //始端x向加1,末端x向减1

       x1++;

       x2--;

       e += dy2;

    }

2 两步算法

    两步画线算法每判断一次就生成两个点,这与对称算法相似,不同的是对称算法是从两端向中间进行的,而该算法是始终沿一个方向进行的,一次生成2个连续的点。当斜率k满足条件0k1时,考虑当前点P,如图1所示,直线与AB的交点一定落在AB区间的四等分中之一。

1 下一待选点位置必在四个等分区间之一

       实际上,两个连续点可能出现的形式只有四种情况,即DDDXXDXX。其中X表示沿水平方向移动一个像素,D表示沿对角方向移动一个像素,见图2

2 连续两点可能出现的4种形式

       决策量e的初值为e=4dy–dx,对于Pattern 1e的增量为4dy-4dx 对于Pattern 23e的增量为4dy-2dx;对于Pattern 4 e的增量为4dy算法用C++语言描述如下:

int x = m_start.m_x;  // 起点x

    int y = m_start.m_y;  // 起点y

    int dx = m_end.m_x - m_start.m_x;

    int dy = m_end.m_y - m_start.m_y;

    int dx2 = dx << 1;

    int dy2 = dy << 1;

    int dx4 = dx2 << 1;

    int dy4 = dy2 << 1;

    int inc4 = dy4 - dx4;

    int inc2 = dy4 - dx2;

   

    int e = dy4 - dx;

    pDC->SetPixel(x, y, color);

    for (int i=0; i<dx; i+=2)

    {  

       if (e > dx)

       {

           // Pattern 4

           if (e > dx2)

           {

              e += inc4;

              x++;

              y++;

              pDC->SetPixel(x, y, color);

              x++;

              y++;

              pDC->SetPixel(x, y, color);

           }

           // Pattern 3

           else

           {

              e += inc2;

              x++;

              y++;

              pDC->SetPixel(x, y, color);

              x++;

              pDC->SetPixel(x, y, color);

           }

          

       }

       else

       {

           // Pattern 2

           if (e > 0)

           {

              e += inc2;

              x++;

              pDC->SetPixel(x, y, color);

              x++;

              y++;

              pDC->SetPixel(x, y, color);

           }

           // Pattern 1

           else

           {

              x++;

              pDC->SetPixel(x ,y, color);

              x++;

              pDC->SetPixel(x, y, color);

              e += dy4;    

           }

       }  

    }  

    每计算一次e值就生成两个点,从而提高画线效率,但是要进行较多的判断,所以效率提高并不明显。

3 四步画线算法

    四步画线算法类似域两步画线算法,不同的时每判断一次,就生成四个点。如图3所示,直线一次前进四个点的情形。

3 四步画线算法示意图

       对于四步画线算法,规的跟两步算法相似的表示方法,共有14种形式,如图4

4 连续四点肯能出现的14种形式

       4中,自底向上依次是Pattern 1Pattern 14Pattern 1XXXXPattern 2XXXD,……,Pattern 14DDDD

       初始时,e=-dx Pattern 1e的增量为8dyPattern 2Pattern 4e的增量为8dy-2dxPattern 5Pattern 8e的增量为8dy-4dxPattern 9Pattern 13e的增量为8dy-6dxPattern 14e的增量为8dy-8dx。鉴于代码过长,这里不再给出。

4 自适应多步位移码画线算法

       与传统的直线算法不同,自适应多步位移码画线算法首先将待绘制直线表达成一串由01组成的位移码,根据位移码的特点,自适应的确定一次生成的像素数目,从而获得更高的绘制效率。这里引入两个引理:

       引理1 设有从(x1, y1)到(x2, y2)的直线,0Hy2-y1Kx2-x1。那么在该直线的位移码中,相邻两个1之间连续0的数目w[(K-H)/H][K/H][A]表示对A取整。

    引理2设有从(x1, y1)到(x2, y2)的直线,0Hy2-y1Kx2-x1。那么在该直线的位移码中,相邻两个0之间连续1的数目w[H/(K-H)][K/(K-H)]

       证明略。

这里给出自适应多步位移码画线算法的伪代码:

       K = x2 – x1;

       H = y2 – y1;

       T = [(K – 1)/2] – H;

       Divide(H, K – H, N, Tchg);

       x = x1;

       y = y1;

       WHILE x<= x2 DO

              IF T<0 THEN

                     y = y +1;

                     xend = x+N;

                     WHILE x<xend Do

                            DrawPixel(x, y);

                            x = x +1;

                     END WHILE

                     T = T+Tchg;

              ELSE

                     T = T – H;

                     DrawPixel(x, y);

              END IF

              x = x +1;

       END WHILE

       从理论而言,该算法根据直线斜率自适应地选择一个步长, 以一次判断生成多个采样点的方式对直线进行绘制,从而大大提供了绘制效率。但是实际上,连续两个10)中间01)的个数虽然只在两个整数上选择,但是到底在哪一步是哪一个难以判断,所以实现起来并不容易,而且目前尚未有解决方法。

算法效率

 

Bresenham

对称

两步

四步

加法

1

0.5

1

1

比较

2

1

1.5

1.3

加法和比较

3

1.5

2.5

2.3

乘法

2

3

4

6

       上表给出平均每步所进行的加法次数和比较次数,乘除次数是整算法总共的次数。DDA算法未在表中给出,它与Bresenham相似,但使用了多次浮点乘除运算和取整运算,效率明显低于其它算法。Bresenham与其它算法相比,加法步骤相当(对称算法除外),但比较次数较多。理论上而言,后面的算法效率较高。但是应该注意到多步算法,如两步和四步算法,在进行循环之前要做很多的初始化工作,而且乘除次数大于Bresenham算法。在进行较短直线绘制时,效率反而不如Bresenham算法快。

(一些算法的源程序较长,这里未给出。)

你可能感兴趣的:(c,算法,语言,化工)