MFC-Simulator/TestSimulator/TestSimulatorDlg.cpp
2023-02-03 10:07:52 +08:00

1582 lines
47 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// TestSimulatorDlg.cpp : 實作檔
//
#include "stdafx.h"
#include "TestSimulator.h"
#include "TestSimulatorDlg.h"
#include "afxdialogex.h"
#define _USE_MATH_DEFINES
#include "math.h"
//#include <iostream>
//using namespace std;
#define WIN_WIDTH 1316 //對話盒客戶區寬度
#define WIN_HEIGHT 559 //對話盒客戶區高度
#define GRID_R 1 //單一格點半徑大小
#define MAX_STR_LEN 100 //最大字串長度 (用於讀取ini檔)
#define WHITE RGB (255, 255, 255) //工作區背景預設顏色
#define GRAY RGB (240, 240, 240) //格點顏色
#define LIGHT_BLUE RGB (176, 224, 230) //選取Block方框顏色
#define RED RGB (255, 0, 0) //模擬Block方框顏色
#define BLACK RGB (0, 0, 0) //連線顏色
#define MARK_FONTSIZE 120 //模式Mark字體大小
#define MARK_WIDTH 90 //Mark區域寬度
#define MARK_LOCK_WIDTH 60 //Lock Mark區域寬度
#define MARK_HEIGHT 40 //Mark區域高度
#define NO_VALUE -10 //不存在輸入訊號
#define NO_OPER_FLAG -11 //不存在運算元
#define NO_INPUT_FLAG -12 //不存在輸入波形
#define COMPUTE_ERROR -13 //不允許的運算
#define NO_BLOCK_HEAD -14 //不存在連接Block
#define NO_SEL_NUM -15 //不存在選取Block編號
#define NO_BLK_TYPE 0 //Block不屬於現有type
#define BLK_IN 1 //Block為IN
#define BLK_OUT 2 //Block為OUT
#define BLK_AND 3 //Block為AND
#define BLK_OR 4 //Block為OR
#define BLK_NOT 5 //Block為NOT
#define BLK_FUN 6 //Block為FUN
#define ZERO 0 //FALSE flag
#define ONE 1 //TRUE flag
#define SIN 2 //Sin flag
#define COS 3 //Cos flag
#define MSEC 0.001 //millisecond
#define MAX_DATA_NUM 512 //最大儲存data數目 (必須為2的次方數)
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 對 App About 使用 CAboutDlg 對話方塊
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 對話方塊資料
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支援
// 程式碼實作
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CTestSimulatorDlg 對話方塊
CTestSimulatorDlg::CTestSimulatorDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CTestSimulatorDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_rcWork.SetRect (0, 0, 0, 0);
m_rcClient.SetRect(0, 0, 0, 0);
m_ptLEnd.SetPoint (0, 0);
m_pOscDlg = NULL;
m_pOldBitmap = NULL;
m_clrBg = WHITE;
m_bInitDlg = FALSE;
m_bSelectBlk = FALSE;
m_bMoveBlk = FALSE;
m_bLineMode = FALSE;
m_bConnect = FALSE;
m_bDelBlk = FALSE;
m_bSimulate = FALSE;
m_bBgPic = FALSE;
m_bGrid = FALSE;
m_bLock = FALSE;
m_iWorkLeft = 150;
m_iWorkTop = 10;
m_iWorkRight = 1150;
m_iWorkBottom = 510;
m_iBlkWidth = 100;
m_iBlkHeight = 50;
m_iGridX = (int) (m_iBlkWidth / 4.);
m_iGridY = (int) (m_iBlkHeight / 2.);
m_iContainerSize = 0;
m_iSlctBlkNum = 0;
m_iHeadBlkNum = 0;
m_iSimBlkNum = 0;
m_iOutSize = 0;
m_iStep = 0;
}
void CTestSimulatorDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CTestSimulatorDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_TIMER()
ON_WM_SIZE()
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_WM_LBUTTONDBLCLK()
ON_WM_DESTROY()
ON_BN_CLICKED(IDC_BUTTON_IN, &CTestSimulatorDlg::OnBnClickedButtonIn)
ON_BN_CLICKED(IDC_BUTTON_OUT, &CTestSimulatorDlg::OnBnClickedButtonOut)
ON_BN_CLICKED(IDC_BUTTON_LINE, &CTestSimulatorDlg::OnBnClickedButtonLine)
ON_BN_CLICKED(IDC_BUTTON_AND, &CTestSimulatorDlg::OnBnClickedButtonAnd)
ON_BN_CLICKED(IDC_BUTTON_OR, &CTestSimulatorDlg::OnBnClickedButtonOr)
ON_BN_CLICKED(IDC_BUTTON_NOT, &CTestSimulatorDlg::OnBnClickedButtonNot)
ON_BN_CLICKED(IDC_BUTTON_FUNCTION, &CTestSimulatorDlg::OnBnClickedButtonFunction)
ON_BN_CLICKED(IDC_BUTTON_SIMULATE, &CTestSimulatorDlg::OnBnClickedButtonSimulate)
ON_BN_CLICKED(IDC_BUTTON_BGCOLOR, &CTestSimulatorDlg::OnBnClickedButtonBgcolor)
ON_BN_CLICKED(IDC_BUTTON_BGPIC, &CTestSimulatorDlg::OnBnClickedButtonBgpic)
ON_BN_CLICKED(IDC_BUTTON_OPEN, &CTestSimulatorDlg::OnBnClickedButtonOpen)
ON_BN_CLICKED(IDC_BUTTON_SAVE, &CTestSimulatorDlg::OnBnClickedButtonSave)
ON_BN_CLICKED(IDC_BUTTON_GRID, &CTestSimulatorDlg::OnBnClickedButtonGrid)
ON_BN_CLICKED(IDC_BUTTON_LOCK, &CTestSimulatorDlg::OnBnClickedButtonLock)
END_MESSAGE_MAP()
// CTestSimulatorDlg 訊息處理常式
BOOL CTestSimulatorDlg::OnInitDialog()
{
this->SetWindowPos (NULL, 0, 0, WIN_WIDTH, WIN_HEIGHT, SWP_NOZORDER | SWP_NOMOVE); //設定對話盒客戶區域
m_rcWork.SetRect (m_iWorkLeft, m_iWorkTop, m_iWorkRight, m_iWorkBottom); //設定工作區域
this->GetClientRect (&m_rcClient); //讀取對話盒客戶區域
m_dcBgPic.CreateCompatibleDC (NULL); //建立與對話盒相容的dc以載入背景圖片
CString strIniPath (_T (".\\Initial.ini")); //.ini路徑
CString strAppName (_T ("BgParameter")); //.ini中[節名]
CString strBgPicBOOL; //儲存背景圖片布林值的字串
CString strBgPicPath; //儲存背景圖片路徑的字串
CString strBgColor; //儲存背景顏色值的字串
CString strGridBOOL; //儲存格點布林值的字串
CString strLockBOOL; //儲存鎖定布林值的字串
CString strKeyName (_T ("BgPicBOOL")); //.ini中變數名稱
GetPrivateProfileString (strAppName, strKeyName, _T ("None"), strBgPicBOOL.GetBuffer (MAX_STR_LEN), MAX_STR_LEN, strIniPath);
strKeyName.Format (_T ("BgPicPath"));
GetPrivateProfileString (strAppName, strKeyName, _T ("None"), strBgPicPath.GetBuffer (MAX_STR_LEN), MAX_STR_LEN, strIniPath);
strKeyName.Format (_T ("BgColor"));
GetPrivateProfileString (strAppName, strKeyName, _T ("None"), strBgColor.GetBuffer (MAX_STR_LEN), MAX_STR_LEN, strIniPath);
strKeyName.Format (_T ("GridBOOL"));
GetPrivateProfileString (strAppName, strKeyName, _T ("None"), strGridBOOL.GetBuffer (MAX_STR_LEN), MAX_STR_LEN, strIniPath);
strKeyName.Format (_T ("LockBOOL"));
GetPrivateProfileString (strAppName, strKeyName, _T ("None"), strLockBOOL.GetBuffer (MAX_STR_LEN), MAX_STR_LEN, strIniPath);
//載入背景圖片(or顏色)
if (strBgPicBOOL == _T ("TRUE"))
{
m_strPicPath = strBgPicPath;
//將讀取的.bmp指定給HBITMAP
HBITMAP hbBgPic;
//利用HBITMAP加載位圖LoadImage (handle, 圖片路徑, 載入樣式, 圖示寬度(像素), 圖示長度(像素), LR_LOADFROMFILE: 根據路徑的值裝在圖像)
hbBgPic = (HBITMAP)::LoadImage (AfxGetInstanceHandle (), m_strPicPath, IMAGE_BITMAP, m_rcWork.Width (), m_rcWork.Height (), LR_LOADFROMFILE);
m_bitmapBgPic.Attach (hbBgPic);
m_pOldBitmap = m_dcBgPic.SelectObject (&m_bitmapBgPic);
m_bBgPic = TRUE;
}
else if (strBgPicBOOL == _T ("FALSE"))
m_clrBg = _ttoi (strBgColor);
//設定格點初始狀態
if (strGridBOOL == _T ("TRUE"))
m_bGrid = TRUE;
//載入鎖定初始狀態
if (strLockBOOL == _T ("TRUE"))
m_bLock = TRUE;
CDialogEx::OnInitDialog();
// 將 [關於...] 功能表加入系統功能表。
// IDM_ABOUTBOX 必須在系統命令範圍之中。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 設定此對話方塊的圖示。當應用程式的主視窗不是對話方塊時,
// 框架會自動從事此作業
SetIcon(m_hIcon, TRUE); // 設定大圖示
SetIcon(m_hIcon, FALSE); // 設定小圖示
m_bInitDlg = TRUE;
return TRUE; // 傳回 TRUE除非您對控制項設定焦點
}
void CTestSimulatorDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果將最小化按鈕加入您的對話方塊,您需要下列的程式碼,
// 以便繪製圖示。對於使用文件/檢視模式的 MFC 應用程式,
// 框架會自動完成此作業。
void CTestSimulatorDlg::OnPaint ()
{
//雙緩衝建立
CPaintDC dcSim (this); //主對話盒dc
CDC dcMem; //內存dc
CBitmap bitmapMem;
CBitmap * pOldBitmap;
dcMem.CreateCompatibleDC (&dcSim); //建立與主對話盒相容的dc
bitmapMem.CreateCompatibleBitmap (&dcSim, m_iWorkRight, m_iWorkBottom);
pOldBitmap = dcMem.SelectObject (&bitmapMem);
//繪製背景
dcMem.SetBkMode (TRANSPARENT);
dcMem.FillSolidRect (m_rcWork, m_clrBg);
//模式Mark的rect
CPoint ptMarkTL (m_iWorkRight - MARK_WIDTH, m_iWorkTop);
CPoint ptMarkBR (m_iWorkRight, m_iWorkTop + MARK_HEIGHT);
CRect rcModeMark (ptMarkTL, ptMarkBR);
//模式Mark字體
CFont fontModeMark, * pOldFont;
fontModeMark.CreatePointFont (MARK_FONTSIZE, _T ("Arial"), &dcMem);
//由存放背景圖片的dc拷貝至內存dc
if (m_bBgPic)
dcMem.BitBlt (m_iWorkLeft, m_iWorkTop, m_rcWork.Width (), m_rcWork.Height (), &m_dcBgPic, 0, 0, SRCCOPY);
//繪製格點
if (m_bGrid)
{
CBrush brushGray (GRAY);
CBrush* pOldBrush;
pOldBrush = dcMem.SelectObject (&brushGray);
for (int i = m_iWorkLeft; i < m_iWorkRight; i += m_iGridX)
{
for (int j = m_iWorkTop; j < m_iWorkBottom; j += m_iGridY)
dcMem.Ellipse (CRect (i - GRID_R, j - GRID_R, i + GRID_R, j + GRID_R));
}
dcMem.SelectObject (pOldBrush);
}
//繪製鎖定Mark
if (m_bLock)
{
CPoint ptLockMarkTL (m_iWorkLeft, m_iWorkTop);
CPoint ptLockMarkBR (m_iWorkLeft + MARK_LOCK_WIDTH, m_iWorkTop + MARK_HEIGHT);
CRect rcLockMark (ptLockMarkTL, ptLockMarkBR);
pOldFont = dcMem.SelectObject (&fontModeMark);
dcMem.DrawText (_T ("Lock"), -1, &rcLockMark, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
dcMem.SelectObject (pOldFont);
}
//繪製Block連線
for (int i = 0; i < m_iContainerSize; i++)
m_vcBlkContainer[i]->DrawLine (&dcMem);
//繪製選取Block方框
if (m_bSelectBlk)
{
if (m_iSlctBlkNum >= 0 && m_iSlctBlkNum < m_iContainerSize)
{
CPen penLightBlue (PS_SOLID, 10, LIGHT_BLUE);
CPen* pOldPen;
pOldPen = dcMem.SelectObject (&penLightBlue);
dcMem.Rectangle (m_vcBlkContainer[m_iSlctBlkNum]->GetBlkRect ());
dcMem.SelectObject (pOldPen);
}
}
//繪製模擬模式Mark與模擬Block方框
if (m_bSimulate)
{
//繪製模擬模式Mark
pOldFont = dcMem.SelectObject (&fontModeMark);
dcMem.DrawText (_T ("Simulation"), -1, &rcModeMark, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
dcMem.SelectObject (pOldFont);
//繪製模擬Block方框
CPen penRed (PS_SOLID, 10, RED);
CPen* pOldPen;
pOldPen = dcMem.SelectObject (&penRed);
dcMem.Rectangle (m_vcBlkContainer[m_iSimBlkNum]->GetBlkRect ());
dcMem.SelectObject (pOldPen);
}
//繪製Block
for (int i = 0; i < m_iContainerSize; i++)
m_vcBlkContainer[i]->Draw (&dcMem);
//繪製連線模式Mark與連線中之虛線線段
if (m_bLineMode)
{
//繪製連線模式Mar
pOldFont = dcMem.SelectObject (&fontModeMark);
dcMem.DrawText (_T ("LineMode"), -1, &rcModeMark, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
dcMem.SelectObject (pOldFont);
//繪製連線中之虛線線段
if (m_bConnect)
{
CPen penBlack (PS_DASH, 1, BLACK);
CPen* pOldPen;
pOldPen = dcMem.SelectObject (&penBlack);
CPoint ptLStart = m_vcBlkContainer[m_iHeadBlkNum]->GetPinOutRect ().CenterPoint (); //線段起點為Block輸出Pin的中心點
int iCornerGridY = (int) (((ptLStart.y + m_ptLEnd.y) / 2. - m_iWorkTop) / m_iGridY + 0.5); //連線轉折處距工作區上方幾個格點
int iCornerY = iCornerGridY * m_iGridY + m_iWorkTop; //連線轉折處Y座標
dcMem.MoveTo (ptLStart);
dcMem.LineTo (CPoint (ptLStart.x, iCornerY));
dcMem.MoveTo (CPoint (ptLStart.x, iCornerY));
dcMem.LineTo (CPoint (m_ptLEnd.x, iCornerY));
dcMem.MoveTo (CPoint (m_ptLEnd.x, iCornerY));
dcMem.LineTo (m_ptLEnd);
dcMem.SelectObject (pOldPen);
}
}
//由內存dc拷貝至主對話盒dc
dcSim.BitBlt (m_iWorkLeft, m_iWorkTop, m_rcWork.Width (), m_rcWork.Height (), &dcMem, m_iWorkLeft, m_iWorkTop, SRCCOPY);
//清理
dcMem.SelectObject (pOldBitmap);
bitmapMem.DeleteObject ();
dcMem.DeleteDC ();
}
// 當使用者拖曳最小化視窗時,
// 系統呼叫這個功能取得游標顯示。
HCURSOR CTestSimulatorDlg::OnQueryDragIcon ()
{
return static_cast<HCURSOR>(m_hIcon);
}
//按下IN按鈕
void CTestSimulatorDlg::OnBnClickedButtonIn ()
{
m_bLineMode = FALSE; //取消連線模式
CBlockBasis* pBlk = new CBlockIn; //new一個CBlockIn的物件
pBlk->SetBlkRect (CPoint (m_rcWork.CenterPoint ().x, m_rcWork.CenterPoint ().y), m_iBlkWidth, m_iBlkHeight); //設定Block In的rect
pBlk->SetBlkNum ((int) m_vcBlkContainer.size ()); //設定Block編號
m_vcBlkContainer.push_back (pBlk); //存入Block的vector中
m_iContainerSize = (int) m_vcBlkContainer.size (); //紀錄Block的vector size
//重繪工作區
InvalidateRect (m_rcWork, FALSE);
UpdateWindow ();
}
//按下OUT按鈕
void CTestSimulatorDlg::OnBnClickedButtonOut ()
{
m_bLineMode = FALSE; //取消連線模式
CBlockBasis* pBlk = new CBlockOut; //new一個CBlockOut的物件
pBlk->SetBlkRect (CPoint (m_rcWork.CenterPoint ().x, m_rcWork.CenterPoint ().y), m_iBlkWidth, m_iBlkHeight); //設定Block Out的rect
pBlk->SetBlkNum ((int) m_vcBlkContainer.size ()); //設定Block編號
m_vcBlkContainer.push_back (pBlk); //存入Block的vector中
m_iContainerSize = (int) m_vcBlkContainer.size (); //紀錄Block的vector size
//重繪工作區
InvalidateRect (m_rcWork, FALSE);
UpdateWindow ();
}
//按下AND按鈕
void CTestSimulatorDlg::OnBnClickedButtonAnd ()
{
m_bLineMode = FALSE; //取消連線模式
CBlockBasis* pBlk = new CBlockAnd; //new一個CBlockAnd的物件
pBlk->SetBlkRect (CPoint (m_rcWork.CenterPoint ().x, m_rcWork.CenterPoint ().y), m_iBlkWidth, m_iBlkHeight); //設定Block And的rect
pBlk->SetBlkNum ((int) m_vcBlkContainer.size ()); //設定Block編號
m_vcBlkContainer.push_back (pBlk); //存入Block的vector中
m_iContainerSize = (int) m_vcBlkContainer.size (); //紀錄Block的vector size
//重繪工作區
InvalidateRect (m_rcWork, FALSE);
UpdateWindow ();
}
//按下OR按鈕
void CTestSimulatorDlg::OnBnClickedButtonOr ()
{
m_bLineMode = FALSE; //取消連線模式
CBlockBasis* pBlk = new CBlockOr; //new一個CBlockOr的物件
pBlk->SetBlkRect (CPoint (m_rcWork.CenterPoint ().x, m_rcWork.CenterPoint ().y), m_iBlkWidth, m_iBlkHeight); //設定Block Or的rect
pBlk->SetBlkNum ((int) m_vcBlkContainer.size ()); //設定Block編號
m_vcBlkContainer.push_back (pBlk); //存入Block的vector中
m_iContainerSize = (int) m_vcBlkContainer.size (); //紀錄Block的vector size
//重繪工作區
InvalidateRect (m_rcWork, FALSE);
UpdateWindow ();
}
//按下NOT按鈕
void CTestSimulatorDlg::OnBnClickedButtonNot ()
{
m_bLineMode = FALSE; //取消連線模式
CBlockBasis* pBlk = new CBlockNot; //new一個CBlockNot的物件
pBlk->SetBlkRect (CPoint (m_rcWork.CenterPoint ().x, m_rcWork.CenterPoint ().y), m_iBlkWidth, m_iBlkHeight); //設定Block Not的rect
pBlk->SetBlkNum ((int) m_vcBlkContainer.size ()); //設定Block編號
m_vcBlkContainer.push_back (pBlk); //存入Block的vector中
m_iContainerSize = (int) m_vcBlkContainer.size (); //紀錄Block的vector size
//重繪工作區
InvalidateRect (m_rcWork, FALSE);
UpdateWindow ();
}
//按下Function按鈕
void CTestSimulatorDlg::OnBnClickedButtonFunction ()
{
m_bLineMode = FALSE; //取消連線模式
CBlockBasis* pBlk = new CBlockFun; //new一個CBlockFun的物件
pBlk->SetBlkRect (CPoint (m_rcWork.CenterPoint ().x, m_rcWork.CenterPoint ().y), m_iBlkWidth, m_iBlkHeight); //設定Block Fun的rect
pBlk->SetBlkNum ((int) m_vcBlkContainer.size ()); //設定Block編號
m_vcBlkContainer.push_back (pBlk); //存入Block的vector中
m_iContainerSize = (int) m_vcBlkContainer.size (); //紀錄Block的vector size
//重繪工作區
InvalidateRect (m_rcWork, FALSE);
UpdateWindow ();
}
//按下Line按鈕
void CTestSimulatorDlg::OnBnClickedButtonLine ()
{
//設定連線模式並重繪工作區
if (!m_bSimulate)
{
if (m_bLineMode)
m_bLineMode = FALSE;
else
{
if (!m_vcBlkContainer.empty ())
{
m_bLineMode = TRUE;
InvalidateRect (m_rcWork, FALSE);
UpdateWindow ();
}
}
}
}
//按下Simulate按鈕
void CTestSimulatorDlg::OnBnClickedButtonSimulate ()
{
if (!m_bSimulate)
{
if (m_bSelectBlk && m_iSlctBlkNum >= 0 && m_iSlctBlkNum < m_iContainerSize &&
m_vcBlkContainer[m_iSlctBlkNum]->BlkTypeIs () == BLK_OUT && m_vcBlkContainer[m_iSlctBlkNum]->GetBlkHeadSize () > 0)
{
m_iSimBlkNum = m_iSlctBlkNum; //設定模擬Block編號
m_bSimulate = TRUE; //設定模擬模式
m_bLineMode = FALSE; //取消連線模式
m_bDelBlk = FALSE; //禁止刪除Block
//若示波器對話盒指標未有指定記憶體則new一個示波器對話盒
if (m_pOscDlg == NULL)
{
m_pOscDlg = new COscDlg (this);
m_pOscDlg->Create (IDD_DIALOG_OSC, this);
m_pOscDlg->SetWindowPos (this, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
m_pOscDlg->UpdateData (FALSE);
}
else
{
m_pOscDlg->ShowWindow (SW_SHOW);
m_pOscDlg->UpdateData (FALSE);
}
//重繪工作區
InvalidateRect (m_rcWork, FALSE);
UpdateWindow ();
}
else
MessageBox (_T ("Please select output block and check if it is connected."));
}
}
//按下Grid按鈕
void CTestSimulatorDlg::OnBnClickedButtonGrid ()
{
//設定格點模式
if (!m_bGrid)
m_bGrid = TRUE;
else
{
m_bGrid = FALSE;
m_bLock = FALSE;
}
InvalidateRect (m_rcWork, FALSE);
UpdateWindow ();
}
//按下Lock按鈕
void CTestSimulatorDlg::OnBnClickedButtonLock ()
{
if (m_bGrid)
{
if (!m_bLock)
{
m_bLock = TRUE; //設定鎖定模式
//設定現有Block鎖定於最為鄰近的格點上
for (int i = 0; i < m_iContainerSize; i++)
{
int GridX = (int) ((m_vcBlkContainer[i]->GetBlkRect ().CenterPoint ().x - m_iWorkLeft) / (double) m_iGridX + 0.5);
int GridY = (int) ((m_vcBlkContainer[i]->GetBlkRect ().CenterPoint ().y - m_iWorkTop) / (double) m_iGridY + 0.5);
m_vcBlkContainer[i]->SetBlkRect (CPoint (GridX * m_iGridX + m_iWorkLeft, GridY * m_iGridY + m_iWorkTop), m_iBlkWidth, m_iBlkHeight);
}
}
else
m_bLock = FALSE;
}
//重繪工作區
InvalidateRect (m_rcWork, FALSE);
UpdateWindow ();
}
//按下背景圖片按鈕
void CTestSimulatorDlg::OnBnClickedButtonBgpic ()
{
//建立CFileDialog (TRUE開啟檔案, 預設的副檔名, 初始檔案名, OFN_HIDEREADONLY: 單選, 篩選)
CFileDialog fileDlg (TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, _T (" bitmap (*.bmp)|*.bmp||"));
//若File對話盒按下確定鍵
if (fileDlg.DoModal () == IDOK)
{
m_strPicPath = fileDlg.GetPathName (); //讀取檔案路徑
//將讀取的.bmp指定給HBITMAP
HBITMAP hbBgPic;
hbBgPic = (HBITMAP)::LoadImage (AfxGetInstanceHandle (), m_strPicPath, IMAGE_BITMAP, m_rcWork.Width (), m_rcWork.Height (), LR_LOADFROMFILE);
m_bitmapBgPic.Detach ();
m_bitmapBgPic.Attach (hbBgPic);
//僅於首次載入圖片時紀錄初始bitmap指標
if (!m_bBgPic)
m_pOldBitmap = m_dcBgPic.SelectObject (&m_bitmapBgPic);
else
m_dcBgPic.SelectObject (&m_bitmapBgPic);
m_bBgPic = TRUE;
//重繪工作區
InvalidateRect (m_rcWork, FALSE);
UpdateWindow ();
}
}
//按下背景顏色按鈕
void CTestSimulatorDlg::OnBnClickedButtonBgcolor ()
{
//建立色彩對話盒
CColorDialog clrDlg (m_clrBg, CC_PREVENTFULLOPEN);
//若色彩對話盒按下確定鍵
if (clrDlg.DoModal () == IDOK)
{
if (m_bBgPic && m_pOldBitmap != NULL)
{
m_dcBgPic.SelectObject (m_pOldBitmap);
m_bBgPic = FALSE;
}
m_clrBg = clrDlg.GetColor (); //設定背景顏色
//重繪工作區
InvalidateRect (m_rcWork, FALSE);
UpdateWindow ();
}
}
//按下Open按鈕
void CTestSimulatorDlg::OnBnClickedButtonOpen ()
{
//模擬模式下不可進行讀檔
if (!m_bSimulate)
{
//建立CFileDialog (TRUE開啟檔案, 預設的副檔名, 初始檔案名, OFN_HIDEREADONLY: 單選, 篩選)
CFileDialog fileDlg (TRUE, _T ("txt"), NULL, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, _T (" txt (*.txt)|*.txt||"));
//建立CStdioFile以讀取檔案資料
CStdioFile fileSim;
//若檔案對話盒按下確定鍵
if (fileDlg.DoModal () == IDOK)
{
//開啟檔案 (檔案路徑, CFile::modeNoTruncate: 不清空文件內容 | CFile::modeRead: 唯讀)
fileSim.Open (fileDlg.GetPathName (), CFile::modeNoTruncate | CFile::modeRead);
CString strData; //儲存每一列字串資料
CStringArray strArray; //儲存每一Block各筆資料
fileSim.ReadString (strData); //讀取檔案資料進字串
if (strData == "BlockData: ") //資料開頭應為BlockDate
{
//讀取檔案時取消選取Block
m_bSelectBlk = FALSE;
m_iSlctBlkNum = NO_SEL_NUM;
//清除示波器對話盒指標
if (m_pOscDlg != NULL)
{
m_pOscDlg->DestroyWindow ();
delete m_pOscDlg;
m_pOscDlg = NULL;
}
//清除存放Block的vector
for (int i = 0; i < m_iContainerSize; i++)
delete m_vcBlkContainer[i];
std::vector <CBlockBasis*> ().swap (m_vcBlkContainer);
//每次由檔案讀取一行資料
while (fileSim.ReadString (strData))
{
SplitString (strData, ',', strArray); //將讀取到的字串分隔為Block各筆資料並儲存至陣列中
if (strArray[0] == "IN") //Block In資料內容包含中心點位置, 波形flag
{
CBlockBasis* pBlk = new CBlockIn;
pBlk->SetBlkRect (CPoint (_ttoi (strArray[1]), _ttoi (strArray[2])), m_iBlkWidth, m_iBlkHeight);
pBlk->SetInputFlag (_ttoi (strArray[3]));
pBlk->SetBlkValue ();
pBlk->SetBlkNum ((int) m_vcBlkContainer.size ());
m_vcBlkContainer.push_back (pBlk);
m_iContainerSize = (int) m_vcBlkContainer.size ();
}
else if (strArray[0] == "OUT") //Block Out資料內容包含中心點位置, 輸入channel數目, 輸入Block編號
{
CBlockBasis* pBlk = new CBlockOut;
pBlk->SetBlkRect (CPoint (_ttoi (strArray[1]), _ttoi (strArray[2])), m_iBlkWidth, m_iBlkHeight);
int iBlkHeadSize = _ttoi (strArray[3]);
for (int i = 0; i < iBlkHeadSize; i++)
{
pBlk->SetBlkHead1Num (_ttoi (strArray[4 + i]));
pBlk->SetBlkHeadSize (FALSE);
}
pBlk->SetBlkNum ((int) m_vcBlkContainer.size ());
m_vcBlkContainer.push_back (pBlk);
m_iContainerSize = (int) m_vcBlkContainer.size ();
}
else if (strArray[0] == "AND") //Block And資料內容包含中心點位置, 輸入Block編號
{
CBlockBasis* pBlk = new CBlockAnd;
pBlk->SetBlkRect (CPoint (_ttoi (strArray[1]), _ttoi (strArray[2])), m_iBlkWidth, m_iBlkHeight);
pBlk->SetBlkHead1Num (_ttoi (strArray[3]));
pBlk->SetBlkHead2Num (_ttoi (strArray[4]));
pBlk->SetBlkNum ((int) m_vcBlkContainer.size ());
m_vcBlkContainer.push_back (pBlk);
m_iContainerSize = (int) m_vcBlkContainer.size ();
}
else if (strArray[0] == "OR") //Block Or資料內容包含中心點位置, 輸入Block編號
{
CBlockBasis* pBlk = new CBlockOr;
pBlk->SetBlkRect (CPoint (_ttoi (strArray[1]), _ttoi (strArray[2])), m_iBlkWidth, m_iBlkHeight);
pBlk->SetBlkHead1Num (_ttoi (strArray[3]));
pBlk->SetBlkHead2Num (_ttoi (strArray[4]));
pBlk->SetBlkNum ((int) m_vcBlkContainer.size ());
m_vcBlkContainer.push_back (pBlk);
m_iContainerSize = (int) m_vcBlkContainer.size ();
}
else if (strArray[0] == "NOT") //Block Not資料內容包含中心點位置, 輸入Block編號
{
CBlockBasis* pBlk = new CBlockNot;
pBlk->SetBlkRect (CPoint (_ttoi (strArray[1]), _ttoi (strArray[2])), m_iBlkWidth, m_iBlkHeight);
pBlk->SetBlkHead1Num (_ttoi (strArray[3]));
pBlk->SetBlkNum ((int) m_vcBlkContainer.size ());
m_vcBlkContainer.push_back (pBlk);
m_iContainerSize = (int) m_vcBlkContainer.size ();
}
else if (strArray[0] == "FUN") //Block Fun資料內容包含中心點位置, 輸入Block編號, 運算元flag
{
CBlockBasis* pBlk = new CBlockFun;
pBlk->SetBlkRect (CPoint (_ttoi (strArray[1]), _ttoi (strArray[2])), m_iBlkWidth, m_iBlkHeight);
pBlk->SetBlkHead1Num (_ttoi (strArray[3]));
pBlk->SetBlkHead2Num (_ttoi (strArray[4]));
pBlk->SetOperFlag (_ttoi (strArray[5]));
pBlk->SetBlkNum ((int) m_vcBlkContainer.size ());
m_vcBlkContainer.push_back (pBlk);
m_iContainerSize = (int) m_vcBlkContainer.size ();
}
}
//資料讀取完成後,關閉檔案
fileSim.Close ();
//依讀取到的輸入Block編號重新設定每一Block其連接Block的指標
m_iContainerSize = (int) m_vcBlkContainer.size ();
for (int i = 0; i < m_iContainerSize; i++)
{
if (!(m_vcBlkContainer[i]->BlkTypeIs () == BLK_OUT))
{
int iHeadBlk1Num = m_vcBlkContainer[i]->GetBlkHead1Num ();
if (iHeadBlk1Num >= 0)
m_vcBlkContainer[i]->SetBlkHead1Ptr (m_vcBlkContainer[iHeadBlk1Num]);
int iHeadBlk2Num = m_vcBlkContainer[i]->GetBlkHead2Num ();
if (iHeadBlk2Num >= 0)
m_vcBlkContainer[i]->SetBlkHead2Ptr (m_vcBlkContainer[iHeadBlk2Num]);
}
else
{
int iBlkHeadSize = m_vcBlkContainer[i]->GetBlkHeadSize ();
for (int j = 0; j < iBlkHeadSize; j++)
{
int iBlkHeadNum = m_vcBlkContainer[i]->GetBlkHead1Num (j);
m_vcBlkContainer[i]->SetBlkHead1Ptr (m_vcBlkContainer[iBlkHeadNum]);
}
}
}
//重繪工作區
InvalidateRect (m_rcWork, FALSE);
UpdateWindow ();
}
else
fileSim.Close ();
}
}
}
//按下Save按鈕
void CTestSimulatorDlg::OnBnClickedButtonSave ()
{
//建立CFileDialog (FALSE儲存檔案, 預設的副檔名, 初始檔案名, OFN_HIDEREADONLY: 單選, 篩選)
CFileDialog fileDlg (FALSE, _T ("txt"), _T ("Simulator"), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T (" txt (*.txt)|*.txt||"));
//建立CStdioFile以儲存資料
CStdioFile fileSim;
//若檔案對話盒按下確定鍵
if (fileDlg.DoModal () == IDOK)
{
// 開啟檔案 (檔案路徑, CFile::modeCreate: 以新建方式打開 | CFile::modeWrite: 只寫)
fileSim.Open (fileDlg.GetPathName (), CFile::modeCreate | CFile::modeWrite);
CString strData; //用以寫入檔案的字串
strData.Format (_T ("BlockData: \n"));
fileSim.WriteString (strData);
for (int i = 0; i < m_iContainerSize; i++)
{
int iBlkFlag = m_vcBlkContainer[i]->BlkTypeIs ();
switch (iBlkFlag)
{
case BLK_IN: //Block In需儲存內容包含中心點位置, 波形flag
strData.Format (_T ("%3s, %3d, %3d, %2d\n"), "IN", m_vcBlkContainer[i]->GetBlkRect ().CenterPoint ().x, m_vcBlkContainer[i]->GetBlkRect ().CenterPoint ().y,
m_vcBlkContainer[i]->GetInputFlag ());
break;
case BLK_OUT: //Block Out需儲存內容包含中心點位置, 輸入channel數目, 輸入Block編號
strData.Format (_T ("%3s, %3d, %3d, %1d"), "OUT", m_vcBlkContainer[i]->GetBlkRect ().CenterPoint ().x, m_vcBlkContainer[i]->GetBlkRect ().CenterPoint ().y,
m_vcBlkContainer[i]->GetBlkHeadSize ());
for (int j = 0; j < m_vcBlkContainer[i]->GetBlkHeadSize (); j++)
{
CString strNum;
strNum.Format (_T ("%1d"), m_vcBlkContainer[i]->GetBlkHead1Num (j));
strData.Append (_T (", "));
strData.Append (strNum);
}
strData.Append (_T ("\n"));
break;
case BLK_AND: //Block And需儲存內容包含中心點位置, 輸入Block編號
strData.Format (_T ("%3s, %3d, %3d, %1d, %1d\n"), "AND", m_vcBlkContainer[i]->GetBlkRect ().CenterPoint ().x, m_vcBlkContainer[i]->GetBlkRect ().CenterPoint ().y,
m_vcBlkContainer[i]->GetBlkHead1Num (), m_vcBlkContainer[i]->GetBlkHead2Num ());
break;
case BLK_OR: //Block Or需儲存內容包含中心點位置, 輸入Block編號
strData.Format (_T ("%3s, %3d, %3d, %1d, %1d\n"), "OR", m_vcBlkContainer[i]->GetBlkRect ().CenterPoint ().x, m_vcBlkContainer[i]->GetBlkRect ().CenterPoint ().y,
m_vcBlkContainer[i]->GetBlkHead1Num (), m_vcBlkContainer[i]->GetBlkHead2Num ());
break;
case BLK_NOT: //Block Not需儲存內容包含中心點位置, 輸入Block編號
strData.Format (_T ("%3s, %3d, %3d, %1d\n"), "NOT", m_vcBlkContainer[i]->GetBlkRect ().CenterPoint ().x, m_vcBlkContainer[i]->GetBlkRect ().CenterPoint ().y,
m_vcBlkContainer[i]->GetBlkHead1Num ());
break;
case BLK_FUN: //Block Fun需儲存內容包含中心點位置, 輸入Block編號, 運算元flag
strData.Format (_T ("%3s, %3d, %3d, %1d, %1d, %2d\n"), "FUN", m_vcBlkContainer[i]->GetBlkRect ().CenterPoint ().x, m_vcBlkContainer[i]->GetBlkRect ().CenterPoint ().y,
m_vcBlkContainer[i]->GetBlkHead1Num (), m_vcBlkContainer[i]->GetBlkHead2Num (), m_vcBlkContainer[i]->GetOperFlag ());
break;
default:
break;
}
fileSim.WriteString (strData); //將字串內容寫入檔案
}
fileSim.Close (); //寫入完成後,關閉檔案
}
}
//滑鼠左鍵按下
void CTestSimulatorDlg::OnLButtonDown (UINT nFlags, CPoint ptCursor)
{
SetCapture ();
m_bDelBlk = FALSE; //滑鼠左鍵按下時禁止刪除Block
//判斷鼠標是否位於Block rect範圍
for (int i = m_iContainerSize - 1; i >= 0; i--)
{
if (m_vcBlkContainer[i]->GetBlkRect ().PtInRect (ptCursor))
{
SetCursor (LoadCursor (NULL, IDC_SIZEALL));
m_iSlctBlkNum = i; //選取Block編號
m_bSelectBlk = TRUE;
m_bMoveBlk = TRUE;
m_bLineMode = FALSE; //取消連線模式
break;
}
else //點選非Block位置時取消選取標記
{
m_bSelectBlk = FALSE;
m_iSlctBlkNum = NO_SEL_NUM;
}
}
//若有選取Block立即重繪工作區
if (m_bSelectBlk)
{
InvalidateRect (m_rcWork, FALSE);
UpdateWindow ();
}
//連線模式時判斷鼠標按下位置是否位於輸出Pin腳範圍
if (m_bLineMode)
{
for (int i = 0; i < m_iContainerSize; i++)
{
if (m_vcBlkContainer[i]->GetPinOutRect ().PtInRect (ptCursor))
{
m_iHeadBlkNum = i;
m_bConnect = TRUE;
break;
}
}
}
CDialogEx::OnLButtonDown (nFlags, ptCursor);
}
//滑鼠移動
void CTestSimulatorDlg::OnMouseMove (UINT nFlags, CPoint ptCursor)
{
//移動選取Block
if (m_bMoveBlk)
{
//鎖定模式下計算鼠標位置最鄰近之格點將移動的Block中心設置於該格點位置
if (m_bLock)
{
int iGridX = (int) ((ptCursor.x - m_iWorkLeft) / (double) m_iGridX + 0.5);
int iGridY = (int) ((ptCursor.y - m_iWorkTop) / (double) m_iGridY + 0.5);
m_vcBlkContainer[m_iSlctBlkNum]->Move (CPoint (iGridX * m_iGridX + m_iWorkLeft, iGridY * m_iGridY + m_iWorkTop));
}
else
m_vcBlkContainer[m_iSlctBlkNum]->Move (ptCursor);
}
//連線模式
if (m_bLineMode)
{
for (int i = 0; i < m_iContainerSize ; i++)
{
//當鼠標靠近Block輸出Pin腳時設定鼠標樣式為十字箭頭
if (m_vcBlkContainer[i]->GetPinOutRect ().PtInRect (ptCursor))
SetCursor (LoadCursor (NULL, IDC_CROSS));
//連線時,設定鼠標位置為虛線線段末端
if (m_bConnect)
m_ptLEnd = ptCursor;
}
}
//重繪工作區
InvalidateRect (m_rcWork, FALSE);
UpdateWindow ();
CDialogEx::OnMouseMove (nFlags, ptCursor);
}
//滑鼠左鍵放開
void CTestSimulatorDlg::OnLButtonUp (UINT nFlags, CPoint ptCursor)
{
//當有選取Block時可刪除該Block
if (m_bSelectBlk)
m_bDelBlk = TRUE;
if (m_bMoveBlk)
{
//移動Block狀態下當滑鼠左鍵放開位置超出工作區則設定Block跳回工作區中心
if (!(m_rcWork.PtInRect (m_vcBlkContainer[m_iSlctBlkNum]->GetBlkRect ().TopLeft ()) &&
m_rcWork.PtInRect (m_vcBlkContainer[m_iSlctBlkNum]->GetBlkRect ().BottomRight ())))
m_vcBlkContainer[m_iSlctBlkNum]->Move (CPoint (m_rcWork.CenterPoint ().x, m_rcWork.CenterPoint ().y));
m_bMoveBlk = FALSE;
}
//連線模式下
if (m_bLineMode && m_bConnect)
{
//判斷滑鼠左鍵放開位置是否位於Block輸入Pin腳範圍若是則設定該Block連接起始Block的指標
for (int i = 0; i < m_iContainerSize; i++)
{
if (m_vcBlkContainer[i]->GetPinIn1Rect ().PtInRect (ptCursor))
{
m_vcBlkContainer[i]->SetBlkHead1Ptr (m_vcBlkContainer[m_iHeadBlkNum]);
m_vcBlkContainer[i]->SetBlkHead1Num (m_iHeadBlkNum);
m_vcBlkContainer[i]->SetBlkHeadSize (FALSE);
break;
}
if (m_vcBlkContainer[i]->GetPinIn2Rect ().PtInRect (ptCursor))
{
m_vcBlkContainer[i]->SetBlkHead2Ptr (m_vcBlkContainer[m_iHeadBlkNum]);
m_vcBlkContainer[i]->SetBlkHead2Num (m_iHeadBlkNum);
m_vcBlkContainer[i]->SetBlkHeadSize (FALSE);
break;
}
}
m_bConnect = FALSE; //滑鼠左鍵放開時,取消連線中線段
}
ReleaseCapture ();
//重繪工作區
InvalidateRect (m_rcWork, FALSE);
UpdateWindow ();
CDialogEx::OnLButtonUp(nFlags, ptCursor);
}
//雙擊滑鼠左鍵
void CTestSimulatorDlg::OnLButtonDblClk (UINT nFlags, CPoint ptCursor)
{
//模擬模式下不可更改Block flag
if (!m_bSimulate)
{
for (int i = 0; i < m_iContainerSize; i++)
{
if (m_vcBlkContainer[i]->GetBlkRect ().PtInRect (ptCursor))
{
if (m_vcBlkContainer[i]->BlkTypeIs () == BLK_IN) //更改Block In輸入波形flag
{
CInputDlg inputdlgSim;
inputdlgSim.SetInputFlag (m_vcBlkContainer[i]->GetInputFlag ());
if (inputdlgSim.DoModal () == IDOK)
{
m_vcBlkContainer[i]->SetInputFlag (inputdlgSim.GetInputFlag ());
m_vcBlkContainer[i]->SetBlkValue ();
}
else
MessageBox (_T ("The input has not been changed."));
}
else if (m_vcBlkContainer[i]->BlkTypeIs () == BLK_FUN) //更改Block Fun運算元flag
{
CFunDlg fundlgSim;
fundlgSim.SetOperFlag (m_vcBlkContainer[i]->GetOperFlag ());
if (fundlgSim.DoModal () == IDOK)
m_vcBlkContainer[i]->SetOperFlag (fundlgSim.GetOperFlag ());
else
MessageBox (_T ("The operator has not been changed."));
}
break;
}
}
}
CDialogEx::OnLButtonDblClk (nFlags, ptCursor);
}
void CTestSimulatorDlg::OnTimer (UINT_PTR nIDEvent)
{
if (nIDEvent == 0)
KillTimer (0);
int iTimeInterval = m_pOscDlg->GetTimeInterval (); //取得使用者設定的時間間隔(單位ms)
double dTime = m_iStep * iTimeInterval * MSEC; //模擬進行總時間(單位s)
std::deque <double> deqRowValue; //用以儲存每一個時間點下各input channel的值
//模擬前判斷input是否合理(僅判斷一次)
if (m_iStep == 0)
{
m_iOutSize = m_vcBlkContainer[m_iSimBlkNum]->GetBlkHeadSize (); //讀取channel數目
for (int i = 0; i < m_iOutSize; i++)
{
int iValueFlag = m_vcBlkContainer[m_iSimBlkNum]->GetValueFlag (i);
if (iValueFlag == NO_VALUE) //不存在input signal
{
MessageBox (_T ("Please check if the output block exists input signal."));
m_pOscDlg->m_bSim = FALSE;
m_pOscDlg->m_bModify = TRUE;
break;
}
else if (iValueFlag == COMPUTE_ERROR) //存在不允許的運算方式
{
MessageBox (_T ("Operation is not allowed."));
m_pOscDlg->m_bSim = FALSE;
m_pOscDlg->m_bModify = TRUE;
break;
}
else if (iValueFlag == NO_OPER_FLAG) //Block Fun未設定運算元
{
MessageBox (_T ("Please check if the operator in function block has been set up."));
m_pOscDlg->m_bSim = FALSE;
m_pOscDlg->m_bModify = TRUE;
break;
}
else
m_pOscDlg->m_bSim = TRUE;
}
}
//當input為合理運算模擬開始
if (m_pOscDlg->m_bSim)
{
if (m_iStep == 0)
{
m_pOscDlg->SetOutputSize (m_iOutSize); //設定示波器對話盒的channel數
m_pOscDlg->InitialData (); //初始化示波器對話盒資料(channel數目, 隨機畫筆)
m_deq2DOutputValue.clear (); //開始模擬前清空二維矩陣
}
//設定該時間下每一個Block In的值
for (int i = 0; i < m_iContainerSize; i++)
{
if (m_vcBlkContainer[i]->BlkTypeIs () == BLK_IN)
{
if (m_vcBlkContainer[i]->GetInputFlag () == SIN)
m_vcBlkContainer[i]->SetBlkValue (dTime);
else if (m_vcBlkContainer[i]->GetInputFlag () == COS)
m_vcBlkContainer[i]->SetBlkValue (dTime);
}
}
//取得選取模擬Block Out的值(有多個channel)
for (int i = 0; i < m_iOutSize; i++)
{
double dValue = m_vcBlkContainer[m_iSimBlkNum]->GetBlkValue (i);
deqRowValue.push_back (dValue); //存入列向量(紀錄該時間點下每一個input channel的值)
}
int iDataSize = (int) m_deq2DOutputValue.size (); //讀取總data數目
//若總data數目超過預設最大data數刪除第一個data並由末端加入新data
if (iDataSize < MAX_DATA_NUM)
m_deq2DOutputValue.push_back (deqRowValue);
else
{
m_deq2DOutputValue.pop_front ();
m_deq2DOutputValue.push_back (deqRowValue);
}
//FFT求即時頻率
double dOutFreq = 0.;
if (iDataSize == MAX_DATA_NUM /*&& m_pOscDlg->m_bFFT*/)
{
std::deque <double> deqOutputData;
for (int i = 0; i < MAX_DATA_NUM; i++)
{
double dValue = m_deq2DOutputValue[i][m_pOscDlg->m_iSlctOutputNum];
deqOutputData.push_back (dValue);
}
dOutFreq = FFT (deqOutputData, MAX_DATA_NUM, iTimeInterval * MSEC);
}
//傳值至示波器對話盒中(當前時間, 選取output value, 頻率)
m_pOscDlg->SetData(dTime, deqRowValue[m_pOscDlg->m_iSlctOutputNum], dOutFreq);
//m_pOscDlg->SetData (dTime, deqRowValue[m_pOscDlg->m_iSlctOutputNum]);
m_iStep++;
//更新示波器對話盒
m_pOscDlg->UpdateData (FALSE);
m_pOscDlg->InvalidateRect (m_pOscDlg->m_rcWork, FALSE);
m_pOscDlg->UpdateWindow ();
}
CDialogEx::OnTimer (nIDEvent);
if (m_pOscDlg->m_bSim && nIDEvent == 0)
SetTimer (0, 10, NULL);
}
//主對話盒視窗大小改變
void CTestSimulatorDlg::OnSize (UINT nType, int cx, int cy)
{
CDialogEx::OnSize(nType, cx, cy);
//剛生成主對話盒時不進入
if (m_bInitDlg)
{
//判斷是否最小化
if (!IsIconic ())
{
//取得主對話盒客戶區
CRect rcCurClient;
this->GetClientRect (&rcCurClient);
//計算x, y方向縮放比例
double dMultipleWid = rcCurClient.Width () / (double) m_rcClient.Width ();
m_rcClient.right = rcCurClient.Width ();
double dMultipleHeight = rcCurClient.Height () / (double) m_rcClient.Height ();
m_rcClient.bottom = rcCurClient.Height ();
//設定更新的工作區域
m_iWorkLeft = (int) (dMultipleWid * m_iWorkLeft + 0.5);
m_iWorkTop = (int) (dMultipleHeight * m_iWorkTop + 0.5);
m_iWorkRight = (int) (dMultipleWid * m_iWorkRight + 0.5);
m_iWorkBottom = (int) (dMultipleHeight * m_iWorkBottom + 0.5);
m_rcWork.SetRect (m_iWorkLeft, m_iWorkTop, m_iWorkRight, m_iWorkBottom);
//設定更新的控件位置與大小
Resize (IDC_BUTTON_IN , dMultipleWid, dMultipleHeight);
Resize (IDC_BUTTON_OUT , dMultipleWid, dMultipleHeight);
Resize (IDC_BUTTON_AND , dMultipleWid, dMultipleHeight);
Resize (IDC_BUTTON_OR , dMultipleWid, dMultipleHeight);
Resize (IDC_BUTTON_NOT , dMultipleWid, dMultipleHeight);
Resize (IDC_BUTTON_FUNCTION , dMultipleWid, dMultipleHeight);
Resize (IDC_BUTTON_LINE , dMultipleWid, dMultipleHeight);
Resize (IDC_BUTTON_SIMULATE , dMultipleWid, dMultipleHeight);
Resize (IDC_BUTTON_GRID , dMultipleWid, dMultipleHeight);
Resize (IDC_BUTTON_LOCK , dMultipleWid, dMultipleHeight);
Resize (IDC_BUTTON_BGPIC , dMultipleWid, dMultipleHeight);
Resize (IDC_BUTTON_BGCOLOR , dMultipleWid, dMultipleHeight);
Resize (IDC_BUTTON_OPEN , dMultipleWid, dMultipleHeight);
Resize (IDC_BUTTON_SAVE , dMultipleWid, dMultipleHeight);
//重新載入背景圖片
if (m_bBgPic)
{
HBITMAP hbBgPic;
hbBgPic = (HBITMAP)::LoadImage (AfxGetInstanceHandle (), m_strPicPath, IMAGE_BITMAP, m_rcWork.Width (), m_rcWork.Height (), LR_LOADFROMFILE);
m_bitmapBgPic.Detach ();
m_bitmapBgPic.Attach (hbBgPic);
m_dcBgPic.SelectObject (&m_bitmapBgPic);
}
//設定更新的Block位置與大小
m_iBlkWidth = (int) (m_iBlkWidth * dMultipleWid + 0.5);
m_iBlkHeight = (int) (m_iBlkHeight * dMultipleHeight + 0.5);
m_iGridX = (int) (m_iBlkWidth / 4. + 0.5);
m_iGridY = (int) (m_iBlkHeight / 2. + 0.5);
for (int i = 0; i < m_iContainerSize; i++)
Resize (m_vcBlkContainer[i], dMultipleWid, dMultipleHeight);
//重繪工作區
Invalidate (TRUE);
UpdateWindow ();
//若存在示波器對話盒,則顯示視窗
if (m_bSimulate && m_pOscDlg != NULL)
m_pOscDlg->ShowWindow (SW_SHOW);
}
}
}
BOOL CTestSimulatorDlg::PreTranslateMessage (MSG* pMsg)
{
if (pMsg->message == WM_KEYDOWN)
{
//按下刪除鍵
if (pMsg->wParam == VK_DELETE && !m_vcBlkContainer.empty () && m_bDelBlk && !m_bSimulate)
{
//判斷其他Block是否有連接至該刪除的Block若有則清除連接指標
for (int i = 0; i < m_iContainerSize; i++)
{
if (!(m_vcBlkContainer[i]->BlkTypeIs () == BLK_OUT))
{
if (m_vcBlkContainer[i]->GetBlkHead1Ptr () == m_vcBlkContainer[m_iSlctBlkNum])
{
m_vcBlkContainer[i]->SetBlkHead1Ptr (NULL);
m_vcBlkContainer[i]->SetBlkHead1Num (NO_BLOCK_HEAD);
}
if (m_vcBlkContainer[i]->GetBlkHead2Ptr () == m_vcBlkContainer[m_iSlctBlkNum])
{
m_vcBlkContainer[i]->SetBlkHead2Ptr (NULL);
m_vcBlkContainer[i]->SetBlkHead2Num (NO_BLOCK_HEAD);
}
}
else
{
int iBlkHeadSize = m_vcBlkContainer[i]->GetBlkHeadSize ();
for (int j = 0; j < iBlkHeadSize; j++)
{
if (m_vcBlkContainer[i]->GetBlkHead1Ptr (j) == m_vcBlkContainer[m_iSlctBlkNum])
{
m_vcBlkContainer[i]->DeleteBlkHead1Ptr (j);
m_vcBlkContainer[i]->SetBlkHeadSize (TRUE);
}
}
}
}
//清除選取Block
delete m_vcBlkContainer[m_iSlctBlkNum];
m_vcBlkContainer.erase (m_vcBlkContainer.begin () + m_iSlctBlkNum);
m_iContainerSize = (int) m_vcBlkContainer.size ();
//重新編號
for (int i = 0; i < m_iContainerSize; i++)
m_vcBlkContainer[i]->SetBlkNum (i);
//重新設定連接編號
for (int i = 0; i < m_iContainerSize; i++)
{
if (!(m_vcBlkContainer[i]->BlkTypeIs () == BLK_OUT))
{
if (m_vcBlkContainer[i]->GetBlkHead1Ptr () != NULL)
{
int iBlkHead1Num = m_vcBlkContainer[i]->GetBlkHead1Ptr ()->GetBlkNum ();
m_vcBlkContainer[i]->SetBlkHead1Num (iBlkHead1Num);
}
if (m_vcBlkContainer[i]->GetBlkHead2Ptr () != NULL)
{
int iBlkHead2Num = m_vcBlkContainer[i]->GetBlkHead2Ptr ()->GetBlkNum ();
m_vcBlkContainer[i]->SetBlkHead2Num (iBlkHead2Num);
}
}
else
{
int iBlkHeadSize = m_vcBlkContainer[i]->GetBlkHeadSize ();
m_vcBlkContainer[i]->ClearBlkHead1Num ();
for (int j = 0; j < iBlkHeadSize; j++)
{
int iBlkHeadNum = m_vcBlkContainer[i]->GetBlkHead1Ptr (j)->GetBlkNum ();
m_vcBlkContainer[i]->SetBlkHead1Num (iBlkHeadNum);
}
}
}
//刪除後,取消選取
m_bSelectBlk = FALSE;
m_iSlctBlkNum = NO_SEL_NUM;
m_bDelBlk = FALSE;
//重繪工作區
InvalidateRect (m_rcWork, FALSE);
UpdateWindow ();
}
//按下ESC鍵
else if (pMsg->wParam == VK_ESCAPE)
{
m_bSelectBlk = FALSE;
m_iSlctBlkNum = NO_SEL_NUM;
m_bMoveBlk = FALSE;
m_bLineMode = FALSE;
m_bConnect = FALSE;
m_bDelBlk = FALSE;
//重繪工作區
InvalidateRect (m_rcWork, FALSE);
UpdateWindow ();
return TRUE;
}
//按下ENTER鍵
else if (pMsg->wParam == VK_RETURN)
return TRUE;
}
return CDialogEx::PreTranslateMessage(pMsg);
}
void CTestSimulatorDlg::OnDestroy ()
{
CString strIniPath (_T (".\\Initial.ini")); //.ini路徑
CString strAppName (_T ("BgParameter")); //.ini中[節名]
CString strColorRef; //顏色變數
strColorRef.Format (_T ("%u"), m_clrBg); //將顏色值轉為字串
//紀錄背景相關資訊
CString strKeyName (_T ("BgPicBOOL")); //.ini中變數名稱
if (m_bBgPic)
{
WritePrivateProfileString (strAppName, strKeyName, _T ("TRUE"), strIniPath); //載入背景圖片
strKeyName.Format (_T ("BgPicPath"));
WritePrivateProfileString (strAppName, strKeyName, m_strPicPath, strIniPath); //背景圖片路徑
strKeyName.Format (_T ("BgColor"));
WritePrivateProfileString (strAppName, strKeyName, _T ("None"), strIniPath); //背景顏色為None
}
else
{
WritePrivateProfileString (strAppName, strKeyName, _T ("FALSE"), strIniPath); //不載入背景圖片
strKeyName.Format (_T ("BgPicPath"));
WritePrivateProfileString (strAppName, strKeyName, _T ("None"), strIniPath); //背景圖片路徑為None
strKeyName.Format (_T ("BgColor"));
WritePrivateProfileString (strAppName, strKeyName, strColorRef, strIniPath); //紀錄背景顏色值
}
//紀錄格點開啟與否
strKeyName.Format (_T ("GridBOOL"));
if (m_bGrid)
WritePrivateProfileString (strAppName, strKeyName, _T ("TRUE"), strIniPath);
else
WritePrivateProfileString (strAppName, strKeyName, _T ("FALSE"), strIniPath);
//紀錄鎖定開啟與否
strKeyName.Format (_T ("LockBOOL"));
if (m_bLock)
WritePrivateProfileString (strAppName, strKeyName, _T ("TRUE"), strIniPath);
else
WritePrivateProfileString (strAppName, strKeyName, _T ("FALSE"), strIniPath);
//清除存放背景圖片的dc
m_dcBgPic.SelectObject (m_pOldBitmap);
m_dcBgPic.DeleteDC ();
//清除示波器對話盒指標
if (m_pOscDlg != NULL)
{
m_pOscDlg->DestroyWindow ();
delete m_pOscDlg;
}
//清除Block vector
for (int i = 0; i < m_iContainerSize; i++)
delete m_vcBlkContainer[i];
CDialogEx::OnDestroy();
}
//將一列字串依據分隔符號分割為獨立字串
void CTestSimulatorDlg::SplitString (CString str, char cSplit, CStringArray& strarray)
{
strarray.RemoveAll ();
CString strTemp = str;
while (1)
{
int iIndex = strTemp.Find (cSplit);
if (iIndex >= 0)
{
CString strLeft = strTemp.Left (iIndex);
strLeft.Remove (' ');
strarray.Add (strLeft);
strTemp = strTemp.Right (strTemp.GetLength () - 1 - iIndex);
}
else
break;
}
strTemp.Remove (' ');
strarray.Add (strTemp);
}
//重新設定控件位置及大小
void CTestSimulatorDlg::Resize (int nID, double dMulWid, double dMulHei)
{
CRect rcItem;
GetDlgItem (nID)->GetWindowRect (&rcItem);
ScreenToClient (&rcItem);
rcItem.TopLeft ().x = (int) (rcItem.TopLeft ().x * dMulWid + 0.5);
rcItem.TopLeft ().y = (int) (rcItem.TopLeft ().y * dMulHei + 0.5);
rcItem.BottomRight ().x = (int) (rcItem.BottomRight ().x * dMulWid + 0.5);
rcItem.BottomRight ().y = (int) (rcItem.BottomRight ().y * dMulHei + 0.5);
GetDlgItem (nID)->MoveWindow (rcItem);
}
//重新設定Block位置及大小
void CTestSimulatorDlg::Resize (CBlockBasis* pBlk, double dMulWid, double dMulHei)
{
CRect rcItem = pBlk->GetBlkRect ();
rcItem.TopLeft ().x = (int) (rcItem.TopLeft ().x * dMulWid + 0.5);
rcItem.TopLeft ().y = (int) (rcItem.TopLeft ().y * dMulHei + 0.5);
rcItem.BottomRight ().x = (int) (rcItem.BottomRight ().x * dMulWid + 0.5);
rcItem.BottomRight ().y = (int) (rcItem.BottomRight ().y * dMulHei + 0.5);
pBlk->SetBlkRect (rcItem.CenterPoint (), m_iBlkWidth, m_iBlkHeight);
}
//計算data層數(應用於FFT)
int CTestSimulatorDlg::GetComputationLayers(int iDataSize)
{
int m_iLayers = 1;
if (iDataSize == 2)
return 1;
while (1)
{
iDataSize = iDataSize / 2;
m_iLayers++;
if (iDataSize == 2)
return m_iLayers;
if (iDataSize <= 1)
return -1;
}
}
//FFT求即時頻率
double CTestSimulatorDlg::FFT (const std::deque <double> & deq2dData, int iSize, double dUnitTime)
{
std::deque <CComplex> deqFData;
std::deque <CComplex> deqWeights;
std::deque <CComplex> deqX;
std::deque <double> deqAmplitude;
int iDeqLen = iSize;
int iLayers = GetComputationLayers (iSize);
for (int i = 0; i < iDeqLen; i++)
deqFData.push_back (CComplex (deq2dData[i], 0));
double dFixedFactors = (-2 * M_PI) / iDeqLen;
//計算權重序列
for (int i = 0; i < iDeqLen / 2; i++)
{
double dAngle = i * dFixedFactors;
deqWeights.push_back (CComplex (cos (dAngle), sin (dAngle)));
}
for (int i = 0; i < iDeqLen / 2; i++)
deqWeights.push_back (CComplex (-deqWeights[i].m_dReal, -deqWeights[i].m_dImag));
//計算倒序位碼
for (int i = 0; i < iDeqLen; i++)
{
int iIndex = 0;
for (int j = iLayers - 1; j >= 0; j--)
iIndex += (1 && (i & (1 << j))) << (iLayers - j - 1);
deqX.push_back (deqFData[iIndex]);
}
//計算FFT
for (int L = 1; L <= iLayers; L++)
{
int iDistance = 1 << (L - 1);
int iW = 1 << (iLayers - L); //總資料長度被分解的份數
int iB = iDeqLen >> L; //需計算幾次資料長度為iN的傅立葉轉換
int iN = iDeqLen / iB; //需計算傅立葉轉換的資料長度
for (int b = 0; b < iB; b++)
{
int iMid = b * iN;
for (int n = 0; n < iN / 2; n++)
{
int iIndex = n + iMid;
deqFData[iIndex] = deqX[iIndex] + deqWeights[n * iW] * deqX[iIndex + iDistance]; //Fe + W*Fo
}
for (int n = iN / 2; n < iN; n++)
{
int iIndex = n + iMid;
deqFData[iIndex] = deqX[iIndex - iDistance] + deqWeights[n * iW] * deqX[iIndex]; //Fe - W*Fo
}
}
deqX = deqFData;
}
//計算振幅
for (int i = 0; i < iDeqLen; i++)
deqAmplitude.push_back (deqFData[i].ComputeAmplitude ());
double dMaxAmp = 0.; //宣告最大振幅變數
double dCornerFreq = 1 / dUnitTime / 2; //計算截止頻率
double dOutFreq = 0.; //紀錄最大振福出現之頻率
//紀錄頻域中出現最大振幅的位置,其對應頻率即為輸出頻率
for (int i = 0; i < iDeqLen; i++)
{
double dFreq = i / (dUnitTime * (iDeqLen - 1));
if (dFreq > dCornerFreq)
break;
if (deqAmplitude[i] > dMaxAmp)
{
dMaxAmp = deqAmplitude[i];
dOutFreq = dFreq;
}
}
return dOutFreq;
}