【寒江雪】计算机图形学直线算法

DDA Algorithm

由于计算机在绘制直线时,需要计算每一个点的纵坐标y的值,由y=kx+b可以枚举x计算y的值得直线上的离散的点。

Y0=kx0+b

Y1=kx1+b=k(x0+1)+b

Y1-y0=k

由此可转换为迭代式,乘法变加法。

的代码实现:

DDA(int x1,int y1,int x2,int y2,){

       floatdx=x1-x2;

       floatdy=y1-y2;

       floatk=dx/dy;

       floaty=y1;

       for(inti=x1;i<=x2;i++){

              drawPoint(i,(int)(y+0.5));

              y=y+k;

}

      

}

但是DDA算法还需要四舍五入,于是就有人希望能通过一定的方法省略掉四舍五入的步骤。

Bresenham算法应运而生

算法思路:

       Y=kx+b是该条直线的表达式。Y和x都是实数,但是为了迁就计算机,我们人为地将x取整,计算y值。X为整数之后,计算出来的y并不一定都为整数,需要四舍五入。但这个算法是如何避免四舍五入的呢?为了解释清楚这个问题,首先定义:通过y=kx+b计算得到的y称为y的实值。而我们用来描点的y值称为y的虚值。y的虚值是y的实值四舍五入的结果。在算法开始时,要计算k的大小,用于迭加。初始时,y的虚值与y的实值可以不加以证明它们相等,且都等于y0。另外,这个算法还有一个最关键的地方,那就是中点。什么中点呢?就是y的虚值与比其大1的值(即(y虚)和(y虚+1))的中点。这个中点是比实值大的,如果y的增长比该中点大,y的实值在四舍五入的时候向上取整,这时候y的虚值就会加1

       而这个算法最精妙的地方就是,整个过程中y的实值一直没有出现,从而不会有四舍五入的过程。其中的中点也没有出现,只是换了另外一个说法,那就是差值。

       什么差值?中点指目标整数与当前整数的中点,差值就是实际值-该中点得到的差值,为负数。当这个差值小于0的时候,说明实际值还没有超过它,y的实值该舍去小数,得到的即为当前虚值。当这个差值大于0的时候,说明实际值已经超过了它,y的实值该五入了,这时候就要更新当前虚值,使其递增1。这个差值还有一个特点,根据DDA算法,在每一轮的迭加中,y的实值都递增k,也就意味着y的实值距离那个神奇的中点接近了k的距离。那么差值就会增加,而且也会增加k(记住,是y的实际值减去那个中点得到的,中点的值永远比y的实际值大)。因此我们只需要迭加这个差值,当差值大于0的时候,说明y的实值已经超过了这个中点,y的虚值应该递增了,新的中点要出现了。为了下一轮的迭代,我们需要计算新的差值。假设当前差值为e且e>0,当前中点值为m,当前y的实际值为y,y-m=e. 新的中点值为q(新的虚值与新的目标整数的中点),此时q-m=1。由这两个式子得y-q=e-1。这样,我们就可以更新e=e-1,得到新的差值,再继续进行迭代。

代码实现如下:

Bresenham(int x1,int y1,int x2,int y2){

       floatdx=x1-x2;

       floatdy=y1-y2;

       floatk=dy/dx;

       inty=y1;//刚开始y的虚值

       floate=-0.5f;//最初的差值为0.5

       for(inti=x1;i<=x2;i++){

              drawPoint(I,y);

              e=e+k;

              if(e>=0){

                     e=e-1;

                     y++;

}

}

}

以上解释如有不明白的欢迎来信讨论——211392413@qq.com 

 

算法优化到这一步,我们还希望算法中少一点浮点数的运算。该怎么办呢?

观察式子

e=e+k;

      而e的初始值是-0.5,即二分之一。为了消去小数,需要两边乘以2,但是这么做并不能保证,k也会变为整数。那么两边必须同乘以一个数使k和e都变为整数。

观察e,初始值为二分之一,观察k,其值为dy/dx.而dy与dx都为整数。

将二分之一与dy/dx通分。得到dx/2dx和2dy/2dx,只要e和k通分,得

e=-(dx/2dx) k=(2dy/2dx)。这样一来,原本浮点数的运算,这样,迭加过程可以稍作改变。初始化e为-dx,每次迭加增加2dy,当e大于0的时候减2dx即可

代码如下:

Bresenham(int x1,int y1,int x2,int y2){

       Intdx=x2-x1;

       Intdy=y2-y1;

       Inte=-dx;

       Inty=y1;

For(inti=x1;i<=x2;i++){
       DrawPoint(I,y);

       e=e+dy+dy;

       if(e>=0){

              e=e-(dx+dx);

              y++;

}

}

}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值