zoukankan      html  css  js  c++  java
  • 实验一 绘制任意斜率的直线段 | 使用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

  • 相关阅读:
    区块链技术栈-区块链账本
    (引文)可扩展的分布式数据库架构
    CentOS7 通过systemd 添加开机重启服务
    spring发布RMI服务(-)
    使用jdbc连接上oracle的两种方法
    用户态和内核态
    MySQL数据库备份还原(基于binlog的增量备份)
    分布式事务
    shuffle 过程
    MapReduce的流程
  • 原文地址:https://www.cnblogs.com/jdemarryme/p/8806752.html
Copyright © 2011-2022 走看看