22-三维几何变换算法

边界表示法建模

立方体-顶表

立方体-面表

变换矩阵

正交投影

算法设计

代码

// 22-三维几何变换算法
// 参考 https://www.bilibili.com/video/BV1Pd4y127iq/

#define UNICODE
#include <Windows.h>
#include <Windowsx.h>
#include <math.h>
#define WINDOW_TEXT L"22-三维几何变换算法"
#define ROUND(d) int(floor(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) {}
};

struct Point3  // 三维点
{
    double x;
    double y;
    double z;
    double w;  // 齐次坐标
    Point3() :x(0), y(0), z(0), w(0) {}
    Point3(double x, double y ,double z) :x(x), y(y), z(z), w(0) {}
};

struct Face        // 面
{
    int ptIndex[4] = {0,0,0,0}; // 面顶点索引
    Face() {};
    ~Face() {};
};

class Transform3
{
public:
    Point3* _P;          // 顶点数组
    int     _ptNumber;   // 顶点数量
    double  _M[4][4];    // 变换矩阵
public:
    Transform3():_P(NULL), _ptNumber(0)
    {        
        memset(_M,0,sizeof(_M));
    };
    ~Transform3() {};

    void MultiplyMatrix()  //矩阵相乘
    {
        Point3* PTemp = new Point3[_ptNumber];
        for (int i = 0; i < _ptNumber; i++)
        {
            PTemp[i] = _P[i];
        }
        for (int i = 0; i < _ptNumber; i++)
        {
            _P[i].x = _M[0][0] * PTemp[i].x + _M[0][1] * PTemp[i].y + _M[0][2] * PTemp[i].z + _M[3][0]; // * PTemp[i].w
            _P[i].y = _M[1][0] * PTemp[i].x + _M[1][1] * PTemp[i].y + _M[1][2] * PTemp[i].z + _M[3][1]; // * PTemp[i].w
            _P[i].z = _M[2][0] * PTemp[i].x + _M[2][1] * PTemp[i].y + _M[2][2] * PTemp[i].z + _M[3][2]; // * PTemp[i].w
            _P[i].w = _M[3][0] * PTemp[i].x + _M[3][1] * PTemp[i].y + _M[3][2] * PTemp[i].z + _M[3][3]; // * PTemp[i].w
        }

        delete[]PTemp;
    }

    void SetMatrix(Point3* P, int ptNumber) //顶点数组初始化
    {
        _P        = P;
        _ptNumber = ptNumber;
    }
    void Identity()
    {
       _M[0][0] = 1.0, _M[0][1] = 0.0, _M[0][2] = 0.0, _M[0][3] = 0.0;
       _M[1][0] = 0.0, _M[1][1] = 1.0, _M[1][2] = 0.0, _M[1][3] = 0.0;
       _M[2][0] = 0.0, _M[2][1] = 0.0, _M[2][2] = 1.0, _M[2][3] = 0.0;
       _M[3][0] = 0.0, _M[3][1] = 0.0, _M[3][2] = 0.0, _M[3][3] = 1.0;
    }

    void Translate(double tx, double ty, double tz)//平移变换
    {
        Identity();
        _M[3][0] = tx;
        _M[3][1] = ty;
        _M[3][2] = tz;
        MultiplyMatrix();
    }

    void Scale(double sx, double sy, double sz)//缩放变换
    {
        Identity();
        _M[0][0] = sx; 
        _M[1][1] = sy;
        _M[2][2] = sz;
        MultiplyMatrix();
    }

    void  Scale(double sx, double sy, double sz, Point3 p)//相对于任意点的缩放变换
    {
        Translate(-p.x, -p.y, -p.z);
        Scale(sx, sy, sz);
        Translate(p.x, p.y, p.z);
    }

    void  Scale(double s)//整体缩放变换
    {
        Identity();
        _M[0][0] = s, _M[1][1] = s, _M[2][2] = s;
        MultiplyMatrix();
    }

    void Scale(double s, Point3 p)//相对于任意点的整体缩放变换
    {
        Translate(-p.x, -p.y, -p.z);
        Scale(s);
        Translate(p.x, p.y, p.z);
    }

    void RotateX(double beta)//绕X轴旋转变换
    {
        Identity();
        beta = beta * PI / 180;
        _M[1][1] = cos(beta), _M[1][2] = -sin(beta);
        _M[2][1] = sin(beta), _M[2][2] = cos(beta);
        MultiplyMatrix();
    }

    void  RotateY(double beta)//绕Y轴旋转变换
    {
        Identity();
        beta = beta * PI / 180;
        _M[0][0] = cos(beta), _M[0][2] = sin(beta);
        _M[2][0] = -sin(beta), _M[2][2] = cos(beta);
        MultiplyMatrix();
    }

    void  RotateZ(double beta)//绕Z轴旋转变换
    {
        Identity();
        beta = beta * PI / 180;
        _M[0][0] = cos(beta), _M[0][1] = -sin(beta);
        _M[1][0] = sin(beta), _M[1][1] = cos(beta);
        MultiplyMatrix();
    }

    void RotateX(double beta, Point3 p)//相对于任意点的X轴旋转变换
    {
        Translate(-p.x, -p.y, -p.z);
        RotateX(beta);
        Translate(p.x, p.y, p.z);
    }

    void RotateY(double beta, Point3 p)//相对于任意点的Y轴旋转变换
    {
        Translate(-p.x, -p.y, -p.z);
        RotateY(beta);
        Translate(p.x, p.y, p.z);
    }

    void RotateZ(double beta, Point3 p)//相对于任意点的Z轴旋转变换
    {
        Translate(-p.x, -p.y, -p.z);
        RotateZ(beta);
        Translate(p.x, p.y, p.z);
    }

    void  ReflectX(void)//X轴反射变换
    {
        Identity();
        _M[1][1] = -1, _M[2][2] = -1;
        MultiplyMatrix();
    }

    void  ReflectY(void)//Y轴反射变换
    {
        Identity();
        _M[0][0] = -1, _M[2][2] = -1;
        MultiplyMatrix();
    }

    void  ReflectZ(void)//Z轴反射变换
    {
        Identity();
        _M[0][0] = -1, _M[1][1] = -1;
        MultiplyMatrix();
    }

    void  ReflectXOY(void)//XOY面反射变换
    {
        Identity();
        _M[2][2] = -1;
        MultiplyMatrix();
    }

    void  ReflectYOZ(void)//YOZ面反射变换
    {
        Identity();
        _M[0][0] = -1;
        MultiplyMatrix();
    }

    void  ReflectZOX(void)//XOZ面反射变换
    {
        Identity();
        _M[1][1] = -1;
        MultiplyMatrix();
    }

    void  ShearX(double b, double c)//X方向错切变换
    {
        Identity();
        _M[0][1] = b, _M[0][2] = c;
        MultiplyMatrix();
    }

    void  ShearY(double d, double f)//Y方向错切变换
    {
        Identity();
        _M[1][0] = d, _M[1][2] = f;
        MultiplyMatrix();
    }

    void  ShearZ(double g, double h)//Z方向错切变换
    {
        Identity();
        _M[2][0] = g; _M[2][1] = h;
        MultiplyMatrix();
    }
};

class Cube        // 立方体
{
public:
    Point3 _V[8]; // 点表
    Face   _F[6]; // 面表
public:
    Cube() {};
    ~Cube() {};
     
    void ReadVertex() // 读取点表
    {
        _V[0].x = 0; _V[0].y = 0; _V[0].z = 0;
        _V[1].x = 1; _V[1].y = 0; _V[1].z = 0;
        _V[2].x = 1; _V[2].y = 1; _V[2].z = 0;
        _V[3].x = 0; _V[3].y = 1; _V[3].z = 0;
        _V[4].x = 0; _V[4].y = 0; _V[4].z = 1;
        _V[5].x = 1; _V[5].y = 0; _V[5].z = 1;
        _V[6].x = 1; _V[6].y = 1; _V[6].z = 1;
        _V[7].x = 0; _V[7].y = 1; _V[7].z = 1;

    }
    void ReadFace()  // 读取面表
    {
        _F[0].ptIndex[0] = 0; _F[0].ptIndex[1] = 4; _F[0].ptIndex[2] = 7;_F[0].ptIndex[3] = 3; // 左
        _F[1].ptIndex[0] = 1; _F[1].ptIndex[1] = 2; _F[1].ptIndex[2] = 6;_F[1].ptIndex[3] = 5; // 右
        _F[2].ptIndex[0] = 0; _F[2].ptIndex[1] = 1; _F[2].ptIndex[2] = 5;_F[2].ptIndex[3] = 4; // 底
        _F[3].ptIndex[0] = 2; _F[3].ptIndex[1] = 3; _F[3].ptIndex[2] = 7;_F[3].ptIndex[3] = 6; // 顶
        _F[4].ptIndex[0] = 0; _F[4].ptIndex[1] = 3; _F[4].ptIndex[2] = 2;_F[4].ptIndex[3] = 1; // 后
        _F[5].ptIndex[0] = 4; _F[5].ptIndex[1] = 5; _F[5].ptIndex[2] = 6;_F[5].ptIndex[3] = 7; // 前
    }

    void Draw(HDC hdc)
    {
        Point2 screenPoint[4];                             // 二维点

        for (int nFace = 0; nFace < 6; nFace++)            // 面循环
        {
           
            for (int nVertex = 0; nVertex < 4; nVertex++)  // 点循环
            {
                int vertex = _F[nFace].ptIndex[nVertex];
                screenPoint[nVertex].x = _V[vertex].x;
                screenPoint[nVertex].y = _V[vertex].y;
            }

            MoveToEx(hdc, ROUND(screenPoint[0].x), ROUND(screenPoint[0].y), NULL); // 绘制多边形
            //LineTo(hdc, ROUND(screenPoint[0].x), ROUND(screenPoint[0].y));
            LineTo(hdc, ROUND(screenPoint[1].x), ROUND(screenPoint[1].y));
            LineTo(hdc, ROUND(screenPoint[2].x), ROUND(screenPoint[2].y));
            LineTo(hdc, ROUND(screenPoint[3].x), ROUND(screenPoint[3].y));
            LineTo(hdc, ROUND(screenPoint[0].x), ROUND(screenPoint[0].y));
        }

    }
};

static bool     m_Play = false;
static wchar_t* m_str = L"左键 - 旋转 | 暂停";

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rc;
    static double alpha;
    static double beta;
  
  
    switch (uMsg)
    {
    case WM_TIMER:
        alpha += 1;
        beta += 1;
        InvalidateRect(hwnd, NULL, FALSE);
        return 0;
 
    case WM_LBUTTONDOWN:
        m_Play = !m_Play;     
        if (m_Play)
        {
            SetTimer(hwnd,0,0,NULL);
        }
        else 
        {
            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, m_str, wcslen(m_str), &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);
             
        
        // 绘制图形
        { 
            static Cube cube;        
            static Transform3 transform;
            
            cube.ReadVertex();
            cube.ReadFace();
            
            transform.SetMatrix(cube._V,8);  // 设置顶点

            double scale = 300;
           
            transform.Scale(scale);                     // 放大
            
            transform.Translate(-scale / 2 , -scale / 2, -scale / 2);    // 平移
            transform.RotateX(alpha);
            transform.RotateY(beta);

            cube.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;

    case WM_DESTROY:
        PostQuitMessage(0);
        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、付费专栏及课程。

余额充值