17-二维图形几何变换算法

参考:https://www.bilibili.com/video/BV12W4y1v75

原始图形

        // 窗格坐标点
        _P[ 0] = Point2(-4,-4);
        _P[ 1] = Point2(-2,-4);
        _P[ 2] = Point2( 0,-4);
        _P[ 3] = Point2( 2,-4);
        _P[ 4] = Point2( 4,-4);
        _P[ 5] = Point2(-2,-3);
        _P[ 6] = Point2( 2,-3);
        _P[ 7] = Point2(-4,-2);
        _P[ 8] = Point2(-3,-2);
        _P[ 9] = Point2( 3,-2);
        _P[10] = Point2( 4,-2);
        _P[11] = Point2(-1.5, -1.5);
        _P[12] = Point2(0, -1.5);
        _P[13] = Point2(1.5, -1.5);
        _P[14] = Point2(-4, 0);
        _P[15] = Point2(-1.5, 0);
        _P[16] = Point2(1.5, 0);
        _P[17] = Point2( 4,  0);
        _P[18] = Point2(-1.5, 1.5);
        _P[19] = Point2(0, 1.5);
        _P[20] = Point2(1.5, 1.5);
        _P[21] = Point2(-4, 2);
        _P[22] = Point2(-3, 2);
        _P[23] = Point2(3, 2);
        _P[24] = Point2(4,2);
        _P[25] = Point2(-2, 3);
        _P[26] = Point2(2, 3);
        _P[27] = Point2(-4, 4);
        _P[28] = Point2(-2,  4);
        _P[29] = Point2(0,  4);
        _P[30] = Point2(2,  4);
        _P[31] = Point2(4, 4);  

平移变换

比例变换

旋转变换

反射变换

错切变换

复合变换

矩阵操作

class Transform2
{ 
private:
    double  _T[3][3];  // 变换矩阵
    Point2* _P;        // 点
    int     _ptNumber; // 顶点个数
public:
   
    void SetMatrix(Point2* p, int ptNumber)   // 设置二维顶点数组
    {
        this->_P = p;
        this->_ptNumber = ptNumber;
    }

    void Identity()  // 单位矩阵
    {
        _T[0][0] = 1.0; _T[0][1] = 0.0; _T[0][2] = 0.0;
        _T[1][0] = 0.0; _T[1][1] = 1.0; _T[1][2] = 0.0;
        _T[2][0] = 0.0; _T[2][1] = 0.0; _T[2][2] = 1.0;

    }

    void Translate(double tx,double ty) // 平移
    {
        Identity();
        _T[2][0] = tx;
        _T[2][1] = ty;
        MultiplyMatrix();

    }

    void Scale(double sx,double sy)    // 缩放
    {
        Identity();
        _T[0][0] = sx;
        _T[1][1] = sy;
        MultiplyMatrix();

    }

    void Scale(double sx, double sy,Point2 p) // 相对于点缩放
    {

        Translate(-p.x,-p.y); // 移至坐标原点
        Scale(sx, sy);
        Translate(p.x,p.y);   // 移回

    }

    void Rotate(double beta) //旋转
    {
        Identity();
        double rad = beta * PI / 180;
        _T[0][0] =  cos(rad); _T[0][1] =  sin(rad);
        _T[1][0] = -sin(rad); _T[1][1] =  cos(rad);
        MultiplyMatrix();
    }

    void Rotate(double beta , Point2 p) //相对于点旋转
    {
        Translate(-p.x, -p.y);
        Rotate(beta);
        Translate(p.x, p.y);

    }

    void ReflectOry() // 原点反射
    {
        Identity();
        _T[0][0] = -1;
        _T[1][1] = -1;
        MultiplyMatrix();
    }

    void ReflectX() // X轴反射
    {
        Identity();
        _T[0][0] =  1;
        _T[1][1] = -1;
        MultiplyMatrix();

    }

    void ReflectY() // Y轴反射
    {
        Identity();
        _T[0][0] =  -1;
        _T[1][1] =   1;
        MultiplyMatrix();

    }

    void Shear(double b,double c)  // 错切
    {
        Identity();
        _T[0][0] = b;
        _T[1][1] = c;
        MultiplyMatrix();
    }

    void MultiplyMatrix()    // 矩阵相乘
    {
        Point2* pTemp = new Point2[_ptNumber];

        for (int i = 0; i < _ptNumber; i++)
        {
            pTemp[i] = _P[i];
        }

        for (int i = 0; i < _ptNumber; i++)
        {
            _P[i].x = pTemp[i].x * _T[0][0] + pTemp[i].y * _T[1][0] + pTemp[i].w * _T[2][0];
            _P[i].y = pTemp[i].x * _T[0][1] + pTemp[i].y * _T[1][1] + pTemp[i].w * _T[2][1];
            _P[i].w = pTemp[i].x * _T[0][2] + pTemp[i].y * _T[1][2] + pTemp[i].w * _T[2][2];
        }
        delete[] pTemp;
    }
};

完整代码

// 16-二维图形几何变换算法
// 参考 https://www.bilibili.com/video/BV12W4y1v75a

#define UNICODE
#include <Windows.h>
#include <Windowsx.h>
#include <math.h>
#define WINDOW_TEXT L"16-二维图形几何变换算法"
#define ROUND(d) int(d+0.5)  // 四舍五入
#define PI 3.1415926

struct Point2  // 二维点
{
    double    x;
    double    y;
    double    w;
    Point2() :x(0), y(0), w(0) {}
    Point2(double x, double y) :x(x), y(y), w(0) {}
    Point2(double x, double y,double w) :x(x), y(y), w(w) {}
};

class Transform2
{ 
private:
    double  _T[3][3];  // 变换矩阵
    Point2* _P;        // 点
    int     _ptNumber; // 顶点个数
public:
   
    void SetMatrix(Point2* p, int ptNumber)   // 设置二维顶点数组
    {
        this->_P = p;
        this->_ptNumber = ptNumber;
    }

    void Identity()  // 单位矩阵
    {
        _T[0][0] = 1.0; _T[0][1] = 0.0; _T[0][2] = 0.0;
        _T[1][0] = 0.0; _T[1][1] = 1.0; _T[1][2] = 0.0;
        _T[2][0] = 0.0; _T[2][1] = 0.0; _T[2][2] = 1.0;

    }

    void Translate(double tx,double ty) // 平移
    {
        Identity();
        _T[2][0] = tx;
        _T[2][1] = ty;
        MultiplyMatrix();

    }

    void Scale(double sx,double sy)    // 缩放
    {
        Identity();
        _T[0][0] = sx;
        _T[1][1] = sy;
        MultiplyMatrix();

    }

    void Scale(double sx, double sy,Point2 p) // 相对于点缩放
    {

        Translate(-p.x,-p.y); // 移至坐标原点
        Scale(sx, sy);
        Translate(p.x,p.y);   // 移回

    }

    void Rotate(double beta) //旋转
    {
        Identity();
        double rad = beta * PI / 180;
        _T[0][0] =  cos(rad); _T[0][1] =  sin(rad);
        _T[1][0] = -sin(rad); _T[1][1] =  cos(rad);
        MultiplyMatrix();
    }

    void Rotate(double beta , Point2 p) //相对于点旋转
    {
        Translate(-p.x, -p.y);
        Rotate(beta);
        Translate(p.x, p.y);

    }

    void ReflectOry() // 原点反射
    {
        Identity();
        _T[0][0] = -1;
        _T[1][1] = -1;
        MultiplyMatrix();
    }

    void ReflectX() // X轴反射
    {
        Identity();
        _T[0][0] =  1;
        _T[1][1] = -1;
        MultiplyMatrix();

    }

    void ReflectY() // Y轴反射
    {
        Identity();
        _T[0][0] =  -1;
        _T[1][1] =   1;
        MultiplyMatrix();

    }

    void Shear(double b,double c)  // 错切
    {
        Identity();
        _T[0][0] = b;
        _T[1][1] = c;
        MultiplyMatrix();
    }

    void MultiplyMatrix()    // 矩阵相乘
    {
        Point2* pTemp = new Point2[_ptNumber];

        for (int i = 0; i < _ptNumber; i++)
        {
            pTemp[i] = _P[i];
        }

        for (int i = 0; i < _ptNumber; i++)
        {
            _P[i].x = pTemp[i].x * _T[0][0] + pTemp[i].y * _T[1][0] + pTemp[i].w * _T[2][0];
            _P[i].y = pTemp[i].x * _T[0][1] + pTemp[i].y * _T[1][1] + pTemp[i].w * _T[2][1];
            _P[i].w = pTemp[i].x * _T[0][2] + pTemp[i].y * _T[1][2] + pTemp[i].w * _T[2][2];
        }
        delete[] pTemp;
    }
};

class  ClassicaPane
{
public:
    Point2 _P[32]; // 窗格顶点
public:
    ClassicaPane()
    {
        _P[ 0] = Point2(-4,-4);
        _P[ 1] = Point2(-2,-4);
        _P[ 2] = Point2( 0,-4);
        _P[ 3] = Point2( 2,-4);
        _P[ 4] = Point2( 4,-4);
        _P[ 5] = Point2(-2,-3);
        _P[ 6] = Point2( 2,-3);
        _P[ 7] = Point2(-4,-2);
        _P[ 8] = Point2(-3,-2);
        _P[ 9] = Point2( 3,-2);
        _P[10] = Point2( 4,-2);
        _P[11] = Point2(-1.5, -1.5);
        _P[12] = Point2(0, -1.5);
        _P[13] = Point2(1.5, -1.5);
        _P[14] = Point2(-4, 0);
        _P[15] = Point2(-1.5, 0);
        _P[16] = Point2(1.5, 0);
        _P[17] = Point2( 4,  0);
        _P[18] = Point2(-1.5, 1.5);
        _P[19] = Point2(0, 1.5);
        _P[20] = Point2(1.5, 1.5);
        _P[21] = Point2(-4, 2);
        _P[22] = Point2(-3, 2);
        _P[23] = Point2(3, 2);
        _P[24] = Point2(4,2);
        _P[25] = Point2(-2, 3);
        _P[26] = Point2(2, 3);
        _P[27] = Point2(-4, 4);
        _P[28] = Point2(-2,  4);
        _P[29] = Point2(0,  4);
        _P[30] = Point2(2,  4);
        _P[31] = Point2(4, 4);       

    };
    ~ ClassicaPane() {};   

    void Draw(HDC hdc)
    {

        MoveToEx(hdc,ROUND(_P[0].x), ROUND(_P[0].y),NULL);
        LineTo(hdc, ROUND(_P[4].x), ROUND(_P[4].y));
        LineTo(hdc, ROUND(_P[31].x), ROUND(_P[31].y));
        LineTo(hdc, ROUND(_P[27].x), ROUND(_P[27].y));
        LineTo(hdc, ROUND(_P[0].x), ROUND(_P[0].y));

        MoveToEx(hdc, ROUND(_P[5].x), ROUND(_P[5].y), NULL);
        LineTo(hdc, ROUND(_P[ 6].x), ROUND(_P[ 6].y));
        LineTo(hdc, ROUND(_P[ 9].x), ROUND(_P[ 9].y));
        LineTo(hdc, ROUND(_P[23].x), ROUND(_P[23].y));
        LineTo(hdc, ROUND(_P[26].x), ROUND(_P[26].y));
        LineTo(hdc, ROUND(_P[25].x), ROUND(_P[25].y));
        LineTo(hdc, ROUND(_P[22].x), ROUND(_P[22].y));
        LineTo(hdc, ROUND(_P[ 8].x), ROUND(_P[ 8].y));
        LineTo(hdc, ROUND(_P[ 5].x), ROUND(_P[ 5].y));
      
      
        MoveToEx(hdc, ROUND(_P[11].x), ROUND(_P[11].y), NULL);
        LineTo(hdc, ROUND(_P[13].x), ROUND(_P[13].y));
        LineTo(hdc, ROUND(_P[20].x), ROUND(_P[20].y));
        LineTo(hdc, ROUND(_P[18].x), ROUND(_P[18].y));
        LineTo(hdc, ROUND(_P[11].x), ROUND(_P[11].y));

        MoveToEx(hdc, ROUND(_P[7].x), ROUND(_P[7].y), NULL);
        LineTo(hdc, ROUND(_P[8].x), ROUND(_P[8].y));

        MoveToEx(hdc, ROUND(_P[1].x), ROUND(_P[1].y), NULL);
        LineTo(hdc, ROUND(_P[5].x), ROUND(_P[5].y));

        MoveToEx(hdc, ROUND(_P[2].x), ROUND(_P[2].y), NULL);
        LineTo(hdc, ROUND(_P[12].x), ROUND(_P[12].y));


        MoveToEx(hdc, ROUND(_P[3].x), ROUND(_P[3].y), NULL);
        LineTo(hdc, ROUND(_P[6].x), ROUND(_P[6].y));

        MoveToEx(hdc, ROUND(_P[10].x), ROUND(_P[10].y), NULL);
        LineTo(hdc, ROUND(_P[9].x), ROUND(_P[9].y));

        MoveToEx(hdc, ROUND(_P[17].x), ROUND(_P[17].y), NULL);
        LineTo(hdc, ROUND(_P[16].x), ROUND(_P[16].y));

        MoveToEx(hdc, ROUND(_P[14].x), ROUND(_P[14].y), NULL);
        LineTo(hdc, ROUND(_P[15].x), ROUND(_P[15].y));


        MoveToEx(hdc, ROUND(_P[23].x), ROUND(_P[23].y), NULL);
        LineTo(hdc, ROUND(_P[24].x), ROUND(_P[24].y));

        MoveToEx(hdc, ROUND(_P[26].x), ROUND(_P[26].y), NULL);
        LineTo(hdc, ROUND(_P[30].x), ROUND(_P[30].y));

        MoveToEx(hdc, ROUND(_P[19].x), ROUND(_P[19].y), NULL);
        LineTo(hdc, ROUND(_P[29].x), ROUND(_P[29].y));

        MoveToEx(hdc, ROUND(_P[25].x), ROUND(_P[25].y), NULL);
        LineTo(hdc, ROUND(_P[28].x), ROUND(_P[28].y));
       
        MoveToEx(hdc, ROUND(_P[21].x), ROUND(_P[21].y), NULL);
        LineTo(hdc, ROUND(_P[22].x), ROUND(_P[22].y));
        /*
         ... ...

        */
    }
};

static bool m_Play = false;
static int  m_Angle = 0;

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rc;
    switch (uMsg)
    {
    case WM_TIMER:
        m_Angle++;
        InvalidateRect(hwnd, NULL, FALSE);
        return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;

    case WM_LBUTTONDOWN:  

        m_Play = !m_Play;
        if (m_Play)
        {
            // 产生 WM_TIMER 消息
            SetTimer(hwnd, 0, 10, NULL);
        }
        else
        {
            // 销毁 WM_TIMER 消息
            KillTimer(hwnd, 0);
        }
        return 0;

    case WM_PAINT:
    {
        hdc = BeginPaint(hwnd, &ps);
        GetClientRect(hwnd, &rc);

        // 内存DC
        HDC     memDC = CreateCompatibleDC(hdc);                               // 创建兼容DC 画板
        HBITMAP newBitmap = CreateCompatibleBitmap(hdc, rc.right, rc.bottom);  // 创建画布
        HGDIOBJ oldBitmap = SelectObject(memDC, newBitmap);                    // 将画布选入画板
        FillRect(memDC, &rc, (HBRUSH)(COLOR_WINDOW + 1));
        DrawText(memDC, L"单击左键旋转图形", wcslen(L"单击左键开始动画"), &rc, NULL);

        SetMapMode(memDC, MM_ANISOTROPIC);
        SetWindowExtEx(memDC, rc.right, -rc.bottom, NULL);
        SetViewportExtEx(memDC, rc.right,-rc.bottom, NULL);
        SetViewportOrgEx(memDC, rc.right / 2, rc.bottom / 2, NULL);

        // 绘制图形
        {
            ClassicaPane pane;
            Transform2 tranform;

            tranform.SetMatrix(pane._P,32);
            tranform.Scale(50.0, 50.0);
            tranform.Rotate(m_Angle);

            pane.Draw(memDC);

        }
        // 内存dc复制到设备
        BitBlt(hdc, rc.left, rc.top, rc.right, rc.bottom, memDC, ROUND(-rc.right / 2), ROUND(-rc.bottom / 2), SRCCOPY);

        SelectObject(memDC, oldBitmap);

        DeleteObject(newBitmap);
        DeleteDC(memDC);

        EndPaint(hwnd, &ps);
    }
    return 0;

    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
    // Register the window class.
    const wchar_t CLASS_NAME[] = L"CAG";
    WNDCLASS wc = { };

    wc.style = CS_HREDRAW | CS_VREDRAW; // 重新绘制整个工作区
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = CLASS_NAME;
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    RegisterClass(&wc);

    HWND hwnd = CreateWindowEx(
        0,                              // Optional window styles.
        CLASS_NAME,                     // Window class
        WINDOW_TEXT,                    // Window text
        WS_OVERLAPPEDWINDOW,            // Window style

        // Size and position
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

        NULL,       // Parent window    
        NULL,       // Menu
        hInstance,  // Instance handle
        NULL        // Additional application data
    );

    if (hwnd == NULL)
    {
        return 0;
    }
    ShowWindow(hwnd, nCmdShow);


    MSG msg = { };
    while (GetMessage(&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值