直线生成算法

直线生成算法:在光栅系统中绘制直线段,需要采用直线生成算法,常用的有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算法,把两算法结合一起用了,通过几何运算处理,结果并未完全按我想象中的一样,而且利于了* / 运算 使得算法效率下降。有待改进……

看下运行效果:

直线生成算法_第1张图片

你可能感兴趣的:(算法,application,mfc,float,2010)