直线生成算法:在光栅系统中绘制直线段,需要采用直线生成算法,常用的有DDA算法、Bresenham算法等。
Ø DDA直线生成算法是一种使用微分方程生成直线的算法,又称作数值微分法。该算法的基本思想是:根据斜率确定增量最大的方向,每次迭代时均在该方向上走一步,然后根据直线方程计算出另一方向上的值,对其四舍五入后得到像素坐标。
Ø Bresenham直线生成算法与DDA算法类似,每次迭代时均在增量最大方向上走一步,并计算决策参数,根据决策参数确定像素坐标。算法的巧妙之处在于采用了增量计算,使得对于每一列,只要检查误差量的符号,就可以确定该下一列的像素坐标。
ok 我们可以有四种不同创建项目方法来实现算法,包括vs2010下创建MFC程序,win32 Application,控制台程序(注:如果用它的话还需要下载openGL库文件, 下载链接:http://download.csdn.net/detail/qiushuiqifei/4136616
具体在vs2010配置操作链接:http://apps.hi.baidu.com/share/detail/55613195),还有就是Dev-c++下创建,这些都差不多,在这里我选择win 32 Application
1.创建一个win 32 Application项目,项目名为“20101620113_1”
2.找到20101620113_1.cpp文件 在该文件下操作
3.找到下面代码行
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: 在此添加任意绘图代码...
EndPaint(hWnd, &ps);
break;
4.下面主要介绍算法
//----------------------------------------------------------------------------------------------------
//绘制指定宽度点
void DrawPixel(HDC hDC,int x,int y,int width,int color)
{
if(width<1)
return;
else
for(int i=0;i<=width;i++)
{
SetPixel(hDC,x,y-i,color);
}
}
template<typename T>
void Breasenham_line(HDC hDC,T x00,T y00,T x11,T y11,int width,int color)
{
int x0=int(x00+0.5);
int y0=int(y00+0.5);
int x1=int(x11+0.5);
int y1=int(y11+0.5);
int dx,dy,e,i,x,y;
dx=x1-x0;
dy=y1-y0;
x=x0;
y=y0;
//----------------------------------------------------------------------------------------------------
//当 y0=y1 即平行x轴 单独处理
if(y0==y1)
{
if(x1>=x0)
{
for(i=0;i<abs(dx);i++)
{
//
DrawPixel(hDC,x,y,width,color);
//SetPixel(hDC,x,y,color);
//pDC->SetPixel(x,y-1,color);
x++;
}
}
else
{
for(i=0;i<=abs(dx);i++)
{
DrawPixel(hDC,x,y,width,color);
x--;
}
}
}
//----------------------------------------------------------------------------------------------------
//当 x0=x1 即平行y轴 单独处理
if(x0==x1)
{
if(y1>=y0)
{
for(i=0;i<=abs(dy);i++)
{
for(int i=0;i<=width;i++)
{
SetPixel(hDC,x-i,y,color);
}
y++;
}
}
else
{
for(i=0;i<=abs(dy);i++)
{
for(int i=0;i<=width;i++)
{
SetPixel(hDC,x-i,y,color);
}
y--;
}
}
}
//----------------------------------------------------------------------------------------------------
//当x0<x1&& y0<y1 即在第一象限的直线处理
if(x0<x1 && y0<y1)
{
//当斜率小于1且大于0时
if((y1-y0)/(x1-x0)<1)
{
e=2*dy-dx;
for(i=0;i<abs(dx);i++)
{
DrawPixel(hDC,x,y,width,color);
x++;
e+=2*dy;
if(e>=0)
{
y++;
e-=2*dx;
}
}
}
//当斜率大于等于1时
else
{
e=2*dx-dy;
for(i=0;i<=abs(dy);i++)
{
DrawPixel(hDC,x,y,width,color);
y++;
e+=2*dx;
if(e>=0)
{
x++;
e-=2*dy;
}
}
}
}
//--------------------------------------------------------------------------------------------------------
//当x0>x1 && y0<y1 在第二象限的直线处理
if(x0>x1 && y0<y1)
{
/* 由对称的性质易知与在第一象限的直线关于y轴对称
故只需将上一段代码稍微更改,把与x有关的变量改为它的相反数
*/
//斜率小于-1
if(dy/dx<-1)
{
e=-2*dx-dy;
for(i=0;i<abs(dy);i++)
{
DrawPixel(hDC,x,y,width,color);
y++;
e-=2*dx;
if(e>0)
{
x--;
e-=2*dy;
}
}
}
//斜率大于等于-1小于0
else
{
e=2*dy+dx;
for(i=0;i<=abs(dx);i++)
{
DrawPixel(hDC,x,y,width,color);
x--;
e+=2*dy;
if(e>=0)
{
y++;
e+=2*dx;
}
}
}
}
//--------------------------------------------------------------------------------------------------------
//当x0>x1 && y0>y1 即第三象限的直线处理
if(x0>x1 && y0>y1)
{
/* 由对称的性质易知与在第一象限的直线关于原点对称
故只需将上一段代码稍微更改,把与x,y有关的变量改为它的相反数
*/
//斜率小于1
if((y1-y0)/(x1-x0)<1)
{
e=-2*dy+dx;
for(i=0;i<abs(dx);i++)
{
DrawPixel(hDC,x,y,width,color);
x--;
e-=2*dy;
if(e>=0)
{
y--;
e+=2*dx;
}
}
}
//斜率大于等于1
else
{
e=-2*dx+dy;
for(i=0;i<=abs(dy);i++)
{
DrawPixel(hDC,x,y,width,color);
y--;
e-=2*dx;
if(e>=0)
{
x--;
e+=2*dy;
}
}
}
}
//--------------------------------------------------------------------------------------------------------
//当x0<x1 && y0>y1 即第四象限的直线处理
if(x0<x1 && y0>y1)
{
/* 由对称的性质易知与在第一象限的直线关于x轴对称
故只需将上一段代码稍微更改,把与x,y有关的变量改为它的相反数
*/
//斜率小于-1
if(dy/dx<-1)
{
e=2*dx+dy;
for(i=0;i<abs(dy);i++)
{
DrawPixel(hDC,x,y,width,color);
y--;
e+=2*dx;
if(e>0)
{
x++;
e+=2*dy;
}
}
}
//斜率大于等于-1
else
{
e=-2*dy-dx;
for(i=0;i<=abs(dx);i++)
{
DrawPixel(hDC,x,y,width,color);
x++;
e-=2*dy;
if(e>=0)
{
y--;
e-=2*dx;
}
}
}
}
}
//------------------------------------------------------------------------------------------
//利用DDA算法和Bresenham算法结合对线的端点进行改进
void DDAAndBreasenham_line(HDC hDC,int x0,int y0,int x1,int y1,int width,int color)
{
int i;
float dx,dy,length,x,y;
if(abs(x1-x0)>=abs(y1-y0))
length=abs(x1-x0);
else
length=abs(y1-y0);
dx=(x1-x0)/length;
dy=(y1-y0)/length;
float k=dy/dx;
i=1;
x=x0;
y=y0;
while(i<=length)
{
//主要利用边线互相垂直的特点进行设计
Breasenham_line(hDC,x,y,x+(k*width)/(k*k+1),y+width/(k*k+1),1,color);
x+=dx;
y+=dy;
i++;
}
}
注释我写得挺详细的 但这里再多几嘴 对于Bresenham_line函数主要是分情况讨论,然后利用对称特性 故只要计算第一象限的直线生成算法,其他象限可以可以利用与第一象限的直线对称得出,这里利用函数模板只是为了兼容float类型(即坐标为浮点的支持)。而对于DDAAndBreasenham_line函数这是改进算法,主要处理有宽度的直线边界,使之不是尖形,这里混合了DDA算法和Bresenham算法,把两算法结合一起用了,通过几何运算处理,结果并未完全按我想象中的一样,而且利于了* / 运算 使得算法效率下降。有待改进……
看下运行效果: