因為我自己也沒太能理解,所以在此就只寫一些些,這么多分類,看著就頭疼,

準備(齊次坐標系/圖形)
新建BaseClass類(.h .cpp),添加必要的引數和函式,
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); };
(一些基本函式上一篇給過了,就不再贅述了,另一些輔助函式,用到時再說,)
1、齊次坐標系

線代的話,高中水平就夠了,齊次坐標系的使用,是為了讓平移運算可以和旋轉、縮放等運算一起處理,這里不再贅述基本變換,
2、圖形

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; }
三視圖
(這里的投影平面和主視圖為xoz面,)

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

主視圖直接垂直投影;俯視圖垂直投影后,繞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,

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); }
2、斜軸測
(投影方向不垂直于投影平面,)

轉換到矩陣上,即錯切,
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() 一樣,只是換了個位置
參考資料:
1、《計算機圖形學原理及演算法教程》和青芳 編著
2、計算機圖形學 - 中國農業大學 趙明老師視頻
本文采用CC BY 4.0知識共享許可協議,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/5183.html
標籤:其他
上一篇:圖形學基礎(二)圖形變換_上:2D 基本變換/復合變換
下一篇:Bresenham演算法理解
