直线绘制算法


   点在计算机中是组成图形的最基本元素,我们几何基本图形的绘制是一个个像素点按照一定规则排列而成的组成的。而复杂的图形是有基本几何图形组成的。所以基本图形的绘制算法,是学习计算机图形学的基础和关键。基本图形包括:直线,矩形,三角形

  直线是图形中最常见的,在解析几何中,二维坐标系中的直线的表达式是:y=k*x+b.

   由于显示器显示图形是像素点组成的,X轴坐标和Y轴坐标只能用整数表示。所以,不能可能每个点都满足直线表达式y=k*x+b,在计算机上只能用离散点来表示图形来。绘制直线的大致思路是在一条直线的周围找到离直线最近的像素点,这些像素点组成的图形离散的分布在直线周围,当分辨率达到人眼无法识别的时候,人眼看到就是一个连续的直线图形。如果直接用直线表达式y=k*x+b.来绘制直线,想象下当斜率>1时,锯齿状非常明显,极端情况下甚至不可见,下面介绍两种绘制直线的算法。

(一)DDA算法

  DDA算法是通过一个点满足的递推关系来得到第二个点的坐标的。

 

  直线表达式:y=k*x+b。

 

  设绘制图形是沿着直线一个端点一个点一个点绘制的,已经绘制第 i个点的坐标(x[i],y[i]), 则:

    斜率:k=(y[i+1]-y[i])/(x[i+1]-x[i]) => y[i+1]= y + k*(x[i+1]-x[i]) 

 

  当 k > =1 时 即:abs( x[i+1]-x[i])  ) > abs( x[i+1]-x[i])  ) 时 

    X[i+1]=X[i]+1

    y[i+1]=y+k

  当 K < 1 时 直线比较接近Y轴。所以要在Y的方向上增1.想象X轴和Y轴交换.

   Y[i+1]=Y[i]+1

   x[i]=x[i]+1/k

 

代码:

void DrawlineDDA(int x1,int y1,int x2,int y2)
{
	double length;
	if(abs(x1-x2)>abs(y1-y2))
		length=abs(x1-x2);
	else
		length=abs(y1-y2);
	double x=x1;
	double y=y1;
	double dx=(x2-x1)/length;
	double dy=(y2-y1)/length;
	int i=0;
	while (i<length)
	{
		glBegin(GL_POINTS);
		glColor3f(0,0,0);
		glVertex2i(int(x+0.5),int(y+0.5));
		glEnd();
		x=x+dx;
		y=y+dy;
		i++;
	}
	glFlush();
}

由于要进行很多浮点运算,所以为了改进效率,介绍下面的算法

 

(二) Bresenham算法

  Bresenham是比较主流的算法,很多主要的图形库软件直线算法都是用的Bresenham算法

 

如图

Bresenham 是通过 D1比较D2的长度来确定下一个点的位置

 

以K<1为例

当D1>D2时,下一个点应该是(X[i+1],y[i+1]).否则下一个点事(x[i+1],y[i]).

 

K<1 时,已知:X[i+1]=x[i]+1,y[i+1]=y[i]+1,x=x[i]+1

D1= y-y[i]   D2=y[i+1]-y

d1-d2 = 2y-y[i]-y[i+1]=2y-y[i]-(y[i]+1) = 2y-2y[i]-1 = 2*(k*x+b)-2y[i]-1 = 2kx-2y[i]-1+2b

          = 2k(x[i]+1)-2y[i]-1+2b

 

设dx=x2-x1,dy=y2-y1

e[i] =(d1-d2)*dx = dx*(d1-d2)=2k(x[i]+1)*dx -2y[i]*dx-dx+2b*dx

      = 2*dy*k*x[i]- 2y[i]*dx+2b*dx -dx +2*dy

 

常数C= 2b*dx -dx +2*dy

e[i]=2*dy*x[i]- 2y[i]*dx  (1)

e[i+1]=2*dy*x[i+1]- 2y[i+1]*dx (2)

 

e[i+1]-e[i] = 2*dy*(x[i+1]-x[i])-2dx(y[i+1]-y[i]) =>e[i+1]= e[i] + 2*dy*(x[i+1]-x[i])-2dx(y[i+1]-y[i])

 

结论: e[i+1]= e[i] + 2*dy - 2dx(y[i+1]-y[i])

 

dx=x2-x1>0.e[i]>0 => d1>d2  => y[i+1]=y[i]+1

e[i]<0   => d1 < d2  => y[i+1]=y[i]

 

得出:0 <  k < 1 的情况下

          e[i]>=0时 e[i+1]= e[i] + 2*dy - 2dx

           e[i]<0, e[i+1] = e[i] + 2*dy

           e 初始化 e=2*dy-dx

 

k 的其他情况可以由图形坐标的对称性得出。

 

代码

 

void Bresenham(int x1,int y1,int x2,int y2)
{
	int k=0;
    if((x2-x1)*(y2-y1)<0)//斜率为负数
	{
		k=1;
	}
	int x=x1,y=y1,dx=abs(x2-x1),dy=abs(y2-y1);
	bool f=0;
	
	if(dx<dy)//斜率绝对值大于1
	{
		f=1;
		swap(dx,dy);
		swap(x,y);
	}
	int e=2*dy-dx;
	glBegin(GL_POINTS);
	for(int i=0;i<dx;i++)
	{
		if(f==1)
			  glVertex2f(y,x);
		else
		      glVertex2f(x,y);
		
	        x++;
	
	  if(e>0)
	  {
		  e=e+2*(dy-dx);
		  if(k==0)
		  y++;
		  else
		  {
			  y--;
		  }
	  }
	  else
	  {
		   e=e+2*dy;
	  }
	}
	glEnd();
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值