实验一 绘制任意斜率的直线段 | 使用VS2017工具

这世界上有很多坑,注定有些坑是要填的。下面我就用VS2017使用MFC对这个课堂实验进行填坑。


 

一、实验目的

1)掌握任意斜率直线段的重点 Bresenham 扫描转换算法;

2)掌握 Cline 直线类的设计方法;

3)掌握状态栏编程方法。

二、实验步骤

打开Visual Studio2017,文件->新建->项目,VC++/MFC/MFC应用程序,弹出设置框选择单文档,点击完成。

首先说一下目录结构,让大家对此有个清晰的了解:

           初始项目类结构                                                      项目最后的类结构

                                            

在添加函数和变量时,有两种规范的方式:

使用类视图的类向导,点击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状态栏控件更改为public成员变量。

 


 

步骤四: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类的消息处理程序

 

最后,点击本地Windows测试器运行程序,等待一段时间,这个坑就被填好了! 

 

三、实验结果

运行后的实验结果如下:

①在空白Pane内可通过点击鼠标左键并移动鼠标松开左键的方式绘制直线

②右下角有显示鼠标的X坐标和Y坐标

图片1-1

 

posted @ 2018-04-12 11:44  霜沐林  阅读(9094)  评论(15编辑  收藏  举报