Home

GDI Topics: Using a Trajectory

 
 

Changing Trajectories

In some programming assignments, you may need to show the trajectory of an item, such as a person, an animal, a car, an air plane, a train, etc. There is no strict about where to start. Still, you would need to recognize and identify how the trajectory would be traced. We will implement a simple example of a car moving on a road. For simplicity, on only will we assume a straight road, but also we will not deal with conflicts (such as collision (detection)).

Practical Learning Practical Learning: Introducing Trajectories

 

  1. To start this exercise, create an MFC Application named Trajectory2
  2. Create it as a Single Document type
  3. Open Microsoft Paint. Create a picture that has the shape of trajectory you will need
     

  4. Save it as Map in the res folder of the Trajectory1 project you created
  5. Import this picture in your project (Project -> Add Resource..., Import...)
  6. Set its ID to IDB_MAP
  7. Save all

Tracing a Trajectory

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 Practical Learning: Tracing a Trajectory 

  1. Using the Resource Symbols dialog box, create an ID named IDT_MOVE
  2. 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
  3. 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;
    }
  4. 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);
    }
  5. 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);
    }
  6. 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);
    }
  7. 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);
    }
  8. 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;
    }
  9. Execute the application again to see the result
     
  10. 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 Practical Learning: Using Two Trajectories

  1. 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
  2. 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);
    }
  3. Execute the application again to see the result
     
  4. Run the application long enough to have both cars collide
     
  5. Close the application
 

Previous Copyright © 2006 FunctionX, Inc.