// TestSimulatorDlg.cpp : 實作檔 // #include "stdafx.h" #include "TestSimulator.h" #include "TestSimulatorDlg.h" #include "afxdialogex.h" #define _USE_MATH_DEFINES #include "math.h" //#include //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(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 ().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 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 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 & deq2dData, int iSize, double dUnitTime) { std::deque deqFData; std::deque deqWeights; std::deque deqX; std::deque 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; }