1. 程式人生 > >實驗一 繪制任意斜率的直線段 | 使用VS2017工具

實驗一 繪制任意斜率的直線段 | 使用VS2017工具

範圍 flag bresenham 註定 mouse wid cpp none 移動

這世界上有很多坑,註定有些坑是要填的。下面我就用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);
    
// 調用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); };
Line.h

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工具