您的位置:首页 > 其它

生成直线的Bresenham算法

2013-06-07 14:50 337 查看
在生成直线的算法中,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个象素点坐标为(xi,yi),它是直线上点(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)=2△y·xi-2△x·yi+c(2-11)
  式(2-11)中的△x=(x2-x1)>0,因此pi与(d1-d2)有相同的符号;

  这里△y=y2-y1,m=△y/△x;c=2△y+△x(2b-1)。

  下面对式(2-11)作进一步处理,以便得出误差判别递推公式并消除常数c。

  将式(2-11)中的下标i改写成i+1,得到:

pi+1=2△y·xi+1-2△x·yi+1+c(2-12)
  将式(2-12)减去(2-11),并利用xi+1=xi+1,可得:

pi+1= pi+2△y-2△x·(yi+1-yi)(2-13)
  再假设直线的初始端点恰好是其象素点的坐标,即满足:

y1=mx1+b(2-14)
  由式(2-11)和式(2-14)得到p1的初始值:

p1=2△y-△x(2-15)
  这样,我们可利用误差判别变量,得到如下算法表示:


初始     p1=2△y-△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+2△y

  从式(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)呢?

  设A为CD边的中点,正确的选择:

  若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=x1;x<=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算法特点:

  由于程序中不含实型数运算,因此速度快、效率高,是一种有效的画线算法。

  七、直线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;
 }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: