Click here to Skip to main content
15,891,253 members
Articles / Desktop Programming / MFC

2D LUA Based Robot Simulator

Rate me:
Please Sign up or sign in to vote.
4.89/5 (26 votes)
14 Apr 2014Public Domain9 min read 131K   7.9K   119  
An article on designing your own robot simulator
��// AzollaView.cpp : implementation of the CAzollaView class

//





#include "stdafx.h"

#include "Azolla.h"



#include "AzollaDoc.h"

#include "AzollaView.h"



#include <vector>



#ifdef _DEBUG

#define new DEBUG_NEW

#endif



#define ZOOM_IN_10_PERCENT	1.10

#define ZOOM_OUT_10_PERCENT	1.00/1.10



// CAzollaView



IMPLEMENT_DYNCREATE(CAzollaView, CView)



BEGIN_MESSAGE_MAP(CAzollaView, CView)

	// Standard mouse events

	ON_WM_MOUSEMOVE()

	ON_WM_LBUTTONUP()

	ON_WM_LBUTTONDOWN()

	ON_WM_SETCURSOR()

	// Screen

	ON_WM_ERASEBKGND()

	//UI update

	ON_UPDATE_COMMAND_UI(ID_SIMULATION_RUN, OnUpdateRunButton)

	ON_UPDATE_COMMAND_UI(ID_SIMULATION_STOP, UnUpdateStopButton)

	ON_UPDATE_COMMAND_UI(ID_ROBOT_SHOWTRAIL, OnUpdateDrawTrajectory)

	ON_UPDATE_COMMAND_UI(ID_WORLD_SHOWGRID, OnUpdateShowGrid)

	ON_UPDATE_COMMAND_UI(ID_BTLINE, OnUpdateLineButton)

	ON_UPDATE_COMMAND_UI(ID_BTCIRC, OnUpdateCircleButton)

	ON_UPDATE_COMMAND_UI(ID_BTRECT, OnUpdateRectangleButton)

	ON_UPDATE_COMMAND_UI(ID_BTSELECT, OnUpdateSelectButton)

	ON_UPDATE_COMMAND_UI(ID_BTDEL, OnUpdateDeleteButton)

	// General

	ON_COMMAND(ID_VIEW_ROBOTPROPERTIES, CAzollaView::OnViewProperty)

	ON_COMMAND(ID_VIEW_EDITOR, CAzollaView::OnViewEditor)

	ON_COMMAND(ID_VIEW_ZOOMIN, CAzollaView::OnZoomIn)

	ON_COMMAND(ID_VIEW_ZOOMOUT, CAzollaView::OnZoomOut)

	ON_COMMAND(ID_ROBOT_SETPROPERTIES, CAzollaView::OnViewSetProperty)

	ON_COMMAND(ID_SIMULATION_RUN, CAzollaView::OnRun)

	ON_COMMAND(ID_SIMULATION_STOP, CAzollaView::OnStop)

	ON_COMMAND(ID_ROBOT_RESETPOSITION, CAzollaView::OnResetRobot)

	ON_COMMAND(ID_WORLD_CLEARWORLD, CAzollaView::OnClearWorld)

	ON_COMMAND(ID_ROBOT_SHOWTRAIL, CAzollaView::OnDrawTrail)

	ON_COMMAND(ID_WORLD_SHOWGRID, CAzollaView::OnShowGrid)

	ON_COMMAND(ID_ROBOT_ADDROBOT, CAzollaView::OnAddRobot)

	ON_COMMAND(ID_ROBOT_REMOVEROBOT, CAzollaView::OnRemoveRobot)

	// Buttin for drawing objects

	ON_COMMAND(ID_BTRECT, CAzollaView::OnBtRect)

	ON_COMMAND(ID_BTCIRC, CAzollaView::OnBtCirc)

	ON_COMMAND(ID_BTLINE, CAzollaView::OnBtLine)

	ON_COMMAND(ID_BTDEL, CAzollaView::OnBtDel)

	ON_COMMAND(ID_BTSELECTALL, CAzollaView::OnBtSelectAll)

	ON_COMMAND(ID_BTSELECT, CAzollaView::OnBtSelect)

END_MESSAGE_MAP()



// CAzollaView construction/destruction

CAzollaView::CAzollaView()

{

	// Init robot

	m_propertyDlg = NULL;

	m_editorDlg = NULL;

	m_evaluate = NULL;

	m_bManuallyMoved = false;

	m_bRunning = false;

	m_isShowGrid = true;

	m_bAddRobot = false;



	// Prepare dynamic variables

	m_evaluate = new CEvaluate;

}



CAzollaView::~CAzollaView()

{

	// Destroy window & clean up memory

	// Clean m_propertyDlg

	if (m_propertyDlg)

    {

		if (::IsWindow(m_propertyDlg->GetSafeHwnd()))

            m_propertyDlg->EndDialog(IDCANCEL);

		m_propertyDlg->DestroyWindow();

		delete m_propertyDlg;

    }



	// Clean m_editorDlg

	if (m_editorDlg){

        if (::IsWindow(m_editorDlg->GetSafeHwnd()))

            m_editorDlg->EndDialog(IDCANCEL);

		m_editorDlg->DestroyWindow();

		delete m_editorDlg;

    }



	if (m_evaluate)

		delete m_evaluate;

}



BOOL CAzollaView::PreCreateWindow(CREATESTRUCT& cs)

{

	m_canvas.setSnapToGrid(true, 10, 10);

	return CView::PreCreateWindow(cs);

}



// CAzollaView drawing

void CAzollaView::OnDraw(CDC* dc)

{

	CMemDC pDC(dc);



	CAzollaDoc* pDoc = GetDocument();

	pDoc->m_canvas = &m_canvas;

	ASSERT_VALID(pDoc);



	if (m_isShowGrid)

		m_canvas.drawGrid(&pDC, this->GetSafeHwnd(), 40, 40);

	m_canvas.update(&pDC);

	m_robot.DrawRobot(&pDC);



	m_canvas.setMessage(m_evaluate->getMsg());

}



BOOL CAzollaView::OnEraseBkgnd(CDC* pDC) 

{

	return FALSE;

}



BOOL CAzollaView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)

{

	if (m_bAddRobot){

		::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_CROSS));

		return TRUE;

	}

	return CView::OnSetCursor(pWnd, nHitTest, message);

}



// CAzollaView diagnostics

#ifdef _DEBUG

void CAzollaView::AssertValid() const

{

	CView::AssertValid();

}



void CAzollaView::Dump(CDumpContext& dc) const

{

	CView::Dump(dc);

}



CAzollaDoc* CAzollaView::GetDocument() const // non-debug version is inline

{

	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CAzollaDoc)));

	return (CAzollaDoc*)m_pDocument;

}

#endif //_DEBUG





// CAzollaView message handlers

/////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////



void CAzollaView::OnMouseMove(UINT nFlags, CPoint point)

{

	CView::OnMouseMove(nFlags, point);



	// Update end point while mouse is moving

	if (GetCapture() == this){

		m_ptEnd = point;

		Invalidate();

		m_canvas.set(m_ptStart, m_ptEnd);

	}



	// Drag robot manually

	if (m_bManuallyMoved){

		m_ptEnd = point;

		m_robot.SetPosition(m_ptEnd);



		// Update robot property values on proerty dialog box

		if (m_propertyDlg)

			m_propertyDlg->update();



		Invalidate();

	}

}



void CAzollaView::OnLButtonDown(UINT nFlags, CPoint point)

{

	CView::OnLButtonDown(nFlags, point);



	// Get start point for drawing

	m_ptStart = m_ptEnd = point;

	

	// Drag robot manually BUT don't move if simulation is running

	if (!m_bRunning && m_robot.IsRobotDetected(m_ptEnd)) {

		m_bManuallyMoved = true;

		m_robot.SetPosition(m_ptEnd);

		Invalidate();

	}



	// For canvas

	else{

		SetCapture();

		m_canvas.set(m_ptStart, m_ptEnd);

	}



	if (m_bAddRobot){

		m_robot.AddRobot(point);

		m_bAddRobot = false;	

	}

}



void CAzollaView::OnLButtonUp(UINT nFlags, CPoint point)

{

	CView::OnLButtonUp(nFlags, point);



	// Get end point for drawing

	if (GetCapture() == this)

	{ 

		ReleaseCapture();

		m_ptEnd = point;

		Invalidate();

		m_canvas.store();

	}



	if (!m_bRunning){

		// Drag robot manually, skip if simulation is running

		m_bManuallyMoved = false;

	}

}



DWORD WINAPI CAzollaView::screenThread(LPVOID param)

{

	CAzollaView *obj = (CAzollaView *)param;

	obj->screenThreadWorker();

	return 0;

}



void CAzollaView::screenThreadWorker()

{

	m_robot.PrepareToRun();



	while(m_bRunning && !m_evaluate->isItDone()){

		// Update robot property values on proerty dialog box

		if (m_propertyDlg) 

			m_propertyDlg->update();



		// Screen thread will refresh the canvas every 10 ms

		Invalidate();

		Sleep(10);

	}



	// Simulation stops, refresh canvas one more time

	Sleep(10);

	Invalidate();

}





void CAzollaView::OnRun()

{

	// Load code from editor to buffer then run it

	if(m_editorDlg && m_bRunning == false){

		// Retrieve code

		CString codes;

		m_editorDlg->GetText(codes);



		// Handle empty scripts

		if (codes.IsEmpty()){

			m_canvas.setMessage("Code editor is empty\n");

			Invalidate();

			return;

		}



		// Prepare to run

		int ret = m_evaluate->init(codes, &m_robot);



		if (ret == 0){

			// Init and start a new thread for simulation

			m_bRunning = true;



			DWORD thid;

			CreateThread(NULL, 0, screenThread, this, 0, &thid);

		}

		else

			// Init failed, get error message

			m_canvas.setMessage( m_evaluate->getMsg());

	}



	else

		m_canvas.setMessage("Open the editor with CTRL + E\n");



	Invalidate();

}



void CAzollaView::OnStop()

{

	if(m_bRunning){

		m_evaluate->setQuitFlag();

		m_bRunning = false;

	}

}



void CAzollaView::OnViewProperty()

{

	if (!m_propertyDlg)

		m_propertyDlg = new CPropertyDlg;



	m_propertyDlg->m_robot = &m_robot;



	if (!::IsWindow(m_propertyDlg->GetSafeHwnd()))

		m_propertyDlg->Create(IDD_SHOWPROPERTIES);



	m_propertyDlg->ShowWindow(SW_SHOW);

}



void CAzollaView::OnViewEditor()

{

	if (!m_editorDlg)

		m_editorDlg = new CEditorDlg;



	if (!::IsWindow(m_editorDlg->GetSafeHwnd()))

		m_editorDlg->Create(IDD_EDITOR, GetDesktopWindow());



	m_editorDlg->ShowWindow(SW_SHOW);

	m_editorDlg->SetActiveWindow();

}



void CAzollaView::OnViewSetProperty()

{

	CSetPropertyDlg setPropertyDlg;

	setPropertyDlg.m_robot = &m_robot;

	setPropertyDlg.DoModal();

	Invalidate();

}





void CAzollaView::OnBtCirc()

{

	m_canvas.set(TOOL_CIRCLE);

}



void CAzollaView::OnBtRect()

{

	m_canvas.set(TOOL_RECTANGLE);

}



void CAzollaView::OnBtLine()

{

	m_canvas.set(TOOL_LINE);

}



void CAzollaView::OnBtDel()

{

	m_canvas.set(TOOL_DELETE);

}



void CAzollaView::OnBtSelectAll()

{

	m_canvas.selectAll();

	Invalidate();

}



void CAzollaView::OnBtSelect()

{

	m_canvas.set(TOOL_SELECT);

}



void CAzollaView::OnResetRobot()

{

	// Stop simulation if running

	OnStop();

	// Init robot with default values. 

	// TODO: read from configuration file!

	m_robot.ResetPosition();

	

	// Refresh screen

	Invalidate();

}



void CAzollaView::OnDrawTrail()

{

	m_robot.SetDrawTrajectoryStatus(!m_robot.GetDrawTrajectoryStatus());

	Invalidate();

}



void CAzollaView::OnShowGrid()

{

	m_isShowGrid = !m_isShowGrid;

	Invalidate();

}



void CAzollaView::OnZoomIn()

{

	m_canvas.zoom(ZOOM_IN_10_PERCENT);

	m_robot.Zoom(ZOOM_IN_10_PERCENT);

	Invalidate();

}



void CAzollaView::OnZoomOut()

{

	m_canvas.zoom(ZOOM_OUT_10_PERCENT);

	m_robot.Zoom(ZOOM_OUT_10_PERCENT);

	Invalidate();

}



void CAzollaView::OnClearWorld()

{

	m_canvas.clearAll();

	Invalidate();

}



void CAzollaView::OnAddRobot()

{

	if (!m_bRunning)

		m_bAddRobot = true;

	// No need to invalidate, it has been handled by mouse event!

}



void CAzollaView::OnRemoveRobot()

{

	if (!m_bRunning){

		m_robot.RemoveRobot();

		Invalidate();

	}

}



// CAzollaView UI update handlers

/////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////



void CAzollaView::OnUpdateRunButton(CCmdUI* pCmdUI)

{

	pCmdUI->Enable(!m_bRunning);

}



void CAzollaView::UnUpdateStopButton(CCmdUI* pCmdUI)

{

	pCmdUI->Enable(m_bRunning);

}



void CAzollaView::OnUpdateDrawTrajectory(CCmdUI* pCmdUI)

{

	pCmdUI->SetCheck((int) m_robot.GetDrawTrajectoryStatus());

}



void CAzollaView::OnUpdateShowGrid(CCmdUI* pCmdUI)

{

	pCmdUI->SetCheck((int) m_isShowGrid);

}



void CAzollaView::OnUpdateRectangleButton(CCmdUI* pCmdUI)

{

	pCmdUI->SetCheck((int) m_canvas.getCursor() == TOOL_RECTANGLE);

}



void CAzollaView::OnUpdateCircleButton(CCmdUI* pCmdUI)

{

	pCmdUI->SetCheck((int) m_canvas.getCursor() == TOOL_CIRCLE);

}



void CAzollaView::OnUpdateLineButton(CCmdUI* pCmdUI)

{

	pCmdUI->SetCheck((int) m_canvas.getCursor() == TOOL_LINE);

}



void CAzollaView::OnUpdateSelectButton(CCmdUI* pCmdUI)

{

	pCmdUI->SetCheck((int) m_canvas.getCursor() == TOOL_SELECT);

}



void CAzollaView::OnUpdateDeleteButton(CCmdUI* pCmdUI)

{

	pCmdUI->SetCheck((int) m_canvas.getCursor() == TOOL_DELETE);

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under A Public Domain dedication


Written By
Student
Indonesia Indonesia
http://kataauralius.com/

Comments and Discussions