圖形學基礎(二)圖形變換_下:3D 平行投影

由於我本身也沒太能理解,因此在此就只寫一些些。這麼多分類,看着就頭疼。算法

 

準備(齊次座標系/圖形函數

新建BaseClass類(.h .cpp),添加必要的參數和函數。spa

typedef double array2d[5][5];
typedef double array[24];

class CBaseClass
{
public:int theta_y, phi_x, xx, yy, nn, n;
    array X, Y, Z, C, XT, YT, ZT, XP, YP, ZP, CP;
    array2d A, Ah, Aw;
    double ax[9], ay[9], az[9];
    double bx[9], by[9], bz[9];
public:
    CBaseClass();
    virtual ~CBaseClass();
    void ReadWorkpiece();void Calculate(array2d B);
    void MCalculate(array2d B);
    void XCalculate(array2d B);
    void Drawtext();
    void Display();
    void Draw();
    void Drawve();
    void Drawvt();
    void Drawse();
    void Drawst();
    void DrawViewV(CDC* pdc, CRect rr);
    void DrawViewH(CDC* pdc, CRect rr);
    void DrawViewW(CDC* pdc, CRect rr);

    void moveto(double x, double y, CDC* pdc);
    void lineto(double x, double y, CDC* pdc);
    void cleanMatrice(array2d B);
};

(一些基本函數上一篇給過了,就再也不贅述了。另外一些輔助函數,用到時再說。)code

 

一、齊次座標系視頻

 線代的話,高中水平就夠了。齊次座標系的使用,是爲了讓平移運算能夠和旋轉、縮放等運算一塊兒處理。這裏再也不贅述基本變換。blog

 

二、圖形教程

 

void CBaseClass::ReadWorkpiece()
{
    X[1] = 0; Y[1] = 0; Z[1] = 0; C[1] = 1;
    X[2] = 45; Y[2] = 0; Z[2] = 0; C[2] = 1;
    X[3] = 45; Y[3] = 37; Z[3] = 0; C[3] = 1;
    X[4] = 0; Y[4] = 37; Z[4] = 0; C[4] = 1;
    X[5] = 0; Y[5] = 37; Z[5] = 45; C[5] = 1;
    X[6] = 0; Y[6] = 0; Z[6] = 45; C[6] = 1;
    X[7] = 12; Y[7] = 0; Z[7] = 45; C[7] = 1;
    X[8] = 30; Y[8] = 0; Z[8] = 14; C[8] = 1;
    X[9] = 45; Y[9] = 0; Z[9] = 14; C[9] = 1;
    X[10] = 45; Y[10] = 37; Z[10] = 14; C[10] = 1;
    X[11] = 30; Y[11] = 37; Z[11] = 14; C[11] = 1;
    X[12] = 12; Y[12] = 37; Z[12] = 45; C[12] = 1;
}

 

三視圖class

(這裏的投影平面和主視圖爲xoz面。)原理

 立體圖形(斜二測)和拆解步驟如圖:float

 

 

 主視圖直接垂直投影;俯視圖垂直投影后,繞x軸旋轉90°;側視圖垂直投影后,繞z軸旋轉90°。

代碼以下,已經將俯視圖和側視圖的旋轉矩陣計算好了。

void CGeoTrans3DView::OnV()
{
    // TODO: 在此添加命令處理程序代碼
    //m_str = "主視圖xoz";
    CBaseClass my;
    my.cleanMatrice(my.A);
    my.A[1][1] = 1;
    my.A[3][3] = 1;
    my.A[4][4] = 1;
    my.Display();
}

void CGeoTrans3DView::OnH()
{
    // TODO: 在此添加命令處理程序代碼
    //m_str = "俯視圖xoy";
    CBaseClass my; 
    my.cleanMatrice(my.Ah);
    my.Ah[1][1] = 1;
    my.Ah[2][3] = -1;
    my.Ah[4][4] = 1;
    my.Display();
}

void CGeoTrans3DView::OnW()
{
    // TODO: 在此添加命令處理程序代碼
    //m_str = "側視圖yoz";
    CBaseClass my;
    my.cleanMatrice(my.Aw);
    my.Aw[2][1] = -1;
    my.Aw[3][3] = 1;
    my.Aw[4][4] = 1;
    my.Display();
}

 輔助函數 Display()DrawViewV(CDC * pdc, CRect rr)

void CBaseClass::Display()
{
    CFrameWnd* pWnd = (CFrameWnd*)AfxGetApp()->m_pMainWnd;
    CDC* pdc = pWnd->GetActiveView()->GetDC();
    CRect rr;
    ::GetClientRect(pWnd->GetActiveView()->m_hWnd, rr);

    DrawViewV(pdc, rr);
    pWnd->GetActiveView()->ReleaseDC(pdc);
}

void CBaseClass::DrawViewV(CDC * pdc, CRect rr)
{
    xx = rr.right / 2;
    yy = rr.bottom / 2;
    Calculate(A);
    moveto(xx + XT[1], yy - ZT[1], pdc);
    for (int I = 2; I <= 12; ++I)
        lineto(xx + XT[I], yy - ZT[I], pdc);
    moveto(xx + XT[1], yy - ZT[1], pdc);
    lineto(xx + XT[4], yy - ZT[4], pdc);
    moveto(xx + XT[1], yy - ZT[1], pdc);
    lineto(xx + XT[6], yy - ZT[6], pdc);
    moveto(xx + XT[7], yy - ZT[7], pdc);
    lineto(xx + XT[12], yy - ZT[12], pdc);
    moveto(xx + XT[3], yy - ZT[3], pdc);
    lineto(xx + XT[10], yy - ZT[10], pdc);
    moveto(xx + XT[2], yy - ZT[2], pdc);
    lineto(xx + XT[9], yy - ZT[9], pdc);
    moveto(xx + XT[12], yy - ZT[12], pdc);
    lineto(xx + XT[5], yy - ZT[5], pdc);
    moveto(xx + XT[8], yy - ZT[8], pdc);
    lineto(xx + XT[11], yy - ZT[11], pdc);
}

 

軸測投影(正軸測/斜軸測)

軸測投影放棄了可度量性,但增長了必定的真實感(透視圖的真實感最強,但我沒搞懂...)。它的原理,就是讓咱們看到一個物體的儘量多的面。咱們在立體幾何題目中遇到的圖形,通常是斜二測投影得來的,因此我只會畫斜二測...

正等軸測圖,X,Y,Z三個軸之間的角度是120°,而且三個軸的軸向伸縮係數都是1。

斜二軸測圖,X,Y軸之間的角度是135°,X,Z軸之間的角度是90°,Y,Z軸之間的角度是135°,且Y軸的軸向伸縮率爲0.5,X,Z軸的軸向伸縮率爲1。

一、正軸測

 正等測和正二測,在原理上的區別是Tv,即正等測視圖,在旋轉後垂直投影便可;正二測旋轉後,還需在一個軸向上調整觀察位置。。。我在說啥?輕點噴orz。

 同理,可推正三測。

void CGeoTrans3DView::OnVe()
{
    // TODO: 在此添加命令處理程序代碼
    //m_str = "正等側圖";
    CBaseClass my;
    my.theta_y = 45;//Y軸夾角
    my.phi_x = 125;//X軸夾角
    my.cleanMatrice(my.A);
    my.A[1][1] = (float)cos(my.theta_y*PI / 180);
    my.A[1][2] = (float)sin(my.theta_y*PI / 180)*(float)sin(my.phi_x*PI / 180);
    my.A[2][2] = (float)cos(my.phi_x*PI / 180);
    my.A[3][1] = (float)sin(my.theta_y*PI / 180);
    my.A[3][2] = (float)-cos(my.theta_y*PI / 180)*(float)sin(my.phi_x*PI / 180);
    my.A[4][4] = 1;
    my.Drawve();
}


void CGeoTrans3DView::OnVt()
{
    // TODO: 在此添加命令處理程序代碼
    //m_str = "正二側圖";
    CBaseClass my;
    my.theta_y = 115;//Y軸夾角
    my.phi_x = 25;//X軸夾角
    my.cleanMatrice(my.A);
    my.A[1][1] = (float)cos(my.theta_y*PI / 180);
    my.A[1][2] = (float)sin(my.theta_y*PI / 180)*(float)sin(my.phi_x*PI / 180);
    my.A[2][2] = (float)cos(my.phi_x*PI / 180);
    my.A[3][1] = (float)sin(my.theta_y*PI / 180);
    my.A[3][2] = (float)-cos(my.theta_y*PI / 180)*(float)sin(my.phi_x*PI / 180);
    my.A[4][4] = 1;
    my.Drawvt();
}

 輔助函數 Drawve()Drawvt() 同樣,只是換了個位置)

void CBaseClass::Drawve()
{
    int I;
    CFrameWnd* pWnd = (CFrameWnd*)AfxGetApp()->m_pMainWnd;
    CDC* pdc = pWnd->GetActiveView()->GetDC();
    CRect rr;
    ::GetClientRect(pWnd->GetActiveView()->m_hWnd, rr);
    xx = rr.right / 3;
    yy = rr.bottom * 2 / 3;
    MCalculate(A);
    Drawtext();
    moveto(xx + XT[1], yy - YT[1], pdc);
    for (I = 2; I <= 12; ++I)
        lineto(xx + XT[I], yy - YT[I], pdc);
    moveto(xx + XT[1], yy - YT[1], pdc);
    lineto(xx + XT[4], yy - YT[4], pdc);
    moveto(xx + XT[1], yy - YT[1], pdc);
    lineto(xx + XT[6], yy - YT[6], pdc);
    moveto(xx + XT[7], yy - YT[7], pdc);
    lineto(xx + XT[12], yy - YT[12], pdc);
    moveto(xx + XT[3], yy - YT[3], pdc);
    lineto(xx + XT[10], yy - YT[10], pdc);
    moveto(xx + XT[2], yy - YT[2], pdc);
    lineto(xx + XT[9], yy - YT[9], pdc);
    moveto(xx + XT[12], yy - YT[12], pdc);
    lineto(xx + XT[5], yy - YT[5], pdc);
    moveto(xx + XT[8], yy - YT[8], pdc);
    lineto(xx + XT[11], yy - YT[11], pdc);
    pWnd->GetActiveView()->ReleaseDC(pdc);
}

 

二、斜軸測

(投影方向不垂直於投影平面。)

 轉換到矩陣上,即錯切。

void CGeoTrans3DView::OnSe()
{
    // TODO: 在此添加命令處理程序代碼
    //m_str = "斜等側圖";
    CBaseClass my;
    my.cleanMatrice(my.A);
    my.A[1][1] = 1;
    my.A[2][2] = 1;    
    my.A[3][1] = 0.707f;//X方向錯切
    my.A[3][2] = 0.707f;//Y方向錯切
    my.A[4][4] = 1;
    my.Drawse();
}

void CGeoTrans3DView::OnSt()
{
    // TODO: 在此添加命令處理程序代碼
    //m_str = "斜二側圖";
    CBaseClass my;
    my.cleanMatrice(my.A);
    my.A[1][1] = 1;
    my.A[2][2] = 1;
    my.A[3][1] = 0.3535f;//X方向錯切
    my.A[3][2] = 0.3535f;//Y方向錯切
    my.A[4][4] = 1;
    my.Drawst();
}

輔助函數:Drawse(),Drawst() Drawve() 同樣,只是換了個位置

 

參考資料:

一、《計算機圖形學原理及算法教程》和青芳 編著

二、計算機圖形學 - 中國農業大學 趙明老師視頻 

 

本文采用CC BY 4.0知識共享許可協議。

相關文章
相關標籤/搜索