(1)一步一步开发一个简单二维CAD之基本框架

在学校没事,所以开发一个具有基本功能的二维CAD,具有画线,画矩形,画圆,有捡选,平移,旋转,镜像,删除,实时放大,缩小,串行化的功能

 

首先谈架构,架构采用流行的MVC架构,也就是模型,视图,控制器的架购,模型包括数据和对数据的操作,而视图则是对模型的显示,控制器则是根据界面的操作.

 

 

(1)为了开发方便,首先开发了两个数学工具类,以便于使用

点类和包围盒类

 

class CBox2D;
class CPosition 
{
public:
 CPosition();
 CPosition(float x, float y);
 virtual ~CPosition();
public:
 float verdistance(CPosition &begin, CPosition &end);
 float Distance(const CPosition pos);
 BOOL  IsBox(const CBox2D &pox);
 CPosition Rotate(const CPosition &base, float angle);
 CPosition Explan(const CPosition &base, float scale);
 CPosition Mirror(CPosition &first, CPosition &second);
 CPosition Move(CPosition &first, CPosition &second);
 float AagleTox();
 void Get2Point(double circel[2]);
   
 CPosition operator-(CPosition pos);
 CPosition operator+(CPosition pos);
 void operator-=(CPosition pos);
 void operator+=(CPosition pos);
 CPosition operator*(float scale);

private:
 float m_x;
 float m_y;
};

class CBox2D
{
public:
 CBox2D();
 CBox2D(CPosition min, CPosition max);
 virtual ~CBox2D();
public:
 void GetExBox2D(float distance);//扩张包围
 

private:
 CPosition m_min;
 CPosition m_max;
};

两个类的实现如下

#define IP 3.1415926

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CBox2D::CBox2D()
{

}

CBox2D::~CBox2D()
{

}

CBox2D::CBox2D(CPosition min, CPosition max)
{
 m_min = min;
 m_max = max;
}

void CBox2D::GetExBox2D(float distance)//扩张包围盒,当直线是水平或者垂直的时候,不存在包围盒,所以要包围对角点平移,以适应这种情况
{
 m_min.m_x -= distance;
 m_min.m_y -= distance;

 m_max.m_x += distance;
 m_max.m_y += distance;
}


CPosition::CPosition()
{

}

CPosition::CPosition(float x, float y)
{
 m_x = x;
 m_y = y;

  
}
CPosition::~CPosition()
{

}

float CPosition::verdistance(CPosition &begin, CPosition &end)//利用三维叉集计算二维距离,Z坐标为0
{
    float a = fabsf( (m_x - begin.m_x) * (end.m_y - begin.m_y) - (m_y - begin.m_y) * (end.m_x - begin.m_x) );
    float b = sqrt( (end.m_x - begin.m_x) * (end.m_x - begin.m_x) + (end.m_y - begin.m_y) * (end.m_y - begin.m_y) );
 return a/b;
}

BOOL  CPosition::IsBox(const CBox2D &pox)
{
 if (m_x >= pox.m_min.m_x && m_y >= pox.m_min.m_y && m_x <= pox.m_max.m_x && m_y <= pox.m_max.m_y)
    return TRUE;
    else
    return FALSE;
}

CPosition CPosition::Rotate(const CPosition &base, float angle)//沿一点旋转angle度,逆时针为正
{
 
 float x = (m_x - base.m_x) * cos(angle) - (m_y - base.m_y) * sin(angle) + base.m_x;
 float y = (m_x - base.m_x) * sin(angle) + (m_y - base.m_y) * cos(angle) + base.m_y;
 
 return CPosition(x, y);
}

CPosition CPosition::Explan(const CPosition &base, float scale)
{
   *this = (*this - base) * scale + base;
      return *this;

}

CPosition CPosition::Move(CPosition &first, CPosition &second)//沿两点方向平移
{
    CPosition pos;
    pos = second - first;
    *this += pos;
    return *this;
}

CPosition CPosition::operator-(CPosition pos)
{
 return CPosition(m_x - pos.m_x, m_y - pos.m_y);
}

CPosition CPosition::operator+(CPosition pos)
{
   return CPosition(m_x + pos.m_x, m_y + pos.m_y);
}

void CPosition::operator-=(CPosition pos)
{
 m_x -= pos.m_x;
 m_y -= pos.m_y;

}

void CPosition::operator+=(CPosition pos)
{
 m_x += pos.m_x;
 m_y += pos.m_y;
}

float CPosition::Distance(const CPosition pos)
{
 return sqrt( (m_x - pos.m_x) * (m_x - pos.m_x) + (m_y - pos.m_y) * (m_y - pos.m_y) );
}

float CPosition::AagleTox()//
{
   
 float cosv = m_x/sqrt(m_x * m_x + m_y * m_y);
 float sinv = m_y/sqrt(m_x * m_x + m_y * m_y) ;

 if(sinv >= 0)
  return acos(cosv) ;
 else if(sinv < 0)
  return 2.*IP-acos(cosv) ;
 return FALSE ;
  
}

CPosition CPosition::operator*(float scale)
{
 return CPosition(m_x * scale, m_y * scale);
}

CPosition CPosition::Mirror(CPosition &first, CPosition &second)
{
     CPosition pos = (second - first) * ( 1 / second.Distance(first) );//镜像线单位化
     CPosition pos1 = *this - first;//第一起点和镜像点之间的矢量
  float pos2 = pos1.m_x * pos.m_x + pos1.m_y * pos.m_y;
  return (first + pos * pos2 ) * 2 - *this;
}  

 

世界坐标,也就是我们在现实中实际看到的物体的坐标

客户坐标,也就是我们屏幕客户区的坐标

我们一切点的坐标,必需在这两个坐标之间转换

这两个函数可以放在CView的派生类里面

 

void CMcadView::DPTOWP(CPoint &point, CPosition &pos)//m_base_x, m_base_y观察坐标系的基点坐标,m_scale是观察坐标和客户转换的系数
{  
 
 CRect rect;
 GetClientRect(&rect);


    pos.m_x = point.x * m_scale + m_base_x;
 pos.m_y = (rect.Height() - point.y) * m_scale + m_base_y;
}

void CMcadView::WPTODP(CPosition &pos, CPoint &point)
{
   CRect rect;
   GetClientRect(&rect);
 

   point.x = (int)(pos.m_x - m_base_x)/m_scale;
   point.y = rect.Height() - (int)(pos.m_y - m_base_y)/m_scale;
}

所有的一切鼠标在屏幕上的操作,必需用这两个函数转换成实际坐标,而所有的实际坐标屏幕上显示的时候,都必需转换为

屏幕坐标

 

原文地址:https://www.cnblogs.com/lizhengjin/p/1289119.html