MFC bresenham直线算法与MidPoint画圆的总结

来源:互联网 发布:淘宝买ps3是新机吗 编辑:程序博客网 时间:2024/06/07 15:50

首先看一下效果图!!

vs2017做的,我觉得跟vc6上做都是一样的。




在MFC的view.h头文件和view.cpp 里新建自己的函数,


void CMFC1View::Bresenhamline(int x0, int y0, int x1, int y1, int color)
{
 CDC *p;
 p = GetDC();
 int x, y, dx, dy, e;
 dx = x1 - x0;
 dy = y1 - y0;
 e = -dx;
 x = x0;
 y = y0;


 if ((dx >= 0 && dy >= 0) || (dx <= 0 && dy <= 0))    //如果k大于0
 {
  if ((dx<0) || (dx == 0 && dy<0))                       //dx小于0说明终点x
  {
   dx = -dx;//
   x = x1;//
   dy = -dy;
   y = y1;
  }
  if (dy<dx)                             //第一种情况,k-(0,1)//////////////
  {
   e = -dx;
   for (int i = 0;i<dx;i++)
   {
    p->SetPixel(x, y, color);
    x++;
    e = e + dy + dy;
    if (e >= 0)
    {
     y++;
     e = e - dx - dx;
    }
   }
  }
  else                                     //第二种情况,k-(1,max)
  {
   e = -dy;
   for (int i = 0;i<dy;i++)
   {
    p->SetPixel(x, y, color);
    y++;
    e = e + dx + dx;
    if (e >= 0)
    {
     x++;
     e = e - dy - dy;
    }
   }
  }
 }
 else                                            //如果k小于0
 {
  int tempx, tempy;    //保存x和y的绝对值
  if (dx<0)                //dx小于0说明终点x
  {
   tempx = -dx;
   tempy = dy;
  }
  if (dy<0)
  {
   tempx = dx;
   tempy = -dy;
  }
  if (tempx>tempy)                                //第三种情况,k-(-1,0)
  {
   if (dx<0)                       //dx小于0说明终点x
   {
    dx = -dx;
    x = x1;
    dy = -dy;
    y = y1;
   }
   e = -dx;
   for (int i = 0;i<dx;i++)
   {
    p->SetPixel(x, y, color);
    x++;
    e = e - dy - dy;
    if (e >= 0)
    {
     y--;
     e = e - dx - dx;
    }
   }
  }
  else                                     //第四种情况,k-(-1,min)
  {
   if (dy<0)//dx小于0说明终点x
   {
    dx = -dx;
    x = x1;
    dy = -dy;
    y = y1;
   }
   e = -dy;
   for (int i = 0;i<dy;i++)
   {
    p->SetPixel(x, y, color);
    y++;
    e = e - dx - dx;
    if (e >= 0)
    {
     x--;
     e = e - dy - dy;
    }
   }
  }
 }
}





在view.cpp里重载鼠标的左键按下和弹起两个函数,在view.h 定义公有的cpoint x1,x2;


void CMFC1View::OnLButtonDown(UINT nFlags, CPoint point)
{
 // TODO: 在此添加消息处理程序代码和/或调用默认值
 x1 = point;
 CView::OnLButtonDown(nFlags, point);
}

void CMFC1View::OnLButtonUp(UINT nFlags, CPoint point)
{
 // TODO: 在此添加消息处理程序代码和/或调用默认值
 x2 = point;
 Bresenhamline(x1.x,x1.y,x2.x,x2.y,255);//直接调用函数,不会重绘制,
 CView::OnLButtonUp(nFlags, point);
}



然后在鼠标弹起的函数里调用就行,也可以先调用invalidate()函数,invalidate()函数会自动调用ondraw()函数,区别是一个是ondraw()里调的后面的会覆盖前面的,直接调用的不会覆盖原来的画出来的直线或者圆。哪个都行,看你的需要。








void CMFC1View::OnDraw(CDC* pDC)
{
 CMFC1Doc* pDoc = GetDocument();
 ASSERT_VALID(pDoc);
 if(m_nshape==1)
 Bresenhamline(x1.x, x1.y, x2.x, x2.y, 255);//ondraw()里调用会覆盖前面画的图
 if (m_nshape == 2)
 {
  radius = (x2.y - x1.y)*(x2.y - x1.y) + (x2.x - x1.x)*(x2.x - x1.x);
  radius = sqrt(radius);
  MidPointCircle(x1.x, x1.y, radius, 255);
 }
  
 // TODO: 在此处为本机数据添加绘制代码
}


以上是直线的输出两种方法哪个都行。
--------------------------------------------------------------------------


直线的函数是可以直接调用的,但是圆的函数涉及到,求半径的问题,所以我在头文件的公有数据里定义了radius,方便直接调用,



圆的view.h  和view.cpp里定义两个函数。


int  CMFC1View::DrawPoint(int x0, int y0, int x, int y, int color)
{
 CDC *PDc = GetDC();
 PDc->SetPixel(x + x0, y + y0, 255);
 PDc->SetPixel(-x + x0, y + y0, 255);
 PDc->SetPixel(-x + x0, -y + y0, 255);
 PDc->SetPixel(x + x0, -y + y0, 255);
 PDc->SetPixel(y + x0, x + y0, 255);
 PDc->SetPixel(-y + x0, x + y0, 255);
 PDc->SetPixel(-y + x0, -x + y0, 255);
 PDc->SetPixel(y + x0, -x + y0, 255);
 return (0);
}
void CMFC1View::MidPointCircle(int x0, int y0, int radus, int color)
{
 int x, y, d;
 x = 0;y = radus;d = int(1.25 - radus);
 while (y >= x)
 {
  DrawPoint(x0, y0, x, y, color);
  if (d<0)
  {
   d = d + 2 * x + 3;x++;
  }
  else
  {
   d = d + 2 * (x - y) + 5;x++;y--;
  }
 }
}


圆的两个函数,一个是定义八分之一的圆,另一个函数负责画出对称点,


radius=sqrt((x2.y-x1.y)*(x2.y-x1.y)+(x2.x-x1.x)*(x2.x-x1.x));
记得加上#include<cmath>



再把圆心和半径传进去进行,
invalidate()这个函数会自动调用ondraw() 函数,
如果不涉及到菜单项就不用invalidate() 调用ondraw()函数,而是 直接在你需要的地方调用该函数就行。


希望对你有帮助,




0 0