您的位置:首页 > 其它

直线的生成算法

2010-10-31 12:32 295 查看
转自:/content/3534744.html

光栅显示器的荧光屏上生成一个对象,实质上是往帧缓存寄存器的相应单元中填入数据。画一条从(x1, y1)到(x2, y2)的直线,实质上是一个发现最佳逼近直线的象素序列,并填入色彩数据的过程。这个过程也称为直线光栅化。

直线的DDA算法
DDA是数字微分分析式(Digital Differential Analyzer)的缩写。设直线之起点为(x1,y1),终点为(x2,y2),则斜率m为:
m = (y2-y1)/(x2-x1)=dy/dx

直线中的每一点坐标都可以由前一点坐标变化一个增量(Dx, Dy)而得到,即表示为递归式:
xi+1=xi+Dx
yi+1=yi+Dy
并有关系:Dy = m · Dx
递归式的初值为直线的起点(x1, y1),这样,就可以用加法来生成一条直线。具体方法是:
 
图2.1.1 直线方向的8个象限



表2.1.1

象限

|dx|>|dy|?
D x
D y
1a
1b
2a
2b
3a
3b
4a
4b
Ö
´
Ö
´
Ö
´
Ö
´
1
1/m
-1
-1/m
-1
-1/m
1
1/m
m
1
m
1
-m
-1
-m
-1
按照直线从(x1,y1)到(x2,y2)的方向不同,分为8个象限(图2.1.1)。对于方向在第1a象限内的直线而言,D x=1,D y=m。对于方向在第1b象限内的直线而言,取值Dy=1,Dx=1/m。各象限中直线生成时Dx, Dy的取值列在表2.1.1之中。
研究表中的数据,可以发现两个规律:
1、当|dx|>|dy|时
|D x|=1, |D y|=m;
否则:
Dx=1/m,|Dy|=1
 
2、Dx, Dy的符号与dx, dy的符号相同。
这两条规律可以导致程序的简化。由上述方法写成的程序如程序2.1.1所示。其中steps变量的设置,以及D x=dx/steps; D y=dy/steps等语句,正是利用了上述两条规律,使得程序变得简练。
使用DDA算法,每生成一条直线做两次除法,每画线中一点做两次加法。因此,用DDA法生成直线的速度是相当快的。


#include <stdlib.h>




#include <math.h>




inline int round(const float a)

{return int(a+0.5);}








void lineDDA(int xa, int ya, int xb, int yb,int c)








{




float delta_x, delta_y, x, y;




int dx, dy, steps, k;




dx=xb-xa;




dy=yb-ya;




if (abs(dx)>abs(dy)) steps=abs(dx);




else steps=abs (dy);




delta_x=(float)dx / (float)steps;




delta_y=(float)dy / (float)steps;




x=xa;




y=ya;




set_pixel(x, y, c);




for (k=1; k<=steps; k++)








{




x+=delta_x;




y+=delta_y;




set_pixel(x, y, c);




}




}




程序2.1.1 DDA直线生成程序







直线的Bresenham算法

本算法由Bresenham在1965年提出。设直线从起点(x1, y1)到终点(x2, y2)。直线可表示为方程y=mx+b。其中
b = y1 - m * x1,
m = (y2-y1)/(x2-x1)=dy/dx

我们的讨论先将直线方向限于1a象限(图2.1.1)在这种情况下,当直线光栅化时,x每次都增加1个单元,即
xi+1=xi+1。而y的相应增加应当小于1。为了光栅化,yi+1只可能选择如下两种位置之一。

yi+1的位置选择yi+1=yi 或者 yi+1=yi+1。选择的原则是看精确值y与yi及yi+1的距离d1及d2的大小而定。计算式为:
y=m(xi+1)+b (2.1.1)
d1=y-yi (2.1.2)
d2=yi+1-y (2.1.3)

如果d1-d2>0,则yi+1=yi+1,否则yi+1=yi。因此算法的关键在于简便地求出d1-d2的符号。将式(2.1.1)、(2.1.2)、(2.1.3)代入d1-d2,得
d1-d2=2y-2yi-1=2(dy/dx) (xi+1)-2yi+2b-1

用dx乘等式两边,并以Pi=dx(d1-d2)代入上述等式,得
Pi=2xidy-2yidx+2dy+dx(2b-1) (2.1.4)

d1-d2是我们用以判断符号的误差。由于在1a象限,dx总大于0,所以Pi仍旧可以用作判断符号的误差。Pi-1为:
Pi+1=Pi+2dy-2dx(yi+1-yi) (2.1.5)
误差的初值P1,可将x1, y1,和b代入式(2.1.4)中的xi, yi而得到:
P1=2dy-dx

综述上面的推导,第1a象限内的直线Bresenham算法思想如下:
 
1、画点(x1, y2); dx=x2-x1; dy=y2-y1;
计算误差初值P1=2dy-dx; i=1;

2、求直线的下一点位置:
xi+1=xi+1;
if Pi>0 则yi+1=yi+1;
否则yi+1=yi;

3、画点(xi+1, yi-1);

4、求下一个误差Pi+1;
if Pi>0 则Pi+1=Pi+2dy-2dx;
否则Pi+1=Pi+2dy;

5、i=i+1; if i<dx+1则转2;否则end。

Bresenham算法的优点是:
1、不必计算直线之斜率,因此不做除法;

2、不用浮点数,只用整数;

3、只做整数加减法和乘2运算,而乘2运算可以用硬件移位实现。

Bresenham算法速度很快,并适于用硬件实现。
 
由上述算法思想编制的程序如程序2.1.2。这个程序适用于所有8个方向的直线(图2.1.1)的生成。程序用色彩C画出一条端点为(x1, y1)和(x2, y2)的直线。其中变量的含义是:P是误差;const1和const2,是误差的逐点变化量;inc是y的单位递变量,值为1或-1;tmp是用作象限变换时的临时变量。程序以判断|dx|>|dy|为分支,并分别将2a, 3a象限的直线和3b, 4b象限的直线变换到1a, 4a和2b, 1b方向去,以求得程序处理的简洁。

作者:洞庭散人

出处:http://phinecos.cnblogs.com/    

本博客遵从Creative Commons Attribution 3.0 License,若用于非商业目的,您可以自由转载,但请保留原作者信息和文章链接URL。


void line (int x1, y1, x2, y2, c)






{


int dx;


int dy;


int x;


int y;


int p;


int const1;


int const2;


int inc;


int tmp;


dx=x2-x1;


dy=y2-y1;




if (dx*dy>=0) /**//*准备x或y的单位递变值。*/


inc=1;


else


inc=-1;




if (abs(dx)>abs(dy))

{




if(dx<0)

{




tmp=x1; /**//*将2a, 3a象限方向*/




x1=x2; /**//*的直线变换到1a, 4a*/


x2=tmp;




tmp=y1; /**//*象限方向去*/


y1=y2;


dx=-dy;


dy=-dy;


}


p=2*dy-dx;




const1=2*dy; /**//*注意此时误差的*/




const2=2*(dy-dy); /**//*变化参数取值. */


x=x1;


y=y1;


set_pixel(x, y, c);




while (x<x2)

{


x++;


if (p<0)


p+=const1;




else

{


y+=inc;


p+=const2;


}


set_piexl(x, y, c);


}


}




else

{




if (dy<0)

{




tmp=x1; /**//* 将3b, 4b象限方向的*/




x1=x2; /**//*直线变换到2b, 1b */




x2=tmp; /**//*象限方向去. */


tmp=y1;


y1=y2;


dx=-dy;


dy=-dy;


}




p=2*dx-dy; /**//*注意此时误差的*/




const1=2*dx; /**//*变化参数取值. */


const2=2*(dx-dy);


x=x1;


y=y1;


set_pixel (x, y, c);




while (y<y2)

{


y++;


if(p<0)


p+=const1;




else

{


x+=inc;


p+=const2;


set_pixel (x, y, c);


}


}


}


 


程序2.1.2 适用于直线所有八个方向的Bresenham直线生成算法

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: