嘻嘻~纪录一下人生中第一个正儿八经的小作品也是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();
}
十、运行结果