DDA(数值微分)算法画直线(三)

2 直    线    

    数学上,理想的直线是由无数个点构成的集合,没有宽度。计算机绘制直线是在显示器所给定的有限个像素组成的矩阵中,确定最佳逼近该直线的一组像素,并且按扫描线顺序,对这些像素进行写操作,实现显示器绘制直线,即通常所说的直线的扫描转换,或称直线光栅化。由于一个图形中可能包含成千上万条直线,所以要求绘制直线的算法应尽可能地快。本节介绍一个像素宽直线的常用算法:数值微分法(DDA)、中点画线法、Bresenham    算法。

2.2.1  DDA(数值微分)算法

(1)  DDA算法原理:

问题:如图1-1所示,已知过端点P0(x0, y0) ,P1 ( x1, y1)的直线段为P0P1,则直线斜率为k=( y1- y0)/ ( x1- x0),要在输出设备上显示该直线段,我们需要计算出经过该直线段P0P1上所有像素点的集合。

根据几何知识,我们只需要将x从左端点x0开始,向右端点x1步进,步长=1(个像素),将x代入直线方程 y=kx+B 计算出相应的坐标即可;

这里有一个问题那就是,我们x的取值是离散的,但是计算出来的y值不一定是整数,所以需要我们对y进行四舍五入,像素点 [x, round(y)] 作为当前点的坐标。

(2)  代码实现:

根据上面的分析,我们开始编写代码,首先我们在the_application类中增加四舍五入取整函数

  //四舍五入为整数

       int Round(float f)

       {

              return int(f+0.5);

       }

在直线的斜截式方程中,我们知道k=( y1- y0)/ ( x1- x0),但是我们还缺少B,这里我们还需要从直线的两点式方程中推导出B的值。下面我们一起推导下,以帮助大家熟悉下还给数学老师的知识:

(y - y0)/( y1- y0)=(x- x0)/( x1- x0) 

y ( x1- x0)= (x- x0) ( y1- y0)+y0( x1- x0)

y ( x1- x0)= ( y1- y0)x-( y1- y0) x0+y0( x1- x0)

y ( x1- x0)= ( y1- y0)x +y0 x1- y1 x0

因此直线截矩B=( y0 x1- y1 x0)/ ( x1- x0),k=( y1- y0)/ ( x1- x0),实现数值微分法画直线的代码如下:

//该算法仅仅适应于|k|<=1,传递参数时,必须x0<=x1
void DDALine(int x0,int y0,int x1,int y1,COLORREF color)    
{ 
	float y, k, b,dx;
	dx = x1-x0;  

	//计算直线斜率
	k=(y1-y0)/dx;

	//计算B
	b= (y0*x1-y1*x0)/dx;         

	for (intx=x0;x<=x1;x++)
	{
		DrawPixel(x,Round(y),color);
		y=k*x+b;
	}
}

(3)  代码优化:

我们回过头来看,在我们的代码中存在一次乘法运算,大家都知道乘法指令是比较占用cpu资源,当系统需要渲染大量的直线段时,造成的效率低下是无法估算的。

我们考虑下看能不能优化掉该条乘法指令,由于直线方程是线性的,可以考虑用增量方式来优化,即当x每递增1,y递增k(即直线斜率),数学推导如下:

yi+1  = k (xi+1)+B

= k xi+B+ k

= yi+ k

     按照我们的分析,我们经过优化后DDALine函数,代码如下:

//该算法仅仅适应于|k|<=1,传递参数时,必须x0<=x1
void DDALine(int x0,int y0,int x1,int y1,COLORREF color)    
{ 
	float y, k, dx;

	//计算直线斜率
	dx = x1-x0;  
	k=(y1-y0)/dx; 

	y=y0; 
	for (int x=x0;x<=x1;x++)
	{
		DrawPixel(x,Round(y),color);
		y+=k;
	}
}

(4)  算法分析:

根据上面的理论分析,我们知道x每递增一个像素,y递增k个像素。

当|k|>1时,x是按1步进的,因此x在整数范围内时连续,但是y将不再连续,这样导致我们画出来的直线就成了虚线,如下图所示:

 

当|k|<=1时,在这种情况下,x每增加1,y最多增加1,此时x,y在整数范围内都是连续的,所以我们画出的直线没有问题,因此我们上述的算法仅适用于|k|<=1。

那么当|k|>1时,我们该怎么办了?其实也简单,我们把x,y地位互换,这样y每增加1,x相应增加|1/k|,此时 |Dx|<=1也是成立的。具体代码实现就不写,这里我们主要理解算法原理就可以了。

(5)  运行效果截图:

     下载工程代码狂击鼠标

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

莫_问

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值