實驗一 繪制任意斜率的直線段 | 使用VS2017工具
這世界上有很多坑,註定有些坑是要填的。下面我就用VS2017使用MFC對這個課堂實驗進行填坑。
一、實驗目的
(1)掌握任意斜率直線段的重點 Bresenham 掃描轉換算法;
(2)掌握 Cline 直線類的設計方法;
(3)掌握狀態欄編程方法。
二、實驗步驟
首先說一下目錄結構,讓大家對此有個清晰的了解:
這裏我們只需要建立一個CLine類,裏面的成員變量和成員函數具體意義如下:
在添加函數和變量時,有兩種規範的方式:
①使用類視圖的類向導,點擊CLine類,右鍵菜單,類向導,這個方式一次性可添加CLine類的所有函數和變量。
②點擊CLine類,右鍵菜單:添加->添加函數/添加變量,這個方式雖然要多次添加,但是可以添加註釋。
步驟一:新建CLine類:
代碼如下:
C#pragma once class CLine { public: CLine(); virtual ~CLine(); private: // 直線斜率 double m_k; // 直線系數 double m_b; //直線起點 CPoint m_start; //直線終點 CPoint m_end; public: // 隱函數F(x,y)=y-kx-b,計算誤差項 double getDistance(double x,double y);Line.h// 調用CDC對象的MoveTo(),移動到起點 void moveTo(CDC *&pDC); // 使用直線掃描算法繪制直線 void lineTo(CDC *&pDC); // 設置直線起點 void setStartPoint(CPoint point); // 設置直線終點 void setEndPoint(CPoint point); // 繪制直線斜率在0<k<1範圍 void kOne(CDC *&pDC); // 繪制直線斜率在k>1範圍 void kTwo(CDC *&pDC);// 繪制直線斜率在-1<k<0範圍 void kThree(CDC *&pDC); // 繪制直線斜率在k<-1範圍 void kFour(CDC *&pDC); };
CLine類的方法的具體實現( 使用Bresenham 掃描轉換算法)。
#include "stdafx.h" #include "CLine.h" CLine::CLine() { } CLine::~CLine() { } // 隱函數F(x,y)=y-kx-b,計算誤差項 double CLine::getDistance(double x,double y) { return y - m_k * x - m_b; } // 調用CDC對象的MoveTo(),移動到起點 void CLine::moveTo(CDC *&pDC) { pDC->MoveTo(m_start); } // 使用直線掃描算法繪制直線 void CLine::lineTo(CDC *&pDC) { //如果直線為垂線或是平行線或是k=1的直線 if ((m_end.x - m_start.x) == 0 || (m_end.y - m_start.y) == 0 || (m_end.x - m_start.x) == (m_end.y - m_end.y) || (m_end.x - m_start.x) == -(m_end.y - m_end.y)) pDC->LineTo(m_end); else { m_k = ((double)(m_end.y - m_start.y)) / (m_end.x - m_start.x); m_b = m_start.y - m_k * m_start.x; if (0 < m_k && m_k < 1) kOne(pDC); else if (m_k > 1) kTwo(pDC); else if (-1 < m_k && m_k < 0) kThree(pDC); else if (m_k < -1) kFour(pDC); } } // 設置直線起點 void CLine::setStartPoint(CPoint point) { this->m_end = point; } // 設置直線終點 void CLine::setEndPoint(CPoint point) { this->m_start = point; } // 繪制直線斜率在0<k<1範圍 void CLine::kOne(CDC *&pDC) { //始終保持起點X坐標小於Y坐標 if (m_start.x > m_end.x) { CPoint tmp = m_start; m_start = m_end; m_end = tmp; } double d = 0; COLORREF color = RGB(0, 0, 0); //設置直線的顏色 CPoint next = m_start; //記錄起始點 pDC->SetPixelV(next, color); //繪制起始點 for (int i = m_start.x + 1; i <= m_end.x; i++) { next.x++; //以X軸為主位移方向 if (d <= 0) //直線位於中點誤差上方 next.y++; //取上面那個點 pDC->SetPixelV(next, color); //繪制點 d = getDistance((double)next.x + 1, next.y + 0.5); //下一個中點 } } // 繪制直線斜率在k>1範圍 void CLine::kTwo(CDC *&pDC) { if (m_start.y > m_end.y) { CPoint tmp = m_start; m_start = m_end; m_end = tmp; } double d = 0; COLORREF color = RGB(0, 0, 0); CPoint next = m_start; pDC->SetPixelV(next, color); for (int i = m_start.y + 1; i <= m_end.y; i++) { next.y++; if (d > 0) next.x++; pDC->SetPixelV(next, color); d = getDistance(next.x + 0.5, (double)next.y + 1); } } // 繪制直線斜率在-1<k<0範圍 void CLine::kThree(CDC *&pDC) { if (m_start.x < m_end.x) { CPoint temp = m_start; m_start = m_end; m_end = temp; } double d = 0; COLORREF color = RGB(0, 0, 0); CPoint next = m_start; pDC->SetPixelV(next, color); for (int i = m_start.x - 1; i >= m_end.x; i--) { next.x--; if (d < 0) next.y++; pDC->SetPixelV(next, color); d = getDistance((double)next.x - 1, next.y + 0.5); } } // 繪制直線斜率在k<-1範圍 void CLine::kFour(CDC *&pDC) { if (m_start.y < m_end.y) { CPoint tmp = m_start; m_start = m_end; m_end = tmp; } double d = 0; COLORREF color = RGB(0, 0, 0); CPoint next = m_start; pDC->SetPixelV(next, color); for (int i = m_start.y - 1; i >= m_end.y; i--) { next.y--; if (d < 0) next.x++; pDC->SetPixelV(next, color); d = getDistance(next.x + 0.5, (double)next.y - 1); } }CLine.cpp
步驟二:MFCApplication1View視圖類中用類向導添加消息的處理程序:
①當左鍵鼠標按鈕按下時,記錄直線起點位置
void OnLButtonDown(UINT nFlags, CPoint point)
②當左鍵鼠標按鈕松開時,記錄直線終點位置並繪制直線
void OnLButtonUp(UINT nFlags, CPoint point)
③當鼠標移動時,在窗口用戶區顯示鼠標的x坐標和y坐標
void OnMouseMove(UINT nFlags, CPoint point)
④ 添加CLine類為成員變量
添加後,顯示如下:
步驟三:CMainFrame類中CMFCStatusBar狀態欄控件更改為共有成員變量。
步驟四:MFCApplication1View添加類的具體實現是方法。
在MFCApplication1View如圖位置添加代碼,
代碼如下:
//當左鍵鼠標按鈕按下時,記錄直線起點位置 void CMFCApplication1View::OnLButtonDown(UINT nFlags, CPoint point) { this->line.setStartPoint(point); CView::OnLButtonDown(nFlags, point); } //當左鍵鼠標按鈕松開時,記錄直線終點位置並繪制直線 void CMFCApplication1View::OnLButtonUp(UINT nFlags, CPoint point) { this->line.setEndPoint(point); CDC *pDC = GetDC(); this->line.moveTo(pDC); this->line.lineTo(pDC); CView::OnLButtonUp(nFlags, point); } //當鼠標移動時,在窗口用戶區顯示鼠標的x坐標和y坐標 void CMFCApplication1View::OnMouseMove(UINT nFlags, CPoint point) { CString stringX, stringY; CMainFrame * pFrame = (CMainFrame *)AfxGetMainWnd(); CMFCStatusBar * pStatus = &pFrame->m_wndStatusBar; if (pStatus != NULL) { //_T是一個宏,作用是讓你的程序支持Unicode編碼(雙字節編碼) stringX.Format(_T("x=%d"), point.x); stringY.Format(_T("y=%d"), point.y); CClientDC dc(this); CSize sizeX = dc.GetTextExtent(stringX); CSize sizeY = dc.GetTextExtent(stringY); pStatus->SetPaneInfo(1, nFlags, SBPS_NORMAL, sizeX.cx); pStatus->SetPaneText(1, stringX); pStatus->SetPaneInfo(2, nFlags, SBPS_NORMAL, sizeY.cx); pStatus->SetPaneText(2, stringY); } CView::OnMouseMove(nFlags, point);CMainFrame類的消息處理程序
三、實驗結果
運行後的實驗結果如下:
①在空白Pane內可通過點擊鼠標左鍵並移動鼠標松開左鍵的方式繪制直線
②右下角有顯示鼠標的X坐標和Y坐標
圖片1-1
實驗一 繪制任意斜率的直線段 | 使用VS2017工具