主从滑块机构的运动仿真程序

嘻嘻~纪录一下人生中第一个正儿八经的小作品也是C++课程的结课作业
在老师给的文件基础上,在网上找了些资料,与宿友一起讨论研究,互帮互助,总算做成
然后写这篇东西的时候又从头到尾的重做了一遍

目的与要求
用文档/视图结构开发一个主从滑块机构的运动仿真程序。
在这里插入图片描述
功能目标描述:
1)按A键,主动块向左运动,带动从动块上下运动
按D键,主动块向右运动,带动从动块上下运动
2)对连杆中点进行轨迹分析(通过菜单启动和关闭分析功能)

一、确定所需的主要数据(数据结构)
新建工程MFC AppWizare(exe),工程名称命名为HuaKuai,选择单文档工程
在Doc类中定义以下函数及变量

public:

 void CalPosition();
 double dX;       //主动块与参考原点的距离
 double i,j;
 double L,W;      //连杆的长度和宽度
 double L1,W1;    //主动块的长度和宽度
 double L2,W2;    //主动块的长度和宽度
 int k;
 bool judge;
 CPoint xian1[2]; //画辅助线
 CPoint xian2[2];
 CPoint Gui1[4];  //画主动导轨两条线的四个点
 CPoint Gui2[4];  //画主动导轨两条线的四个点
 CPoint Kuai1[4]; //主动块四边形的四点
 CPoint Kuai2[4]; //从动块四边形的四点
 CPoint Gan[4];   //杆
 CPoint Path[520]; 
 CPoint Origin;   //主动导轨的中点,机械机构的参考原点,程序中定为横向的中间、竖向的1/3处
 CPoint Circle1[2]; 
 CPoint Circle2[2]; 
 
virtual ~CHuaKuaiDoc();

二、对不需要变化的数据进行初始化

BOOL CHuaKuaiDoc::OnNewDocument()
{
 if (!CDocument::OnNewDocument())
  return FALSE;
  
 // TODO: add reinitialization code here
 // (SDI documents will reuse this document)
 //对不需要变化的数据初始化
 L = 100;   //连杆长度
 W = 10;    //连杆宽度
 L1 = 30;   //主动块长度
 W1 = 25;   //主动块宽度
 L2 = 25;   //从动块长度
 W2 = 30;   //从动块宽度
 
 Origin = CPoint(0,0);  //暂时初始化为(0,0)点,一会要根据窗口实际情况变化

//dX开始时为0,dX是要变化的
 dX = 0;
 i = -100;
 j = 0;
 k=0;
 judge=true;
 
return TRUE;
}

三、计算各个时刻变化的数据
因为sqrt和pow是math中的函数,所以在Doc类中要添加头文件如下

#include <math.h>

由于CalPosition()函数是自定义的函数,所以若点击Doc类下方的CalPosition()会弹出“cannot find the definition (implementation) of this function ”的对话框
所以直接在Doc类的头文件所在窗口的最下方加入以下代码

void CHuaKuaiDoc::CalPosition()
{
 //计算主动导轨四点的位置
 Gui1[0].x = (int)(Origin.x - L - 10 + 0.5);  //(int)(*** + 0.5)是四舍五入
 Gui1[0].y = (int)(Origin.y - W1/2 + 0.5);
 Gui1[1].x = (int)(Origin.x + L + 10 + 0.5);
 Gui1[1].y = (int)(Origin.y - W1/2 + 0.5);
 Gui1[2].x = (int)(Origin.x - L - 10 + 0.5);
 Gui1[2].y = (int)(Origin.y + W1/2 + 0.5);
 Gui1[3].x = (int)(Origin.x + L + 10 + 0.5);
 Gui1[3].y = (int)(Origin.y + W1/2 + 0.5);
 
 //计算主动块位置
 Kuai1[0].x = (int)(Origin.x +dX - L1/2 + 0.5);
 Kuai1[0].y = (int)(Origin.y - W1/2 + 0.5);
 Kuai1[1].x = (int)(Origin.x +dX + L1/2 + 0.5);
 Kuai1[1].y = (int)(Origin.y - W1/2 + 0.5);
 Kuai1[2].x = (int)(Origin.x +dX + L1/2 + 0.5);
 Kuai1[2].y = (int)(Origin.y + W1/2 + 0.5);
 Kuai1[3].x = (int)(Origin.x +dX - L1/2 + 0.5);
 Kuai1[3].y = (int)(Origin.y + W1/2 + 0.5);

 //计算从动导轨四点的位置
 Gui2[0].x = (int)(Origin.x - W2/2 + 0.5);   
 Gui2[0].y = (int)(Origin.y + 32);
 Gui2[1].x = (int)(Origin.x + W2/2 + 0.5);
 Gui2[1].y = (int)(Origin.y + 32);
 Gui2[2].x = (int)(Origin.x - W2/2 + 0.5);
 Gui2[2].y = (int)(Origin.y + L/2 + 200);
 Gui2[3].x = (int)(Origin.x + W2/2 + 0.5);
 Gui2[3].y = (int)(Origin.y + L/2 + 200);

 //计算从动块位置
 Kuai2[0].x = (int)(Origin.x - W2/2 + 0.5);
 Kuai2[0].y = (int)(Origin.y + L- W2/2-(L-sqrt(pow(L,2)-pow(dX,2))));
 Kuai2[1].x = (int)(Origin.x + W2/2 + 0.5);
 Kuai2[1].y = (int)(Origin.y + L- W2/2-(L-sqrt(pow(L,2)-pow(dX,2))));
 Kuai2[2].x = (int)(Origin.x + W2/2 + 0.5);
 Kuai2[2].y = (int)(Origin.y + L+ W2/2-(L-sqrt(pow(L,2)-pow(dX,2))));
 Kuai2[3].x = (int)(Origin.x - W2/2 + 0.5);
 Kuai2[3].y = (int)(Origin.y + L+ W2/2-(L-sqrt(pow(L,2)-pow(dX,2))));
 
 //计算杆位置
 Gan[0].x = (int)(Origin.x + dX - W * sqrt(pow(L,2)-pow(dX,2))/(2*L));
 Gan[0].y = (int)(Origin.y - W * dX /(2*L));
 Gan[1].x = (int)(Origin.x + dX + W * sqrt(pow(L,2)-pow(dX,2))/(2*L));
 Gan[1].y = (int)(Origin.y + W * dX /(2*L));
 Gan[2].x = (int)(Origin.x + (W * sqrt(pow(L,2)-pow(dX,2))/(2*L)));
 Gan[2].y = (int)(Origin.y + sqrt(pow(L,2)-pow(dX,2)) + W * dX/(2*L));
 Gan[3].x = (int)(Origin.x - (W * sqrt(pow(L,2)-pow(dX,2))/(2*L)));
 Gan[3].y = (int)(Origin.y + sqrt(pow(L,2)-pow(dX,2)) - W * dX/(2*L));
  
  //计算圆位置
 Circle1[0].x = (int)(Origin.x + dX - W/2 );
 Circle1[0].y = (int)(Origin.y -  W/2 );
 Circle1[1].x = (int)(Origin.x + dX + W/2 +1.5);
 Circle1[1].y = (int)(Origin.y + W/2 +1.5);

 Circle2[0].x = (int)(Origin.x - W/2 );
 Circle2[0].y = (int)(Origin.y + sqrt(pow(L,2)-pow(dX,2)) -  W/2 );
 Circle2[1].x = (int)(Origin.x + W/2 +1.5);
 Circle2[1].y = (int)(Origin.y + sqrt(pow(L,2)-pow(dX,2)) + W/2 +1.5);
 
 //计算辅助线位置
 xian1[0].x = (int)(Origin.x - L - 10 - 6); 
 xian1[0].y = (int)(Origin.y );
 xian1[1].x = (int)(Origin.x + L + 10 + 6);
 xian1[1].y = (int)(Origin.y );
 xian2[0].x = (int)(Origin.x  ); 
 xian2[0].y = (int)(Origin.y -50);
 xian2[1].x = (int)(Origin.x  );
 xian2[1].y = (int)(Origin.y + L + 200 );

 if(judge==false)
 {
  Path[k].x = int((Gan[1].x + Gan[3].x)/2);
  Path[k].y = int((Gan[1].y + Gan[3].y)/2);
  k+=1;
 }

}

四、画图

void CHuaKuaiView::OnDraw(CDC* pDC)
{
 CPen penThick,pen,pen1, *oldpen;
 CHuaKuaiDoc* pDoc = GetDocument();
 ASSERT_VALID(pDoc);
 // TODO: add draw code for native data here
 //先确定参考原点的位置
 CRect recClient;
 GetClientRect(&recClient);
 pDoc->Origin.x = recClient.Width()/2;
 pDoc->Origin.y = recClient.Height()/3;
 //原点可能以变化,需重新计算各部件位置
 pDoc->CalPosition();
 //画主动导轨
 pDC->MoveTo(pDoc->Gui1[0]);
 pDC->LineTo(pDoc->Gui1[1]);
 pDC->MoveTo(pDoc->Gui1[2]);
 pDC->LineTo(pDoc->Gui1[3]);
    //画从动导轨
 pDC->MoveTo(pDoc->Gui2[0]);
 pDC->LineTo(pDoc->Gui2[2]);
 pDC->MoveTo(pDoc->Gui2[1]);
 pDC->LineTo(pDoc->Gui2[3]);
 //换笔
 penThick.CreatePen(PS_SOLID,3,RGB(0,0,0));
 oldpen = pDC->SelectObject(&penThick);
 //画主动块
 pDC->Polygon(pDoc->Kuai1,4);
 //画从动块
 pDC->Polygon(pDoc->Kuai2,4);
 //画杆
 pDC->Polygon(pDoc->Gan,4); 
 //画圆
 pDC->Ellipse(pDoc->Circle1[0].x, pDoc->Circle1[0].y, pDoc->Circle1[1].x, pDoc->Circle1[1].y); 
 pDC->Ellipse(pDoc->Circle2[0].x, pDoc->Circle2[0].y, pDoc->Circle2[1].x, pDoc->Circle2[1].y);

 pDC->SelectObject(oldpen);

 //画辅助线
 pen1.CreatePen(PS_DASHDOTDOT,1,RGB(255,0,0));
 oldpen = pDC->SelectObject(&pen1);
 pDC->MoveTo(pDoc->xian1[0]);
 pDC->LineTo(pDoc->xian1[1]);

 pDC->MoveTo(pDoc->xian2[0]);
 pDC->LineTo(pDoc->xian2[1]);
 pDC->SelectObject(oldpen);

 pen.CreatePen(PS_SOLID,1,RGB(255,0,0));
 oldpen = pDC->SelectObject(&pen); 
  if(pDoc->judge==false) 
 {
  int a=0;
  pDC->MoveTo(pDoc->Path[a].x,pDoc->Path[a].y);
  for(a=1;a<500;a++){ 
      if(pDoc->Path[a].x==0){break; }
   pDC->LineTo(pDoc->Path[a].x,pDoc->Path[a].y);
    }
  }
 pDC->SelectObject(oldpen);
 
 }  

五、添加定时器
在View类添加OnCreate()函数

int CHuaKuaiView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
 if (CView::OnCreate(lpCreateStruct) == -1)
  return -1;
  
 // TODO: Add your specialized creation code here
 SetTimer(1,66,NULL);
 return 0;
}

六、设置定时器
在View类添加OnTimer()函数

void CHuaKuaiView::OnTimer(UINT nIDEvent) 
{
 // TODO: Add your message handler code here and/or call default
 
 CHuaKuaiDoc* pDoc = GetDocument();
 ASSERT_VALID(pDoc);  
   if(pDoc->i>-84)
    {
     pDoc->dX -= 2; 
     pDoc->i-= 2; 
     pDoc->j-= 2;       
    } 

  if(pDoc->i==-84)
    {
     pDoc->dX += 2; 
     pDoc->j += 2; 
    } 

  if(pDoc->j>82)
  {  
    pDoc->i = 84;
   }

 pDoc->CalPosition();  //重新计算各部件位置
 Invalidate();         //刷新客户区

 CView::OnTimer(nIDEvent);
}

七、响应按键A或D使滑块运动
在View类添加OnKeyDown()函数

void CHuaKuaiView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
 // TODO: Add your message handler code here and/or call default
 CHuaKuaiDoc* pDoc = GetDocument();
 ASSERT_VALID(pDoc);
if(nChar=='A')
 {
  if(pDoc->dX<-84)
   pDoc->dX-=0; 
  else 
   pDoc->dX -= 2; //让主动块左移2像素
 }
 else if(nChar=='D')
 {
  if(pDoc->dX>84)
   pDoc->dX-=0; 
  else 
   pDoc->dX += 2;//让主动块右移2像素
 }
 pDoc->CalPosition();  //重新计算各部件位置
    OnPaint();            //刷新客户区
    
CView::OnKeyDown(nChar, nRepCnt, nFlags);
}

八、添加一个菜单和两个子菜单并添加相应的消息响应函数
在这里插入图片描述
子菜单“开始”的ID是ID_PATH_START,建立类向导,添加相应的消息响应函数OnPathStart() 在这里插入图片描述
子菜单“结束”的ID是ID_PATH_END,建立类向导,添加相应的消息响应函数OnPathEnd() ,如上

九、编写菜单消息响应函数

void CHuaKuaiView::OnPathStart() 
{
 // TODO: Add your command handler code here
 CHuaKuaiDoc* pDoc = GetDocument();
 ASSERT_VALID(pDoc);  
 pDoc->i = 0;
 pDoc->j = 0;
 pDoc->k = 0;
 pDoc->dX = 0;
 pDoc->judge=false; 
 
}
void CHuaKuaiView::OnPathEnd() 
{
 // TODO: Add your command handler code here
 CHuaKuaiDoc* pDoc = GetDocument();
 ASSERT_VALID(pDoc);  
 pDoc->i = -100;
 pDoc->judge=true;
 pDoc->dX = 0;
 pDoc->k = 0;
 for(int a=0;a<500;a++){//把所有点归于零
  pDoc->Path[a].x =0;
  pDoc->Path[a].y =pDoc-> Origin.y; 
 }    
  Invalidate(); 
 
}

十、运行结果
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值