23-三视图算法

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

!!!注意矩阵行列方向,视频和书不一样。

正三棱-顶点表

正三棱-面表

主视图

俯视图

侧视图

斜投影

算法设计

完整代码

// 23-三视图算法
// 参考 https://www.bilibili.com/video/BV1ge4y1777j

#define UNICODE
#include <Windows.h>
#include <Windowsx.h>
#include <math.h>
#define WINDOW_TEXT L"23-三视图算法"
#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(1.0) {}
    Point2(double x, double y) :x(x), y(y), w(1.0) {}
};

struct Point3 :Point2 // 三维点
{
    double z;
    Point3():z(0) {}
    Point3(double x, double y, double z) :Point2(x, y), z(z) {}
};

class Face    // 面
{
public:
    int ptIndex[4] = { 0,0,0,0 };   // 面顶点索引
    int ptNubmer = 0;               // 面的顶点数 
public:
    void SetPtNumber(int number)
    {
        ptNubmer = number;
    }
};

class Projection  // 三视图投影
{
private:
    double  T[4][4];  // 矩阵
    Point3* P3d;      // 三维顶点数组
    Point2* POblView; // 斜视图顶点数组
    Point2* PTriView; // 三视图投影顶点数组
    int     PtNumber; // 三维顶点个数
public:
    Projection() {};
    ~Projection() {};
    void SetMatrix(Point3* P, int ptNumber) // 初始化顶点
    {
        P3d = P;
        PtNumber = ptNumber;
        POblView = new Point2[ptNumber];  
        PTriView = new Point2[ptNumber]; 
    }

    void Identity()
    {
        T[0][0] = 1.0, T[0][1] = 0.0, T[0][2] = 0.0, T[0][3] = 0.0;
        T[1][0] = 0.0, T[1][1] = 1.0, T[1][2] = 0.0, T[1][3] = 0.0;
        T[2][0] = 0.0, T[2][1] = 0.0, T[2][2] = 1.0, T[2][3] = 0.0;
        T[3][0] = 0.0, T[3][1] = 0.0, T[3][2] = 0.0, T[3][3] = 1.0;
    }
    Point2* OProject()    // 斜等侧
    {   
        Identity();
        T[2][0] = -0.707;
        T[2][1] = -0.707;
        T[2][2] = 0.0;
        MultiplyMatrix();
        return POblView;
    }                     
                          
    Point2* VProject()    // 主视图
    {
        Identity();
        T[0][0] = 0;
        MultiplyMatrix();
        return PTriView;
                          
    }                     
                          
    Point2* HProject()    // 俯视图
    {    
        Identity();
        T[0][0] = 0;
        T[0][1] = -1;
        T[1][1] = 0;
        MultiplyMatrix();
        return PTriView;                          
    }                     
                          
    Point2* WProject()    // 侧视图
    {
        Identity();
        T[0][0] = 0;
        T[0][2] = -1;
        T[2][2] = 0;
        MultiplyMatrix();
        return PTriView;
    }

    void MultiplyMatrix()  //矩阵相乘
    {
        Point3* pTemp = new Point3[PtNumber];
        for (int i = 0; i < PtNumber; i++)
        {
           
            pTemp[i].x = P3d[i].x * T[0][0] + P3d[i].y * T[1][0] + P3d[i].z * T[2][0] + P3d[i].w * T[3][0];
            pTemp[i].y = P3d[i].x * T[0][1] + P3d[i].y * T[1][1] + P3d[i].z * T[2][1] + P3d[i].w * T[3][1];
            pTemp[i].z = P3d[i].x * T[0][2] + P3d[i].y * T[1][2] + P3d[i].z * T[2][2] + P3d[i].w * T[3][2];
            pTemp[i].w = P3d[i].x * T[0][3] + P3d[i].y * T[1][3] + P3d[i].z * T[2][3] + P3d[i].w * T[3][3];

            PTriView[i].x = -pTemp[i].z; // 三视图顶点
            PTriView[i].y =  pTemp[i].y;  // 三视图顶点
            POblView[i] = Point2(pTemp[i].x, pTemp[i].y); // 三视图顶点
        }
        delete[]pTemp;
        pTemp = NULL;
    }

};


class Prism  // 三棱柱
{
public:
    int        _a;            // 三角形边长
    int        _b;            // 棱长
    Point3     V[6];          // 三棱柱三维顶点
    Face       F[5];          // 小面表
    Point2*    _pTrivew;      // 三视图顶点数组指针
    Point2*    _pObliqueView; // 倾视图顶点数组指针
    Projection _projection;   // 投影对象
    Point2     _ptCenter;     // 中心点 
public:
    Prism()
    {
        _pTrivew = NULL;
        _pObliqueView = NULL;
    };
    ~Prism ()
    {
        if (_pTrivew != NULL)
        {
            delete[]_pTrivew;
            _pTrivew = NULL;
        }

        if (_pObliqueView != NULL)
        {
            delete[]_pObliqueView;
            _pObliqueView = NULL;
        }
    };
    void SetParameter(int a, int b) // 读入参数
    {
        _a = a;
        _b = b;
    }

    void ReadVertex()
    {
        V[0].x = -_a / 2.0; V[0].y = 0;                  V[0].z = -_b / 2.0;
        V[1].x = 0;         V[1].y = sqrt(3.0) / 2 * _a; V[1].z = -_b / 2.0;
        V[2].x =  _a / 2.0; V[2].y = 0;                  V[2].z = -_b / 2.0;
        V[3].x = -_a / 2.0; V[3].y = 0;                  V[3].z =  _b / 2.0;
        V[4].x = 0;         V[4].y = sqrt(3.0) / 2 * _a; V[4].z =  _b / 2.0;
        V[5].x =  _a / 2.0; V[5].y = 0;                  V[5].z =  _b / 2.0;

    }

    void ReadFace()
    {
        F[0].SetPtNumber(4); F[0].ptIndex[0] = 0; F[0].ptIndex[1] = 3; F[0].ptIndex[2] = 4; F[0].ptIndex[3] = 1;
        F[1].SetPtNumber(3); F[1].ptIndex[0] = 0; F[1].ptIndex[1] = 1; F[1].ptIndex[2] = 2; 
        F[2].SetPtNumber(4); F[2].ptIndex[0] = 0; F[2].ptIndex[1] = 2; F[2].ptIndex[2] = 5; F[2].ptIndex[3] = 3;
        F[3].SetPtNumber(4); F[3].ptIndex[0] = 1; F[3].ptIndex[1] = 4; F[3].ptIndex[2] = 5; F[3].ptIndex[3] = 2;
        F[4].SetPtNumber(3); F[4].ptIndex[0] = 3; F[4].ptIndex[1] = 5; F[4].ptIndex[2] = 4; 

    }
    void DrawOblique(HDC hdc,Point2 ptCenter)  // 绘制倾等侧
    {
        TextOut(hdc,50,-10, L"立体图", wcslen(L"立体图"));
        _ptCenter = ptCenter;
        _projection.SetMatrix(V, 6);
        _pObliqueView = _projection.OProject();
        Draw(hdc, _pObliqueView);

    }
    void DrawVView(HDC hdc, Point2 ptCenter)  // 绘制主视图
    {
        TextOut(hdc, -450, 320, L"主视图", wcslen(L"主视图"));
        _ptCenter = ptCenter;
        _projection.SetMatrix(V, 6);
        _pTrivew = _projection.VProject();
        Draw(hdc, _pTrivew);

    }
    void DrawHView(HDC hdc, Point2 ptCenter)  // 绘制俯视图  
    {
        TextOut(hdc, -450, -10, L"俯视图", wcslen(L"俯视图"));
        _ptCenter = ptCenter;
        _projection.SetMatrix(V, 6);
        _pTrivew = _projection.HProject();
        Draw(hdc, _pTrivew);
    }
    void DrawWView(HDC hdc, Point2 ptCenter)  // 绘制侧视图
    {
        TextOut(hdc, 50, 320, L"侧视图", wcslen(L"侧视图"));
        _ptCenter = ptCenter;
        _projection.SetMatrix(V, 6);
        _pTrivew = _projection.WProject();
        Draw(hdc, _pTrivew);
    }

    void Draw(HDC hdc, Point2* p2d) // 绘制线框
    {
        Point2 screenPoint, pTemp;
        for (int nFace = 0; nFace < 5; nFace++)  // 访问面
        {
            for (int nPoint = 0; nPoint < F[nFace].ptNubmer; nPoint++)  // 访问面顶点
            {
                screenPoint = p2d[F[nFace].ptIndex[nPoint]];
                int x = ROUND(_ptCenter.x + screenPoint.x);
                int y = ROUND(_ptCenter.y + screenPoint.y);
                if (0 == nPoint)
                {
                    MoveToEx(hdc, x, y, NULL);
                    pTemp = screenPoint;
                }
                else
                {
                    LineTo(hdc, x, y );
                }
            }

            LineTo(hdc, ROUND(_ptCenter.x + pTemp.x), ROUND(_ptCenter.y + pTemp.y));
        }
    }
};


LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC        hdc;
    RECT       rect;
    switch (uMsg)
    {
   
    case WM_PAINT:
    {
        hdc = BeginPaint(hwnd, &ps);
        GetClientRect(hwnd, &rect);

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

        // 内存DC
        HDC     memDC = CreateCompatibleDC(hdc);                                   // 创建兼容DC 画板
        HBITMAP newBitmap = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);  // 创建画布
        HGDIOBJ oldBitmap = SelectObject(memDC, newBitmap);                        // 将画布选入画板
        FillRect(memDC, &rect, (HBRUSH)(COLOR_WINDOW + 1));
        //DrawText(memDC, m_str, wcslen(m_str), &rc, NULL);

        SetMapMode(memDC, MM_ANISOTROPIC);
        SetWindowExtEx(memDC, rect.right, rect.bottom, NULL);
        SetViewportExtEx(memDC, rect.right, -rect.bottom, NULL);
        SetViewportOrgEx(memDC, rect.right / 2, rect.bottom / 2, NULL);
      
        int nClientWidth = rect.right;
        int nClientHeght = rect.bottom;

        {   // 绘制边框

            MoveToEx(memDC, -nClientWidth / 2, 0, NULL);
            LineTo(memDC, nClientWidth / 2, 0);
            MoveToEx(memDC, 0, -nClientHeght / 2, NULL);
            LineTo(memDC, 0, nClientHeght / 2);
        }
       
        {   // 绘制图形
            static Prism prism;

            prism.SetParameter(100,150);
            prism.ReadVertex();
            prism.ReadFace();
                      

            Point2 ptCenter;
          
            ptCenter = Point2(nClientHeght/4.0,-nClientHeght/4.0);
            prism.DrawOblique(memDC,ptCenter); // 绘制立体图
           
            ptCenter = Point2(-nClientHeght / 4.0, nClientHeght / 4.0);
            prism.DrawVView(memDC, ptCenter); // 绘制主视图
           
            ptCenter = Point2(nClientHeght / 4.0, nClientHeght / 4.0);
            prism.DrawWView(memDC, ptCenter); // 绘制侧视图
           
            ptCenter = Point2(-nClientHeght / 4.0, -nClientHeght / 4.0);
            prism.DrawHView(memDC, ptCenter); // 绘制俯视图

        }

        // 内存dc复制到设备
        BitBlt(hdc, ROUND(-rect.right / 2), ROUND(-rect.bottom / 2), rect.right, rect.bottom, memDC, ROUND(-rect.right / 2), ROUND(-rect.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;
}

案例总结

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值