- To start this exercise, create an MFC Application named Trajectory2
- Create it as a Single Document type
- Open Microsoft Paint. Create a picture that has the shape
of trajectory you will need
- Save it as Map in the res folder of the Trajectory1 project
you created
- Import this picture in your project (Project -> Add Resource...,
Import...)
- Set its ID to IDB_MAP
- Save all
To trace the trajectory of an object, you should
determine where it would start and where it would stop. For our example,
we will have a car that start on the left section of a view. When it gets
to the right extreme, we will simply change its direction and move it
opposite.
Practical Learning: Tracing a Trajectory
|
|
- Using the Resource Symbols dialog box, create an ID
named IDT_MOVE
- In the view header file, declare the following variables:
// Trajectory2View.h : interface of the CTrajectory1View class
//
#pragma once
class CTrajectory2View : public CView
{
protected: // create from serialization only
CTrajectory2View();
DECLARE_DYNCREATE(CTrajectory2View)
// Attributes
public:
CTrajectory2Doc* GetDocument() const;
// Operations
public:
// Overrides
public:
virtual void OnDraw(CDC* pDC); // overridden to draw this view
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
// Implementation
public:
virtual ~CTrajectory1View();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
DECLARE_MESSAGE_MAP()
private:
static const int BusWidth = 45;
static const int BusHeight = 15;
int xBus;
int yBus;
int wBus;
int hBus;
BOOL BusMovingRight;
};
#ifndef _DEBUG // debug version in Trajectory1View.cpp
inline CTrajectory2Doc* CTrajectory2View::GetDocument() const
{ return reinterpret_cast<CTrajectory1Doc*>(m_pDocument); }
#endif
|
- In the constructor of the view class, initialize the variables as
follows:
CTrajectory2View::CTrajectory1View()
{
// TODO: add construction code here
xBus = 60;
yBus = 180;
wBus = xBus + BusWidth;
hBus = yBus + BusHeight;
BusMovingRight = TRUE;
}
|
- Generate the OnInitialUpdate event for the view class and use it to
initialize the timer as follows:
void CTrajectory2View::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: Add your specialized code here and/or call the base class
SetTimer(IDT_MOVE, 10, NULL);
}
|
- Change the OnDraw event as follows:
void CTrajectory2View::OnDraw(CDC* pDC)
{
CTrajectory2Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
CBitmap bmpMap;
CDC mdcMap;
CBrush brsOrange, *brsOld;
bmpMap.LoadBitmap(IDB_MAP);
mdcMap.CreateCompatibleDC(pDC);
CBitmap *bmpOld = mdcMap.SelectObject(&bmpMap);
pDC->BitBlt(0, 0, 692, 586, &mdcMap, 0, 0, SRCCOPY);
brsOrange.CreateSolidBrush(RGB(240, 155, 50));
brsOld = pDC->SelectObject(&brsOrange);
pDC->RoundRect(xBus, yBus, xBus + BusWidth, yBus + BusHeight, 5, 5);
pDC->SelectObject(bmpOld);
}
|
- Generate the event of the WM_TIMER message for the view class and
implement it as follows:
void CTrajectory2View::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
if( xBus < 0 )
{
xBus = 0;
yBus = 180;
BusMovingRight = TRUE;
}
if( xBus > 645 )
{
xBus = 645;
yBus = 150;
BusMovingRight = FALSE;
}
Invalidate();
if( BusMovingRight == TRUE )
xBus++;
else
xBus--;
CView::OnTimer(nIDEvent);
}
|
- Generate the event of the WM_ERASEBKGND message of the view class
and change its return value as follows:
BOOL CTrajectory2View::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
return TRUE; // CView::OnEraseBkgnd(pDC);
}
|
- Change the OnCreate and the PreCreateWindow events of the frame class as
follows:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndToolBar.CreateEx(this,
TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY |
CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar\n");
return -1; // fail to create
}
// TODO: Delete these three lines if you don't
// want the toolbar to be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
CenterWindow();
SetWindowText(TEXT("Trajectory Recognition"));
return 0;
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
cs.cx = 700;
cs.cy = 590;
cs.style &= ~FWS_ADDTOTITLE;
return TRUE;
}
|
- Execute the application again to see the result
- Close the application
Using More Than one Trajectory |
|
Most simulations and trajectory assignments use more
than one object. This also means that you would deal with more than one
object and probably more than one trajectory. Here is a simple example of
how you may address this problem.
Practical Learning: Using Two Trajectories
|
|
- Change the header file of the view class as follows:
// Trajectory2View.h : interface of the CTrajectory1View class
//
#pragma once
class CTrajectory2View : public CView
{
protected: // create from serialization only
CTrajectory2View();
DECLARE_DYNCREATE(CTrajectory2View)
// Attributes
public:
CTrajectory1Doc* GetDocument() const;
// Operations
public:
// Overrides
public:
virtual void OnDraw(CDC* pDC); // overridden to draw this view
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
// Implementation
public:
virtual ~CTrajectory1View();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
DECLARE_MESSAGE_MAP()
private:
static const int BusWidth = 45;
static const int BusHeight = 15;
static const int CarWidth = 15;
static const int CarHeight = 30;
int xBus;
int yBus;
int wBus;
int hBus;
BOOL BusMovingRight;
int xCar;
int yCar;
int wCar;
int hCar;
BOOL CarMovingDown;
virtual void OnInitialUpdate();
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
};
#ifndef _DEBUG // debug version in Trajectory1View.cpp
inline CTrajectory1Doc* CTrajectory2View::GetDocument() const
{ return reinterpret_cast<CTrajectory2Doc*>(m_pDocument); }
#endif
|
- Change the source file of the view as follows:
// Trajectory2View.cpp : implementation of the CTrajectory1View class
//
#include "stdafx.h"
#include "Trajectory2.h"
#include "Trajectory2Doc.h"
#include "Trajectory2View.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CTrajectory1View
IMPLEMENT_DYNCREATE(CTrajectory2View, CView)
BEGIN_MESSAGE_MAP(CTrajectory1View, CView)
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
ON_WM_TIMER()
ON_WM_ERASEBKGND()
END_MESSAGE_MAP()
// CTrajectory2View construction/destruction
CTrajectory2View::CTrajectory2View()
{
// TODO: add construction code here
xBus = 60;
yBus = 180;
wBus = xBus + BusWidth;
hBus = yBus + BusHeight;
BusMovingRight = TRUE;
xCar = 330;
yCar = 100;
wCar = CarWidth;
hCar = yCar + CarHeight;
CarMovingDown = TRUE;
}
CTrajectory2View::~CTrajectory2View()
{
}
BOOL CTrajectory2View::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CView::PreCreateWindow(cs);
}
// CTrajectory2View drawing
void CTrajectory2View::OnDraw(CDC* pDC)
{
CTrajectory2Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
CBitmap bmpMap;
CDC mdcMap;
CBrush brsOrange, brsBlue, *brsOld;
bmpMap.LoadBitmap(IDB_MAP);
mdcMap.CreateCompatibleDC(pDC);
CBitmap *bmpOld = mdcMap.SelectObject(&bmpMap);
pDC->BitBlt(0, 0, 692, 586, &mdcMap, 0, 0, SRCCOPY);
brsOrange.CreateSolidBrush(RGB(240, 155, 50));
brsOld = pDC->SelectObject(&brsOrange);
pDC->RoundRect(xBus, yBus, xBus + BusWidth, yBus + BusHeight, 5, 5);
brsBlue.CreateSolidBrush(RGB(0, 150, 250));
brsOld = pDC->SelectObject(&brsBlue);
pDC->RoundRect(xCar, yCar, xCar + CarWidth, yCar + CarHeight, 5, 5);
pDC->SelectObject(bmpOld);
}
. . .
void CTrajectory2View::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: Add your specialized code here and/or call the base class
SetTimer(IDT_MOVE, 10, NULL);
}
void CTrajectory2View::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
if( xBus < 0 )
{
xBus = 0;
yBus = 180;
BusMovingRight = TRUE;
}
if( xBus > 645 )
{
xBus = 645;
yBus = 150;
BusMovingRight = FALSE;
}
if( yCar < 0 )
{
xCar = 330;
yCar = 0;
CarMovingDown = TRUE;
}
if( yCar > 500 )
{
xCar = 370;
yCar = 500;
CarMovingDown = FALSE;
}
Invalidate();
if( BusMovingRight == TRUE )
xBus++;
else
xBus--;
if( CarMovingDown == TRUE )
yCar++;
else
yCar--;
CView::OnTimer(nIDEvent);
}
BOOL CTrajectory2View::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
return TRUE; // CView::OnEraseBkgnd(pDC);
}
|
- Execute the application again to see the result
- Run the application long enough to have both cars collide
- Close the application
|
|