C++,MFC模板,VS2017
准备(2D图形、矩阵、坐标系)
typedef double array2d[5][5];
typedefdouble array[24];classCMyClass
{public:intxx, yy;//屏幕
array X, Y, Z, C;
array2d A1, A;//矩阵public:
CMyClass();virtual ~CMyClass();voidCalculate(array2d B);//矩阵计算voidDisplay();//显示void DrawView(CDC*pdc, CRect rr);//在坐标系内画图void moveto(double x, double y, CDC*pdc);void lineto(double x, double y, CDC*pdc);voidcleanB(array2d B);//矩阵复位
};
1、2D图形
(可使用CDC类的成员函数GetMapMode和SetMapMode来获得和设置当前映射模式:
int GetMapMode( ) const; // 返回当前的映射模式
virtual int SetMapMode( int nMapMode ); // 返回先前的映射模式)
在默认映射模式(MM_TEXT)下:
代码(给到了初始化):
CMyClass::CMyClass()
{
X[1] = 20; Y[1] = -20; C[1] = 1;
X[2] = 20; Y[2] = -80; C[2] = 1;
X[3] = 40; Y[3] = -60; C[3] = 1;
X[4] = 60; Y[4] = -80; C[4] = 1;
X[5] = 60; Y[5] = -20; C[5] = 1;
X[6] = 25; Y[6] = -20; C[6] = 1;
X[7] = 25; Y[7] = -70; C[7] = 1;
X[8] = 40; Y[8] = -50; C[8] = 1;
X[9] = 55; Y[9] = -70; C[9] = 1;
X[10] = 55; Y[10] = -20; C[10] = 1;
}
2、矩阵
矩阵计算:
voidCMyClass::Calculate(array2d B)
{
for (int i = 1; i <= 10; ++i) {
X[i]= X[i] * B[1][1] + Y[i] * B[2][1] + C[i] * B[3][1];
Y[i]= X[i] * B[1][2] + Y[i] * B[2][2] + C[i] * B[3][2];
}
}
矩阵清零:
voidCMyClass::cleanB(array2d B)
{inti, j;for (i = 1; i <= 3; ++i) {for (j = 1; j <= 3; ++j) {
B[i][j]= 0;
}
}
}
3、坐标系
以屏幕中点为原点,x向右,y向上为正方向
void CGeoTrans2DView::OnDraw(CDC*pDC)
{
CGeoTrans2DDoc* pDoc =GetDocument();
ASSERT_VALID(pDoc);if (!pDoc)return;//TODO: 在此处为本机数据添加绘制代码//画坐标系
RECT rectWnd;
GetClientRect(&rectWnd);//获取窗口大小
pDC->MoveTo(rectWnd.right / 2 , rectWnd.bottom / 2 - 200);
pDC->LineTo(rectWnd.right / 2 , rectWnd.bottom / 2 + 200);
pDC->MoveTo(rectWnd.right / 2 - 200, rectWnd.bottom / 2);
pDC->LineTo(rectWnd.right / 2 + 200, rectWnd.bottom / 2);
ReleaseDC(pDC);//绘制字符图形CMyClass my1;//A1 矩阵清零
my1.cleanB(my1.A1);//A1 矩阵赋值
my1.A1[1][1] = 1;
my1.A1[2][2] = 1;
my1.A1[3][3] = 1;//A 矩阵清零
my1.cleanB(my1.A);
my1.Display();
}
基本变换(平移、旋转、缩放、对称)
(两种矩阵表示方式)以下采用第一种表示方式:
1、平移
只改变矩阵 [3] [1],[3] [2] 位置的值即可:
M平移了(x+15,y+45)
voidCGeoTrans2DView::OnTranslation()
{//TODO: 在此添加命令处理程序代码
CMyClass my;
my.cleanB(my.A1);
my.A1[1][1] = 1;
my.A1[2][2] = 1;
my.A1[3][3] = 1;
my.A1[3][1] = 15;
my.A1[3][2] = -45;
my.Display();
}
2、旋转
只改变矩阵 [1] [1],[1] [2],[2] [1],[2] [2] 位置的值:
逆时针旋转30°
voidCGeoTrans2DView::OnRotation()
{//TODO: 在此添加命令处理程序代码
CMyClass my;
my.cleanB(my.A1);
my.A1[1][1] = cos(PI / 6);
my.A1[1][2] = -sin(PI / 6);
my.A1[2][1] = sin(PI / 6);
my.A1[2][2] = cos(PI / 6);
my.A1[3][3] = 1;
my.Display();
}
3、缩放
该代码没有对Z进行处理,所以此处用下面的一种方法(有误:应该是放大 1/x 倍),是不可行的
voidCGeoTrans2DView::OnScaling()
{//TODO: 在此添加命令处理程序代码
CMyClass my;
my.cleanB(my.A1);
my.A1[1][1] = 3;
my.A1[2][2] = 3;
my.A1[3][3] = 1;
my.Display();
}
4、对称
x轴对称
voidCGeoTrans2DView::OnMirrorX()
{//TODO: 在此添加命令处理程序代码
CMyClass my;
my.cleanB(my.A1);
my.A1[1][1] = 1;
my.A1[2][2] = -1;
my.A1[3][3] = 1;
my.Display();
}
复合变换(级联)
级联变换:一种以上的基本变换
1、非原点缩放
以(-40,-40)为中心,放大3倍
voidCGeoTrans2DView::OnScalingxy()
{//TODO: 在此添加命令处理程序代码
CMyClass my;
my.cleanB(my.A1);
my.cleanB(my.A);//将(-40,-40)移到原点
my.A1[1][1] = 1;
my.A1[2][2] = 1;
my.A1[3][3] = 1;
my.A1[3][1] = 40;
my.A1[3][2] = -40;
my.Calculate(my.A1);//缩放3
my.A[1][1] = 3;
my.A[2][2] = 3;
my.A[3][3] = 1;
my.Calculate(my.A);//从原点复位
my.cleanB(my.A1);
my.A1[1][1] = 1;
my.A1[2][2] = 1;
my.A1[3][3] = 1;
my.A1[3][1] = -40;
my.A1[3][2] = 40;
my.Calculate(my.A1);
my.Display();
}
2、非原点旋转
绕(0,40)旋转60°
voidCGeoTrans2DView::OnRotationxy()
{//TODO: 在此添加命令处理程序代码
CMyClass my;
my.cleanB(my.A1);
my.cleanB(my.A);//将(0,40)移到原点
my.A1[1][1] = 1;
my.A1[2][2] = 1;
my.A1[3][3] = 1;
my.A1[3][2] = 40;
my.Calculate(my.A1);//旋转60°
my.A[1][1] = cos(PI / 3);
my.A[1][2] = -sin(PI / 3);
my.A[2][1] = sin(PI / 3);
my.A[2][2] = cos(PI / 3);
my.A[3][3] = 1;
my.Calculate(my.A);//从原点复位
my.cleanB(my.A1);
my.A1[1][1] = 1;
my.A1[2][2] = 1;
my.A1[3][3] = 1;
my.A1[3][2] = -40;
my.Calculate(my.A1);
my.Display();
}
参考资料:
1、《计算机图形学原理及算法教程》和青芳 编著
2、计算机图形学 - 中国农业大学 赵明老师视频
本文采用CC BY 4.0知识共享许可协议。