zoukankan      html  css  js  c++  java
  • 图形学基础(二)图形变换_上:2D 基本变换/复合变换

    C++,MFC模板,VS2017

    准备(2D图形、矩阵、坐标系)

    typedef double array2d[5][5];
    typedef double array[24];
    class CMyClass
    {
    public:
        int xx, yy;//屏幕
        array X, Y, Z, C;
        array2d A1, A;//矩阵
    public:
        CMyClass();
        virtual ~CMyClass();void Calculate(array2d B);//矩阵计算
        void Display();//显示
        void DrawView(CDC* pdc, CRect rr);//在坐标系内画图
        void moveto(double x, double y, CDC* pdc);
        void lineto(double x, double y, CDC* pdc);
        void cleanB(array2d B);//矩阵复位
    };

    1、2D图形

    (可使用CDC类的成员函数GetMapMode和SetMapMode来获得和设置当前映射模式:

      int GetMapMode( ) const; // 返回当前的映射模式

      virtual int SetMapMode( int nMapMode ); // 返回先前的映射模式)

    在默认映射模式(MM_TEXT)下:

    代码(给到了初始化):

    CMyClass::CMyClass()
    {
        X[1] = 20; Y[1] = -20; C[1] = 1;
        X[2] = 20; Y[2] = -80; C[2] = 1;
        X[3] = 40; Y[3] = -60; C[3] = 1;
        X[4] = 60; Y[4] = -80; C[4] = 1;
        X[5] = 60; Y[5] = -20; C[5] = 1;
        X[6] = 25; Y[6] = -20; C[6] = 1;
        X[7] = 25; Y[7] = -70; C[7] = 1;
        X[8] = 40; Y[8] = -50; C[8] = 1;
        X[9] = 55; Y[9] = -70; C[9] = 1;
        X[10] = 55; Y[10] = -20; C[10] = 1;
    }

    2、矩阵

    矩阵计算:

    void CMyClass::Calculate(array2d B)
    {
        for (int i = 1; i <= 10; ++i) {
            X[i] = X[i] * B[1][1] + Y[i] * B[2][1] + C[i] * B[3][1];
            Y[i] = X[i] * B[1][2] + Y[i] * B[2][2] + C[i] * B[3][2];
        }
    }

    矩阵清零:

    void CMyClass::cleanB(array2d B)
    {
        int i, j;
        for (i = 1; i <= 3; ++i) {
            for (j = 1; j <= 3; ++j) {
                B[i][j] = 0;
            }
        }
    }

    3、坐标系

    以屏幕中点为原点,x向右,y向上为正方向

    void CGeoTrans2DView::OnDraw(CDC* pDC)
    {
        CGeoTrans2DDoc* pDoc = GetDocument();
        ASSERT_VALID(pDoc);
        if (!pDoc)
            return;
    
        // TODO: 在此处为本机数据添加绘制代码
        //画坐标系
        RECT rectWnd;
        GetClientRect(&rectWnd);//获取窗口大小
        pDC->MoveTo(rectWnd.right / 2 , rectWnd.bottom / 2 - 200);
        pDC->LineTo(rectWnd.right / 2 , rectWnd.bottom / 2 + 200);
        pDC->MoveTo(rectWnd.right / 2 - 200, rectWnd.bottom / 2 );
        pDC->LineTo(rectWnd.right / 2 + 200, rectWnd.bottom / 2 );
        ReleaseDC(pDC);
        //绘制字符图形
        CMyClass my1;
        //A1 矩阵清零
        my1.cleanB(my1.A1);
        //A1 矩阵赋值
        my1.A1[1][1] = 1;
        my1.A1[2][2] = 1;
        my1.A1[3][3] = 1;
        //A 矩阵清零
        my1.cleanB(my1.A);
        my1.Display();
    }

    基本变换(平移、旋转、缩放、对称)

    (两种矩阵表示方式)以下采用第一种表示方式:

    1、平移

     只改变矩阵 [3] [1],[3] [2] 位置的值即可:

     M平移了(x+15,y+45)

    void CGeoTrans2DView::OnTranslation()
    {
        // TODO: 在此添加命令处理程序代码    
        CMyClass my;
        my.cleanB(my.A1);
    
        my.A1[1][1] = 1;
        my.A1[2][2] = 1;
        my.A1[3][3] = 1;
        my.A1[3][1] = 15;
        my.A1[3][2] = -45;
    
        my.Display();
    }

    2、旋转

    只改变矩阵 [1] [1],[1] [2],[2] [1],[2] [2] 位置的值:

    逆时针旋转30°

    void CGeoTrans2DView::OnRotation()
    {
        // TODO: 在此添加命令处理程序代码
        CMyClass my;
        my.cleanB(my.A1);
        
        my.A1[1][1] = cos(PI / 6);
        my.A1[1][2] = -sin(PI / 6);
        my.A1[2][1] = sin(PI / 6);
        my.A1[2][2] = cos(PI / 6);
        my.A1[3][3] = 1;
    
        my.Display();
    }

    3、缩放

     该代码没有对Z进行处理,所以此处用下面的一种方法(有误:应该是放大 1/x 倍),是不可行的

    void CGeoTrans2DView::OnScaling()
    {
        // TODO: 在此添加命令处理程序代码
        CMyClass my;
        my.cleanB(my.A1);
    
        my.A1[1][1] = 3;
        my.A1[2][2] = 3;
        my.A1[3][3] = 1;
    
        my.Display();
    }

    4、对称

     x轴对称

    void CGeoTrans2DView::OnMirrorX()
    {
        // TODO: 在此添加命令处理程序代码
        CMyClass my;
        my.cleanB(my.A1);
    
        my.A1[1][1] = 1;
        my.A1[2][2] = -1;
        my.A1[3][3] = 1;
    
        my.Display();
    }

    复合变换(级联)

    级联变换:一种以上的基本变换

    1、非原点缩放

     以(-40,-40)为中心,放大3倍

    void CGeoTrans2DView::OnScalingxy()
    {
        // TODO: 在此添加命令处理程序代码
        CMyClass my;
        my.cleanB(my.A1);
        my.cleanB(my.A);
        //将(-40,-40)移到原点
        my.A1[1][1] = 1;
        my.A1[2][2] = 1;
        my.A1[3][3] = 1;
        my.A1[3][1] = 40;
        my.A1[3][2] = -40;
        my.Calculate(my.A1);
        //缩放3
        my.A[1][1] = 3;
        my.A[2][2] = 3;
        my.A[3][3] = 1;
        my.Calculate(my.A);
        //从原点复位
        my.cleanB(my.A1);
        my.A1[1][1] = 1;
        my.A1[2][2] = 1;
        my.A1[3][3] = 1;
        my.A1[3][1] = -40;
        my.A1[3][2] = 40;
        my.Calculate(my.A1);
    
        my.Display();
    }

    2、非原点旋转 

     绕(0,40)旋转60°

    void CGeoTrans2DView::OnRotationxy()
    {
        // TODO: 在此添加命令处理程序代码
        CMyClass my;
        my.cleanB(my.A1);
        my.cleanB(my.A);
        //将(0,40)移到原点
        my.A1[1][1] = 1;
        my.A1[2][2] = 1;
        my.A1[3][3] = 1;
        my.A1[3][2] = 40;
        my.Calculate(my.A1);
        //旋转60°
        my.A[1][1] = cos(PI / 3);
        my.A[1][2] = -sin(PI / 3);
        my.A[2][1] = sin(PI / 3);
        my.A[2][2] = cos(PI / 3);
        my.A[3][3] = 1;
        my.Calculate(my.A);
        //从原点复位
        my.cleanB(my.A1);
        my.A1[1][1] = 1;
        my.A1[2][2] = 1;
        my.A1[3][3] = 1;
        my.A1[3][2] = -40;
        my.Calculate(my.A1);
    
        my.Display();
    }

    参考资料:

    1、《计算机图形学原理及算法教程》和青芳 编著

    2、计算机图形学 - 中国农业大学 赵明老师视频 

    本文采用CC BY 4.0知识共享许可协议。

  • 相关阅读:
    杭州电acm理工大舞台版
    String.Split()功能
    android layout物业介绍
    讨厌OpenSSL
    Android Bundle类别
    多项式回归
    如何直接串行电缆以及空调制解调器串行电缆之间的区别?
    为什么写科技博客是情侣如此重要?
    SSH框架总结(帧分析+环境结构+示例源代码下载)
    RapidXml用法
  • 原文地址:https://www.cnblogs.com/CowryGao/p/12613069.html
Copyright © 2011-2022 走看看