由於我本身也沒太能理解,因此在此就只寫一些些。這麼多分類,看着就頭疼。算法
準備(齊次座標系/圖形)函數
新建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知識共享許可協議。