二维图形变换
一.目的:
1.了解不同的二维坐标变换公式。
2.掌握二维坐标变换公式的使用方法。
3.掌握二维图形的基本几何变换:平移、旋转和缩放。
二.要求:
1.在屏幕上绘制出较简单的几何图形。
2.对1的图形进行平移变换(每次平移一个单位),绘制出变换后的几何图形。
3.对1的图形进行旋转变换(每次旋转角度为3.14/36),绘制出变换后的几何图形。
4.对1的图形进行比例变换(横纵坐标变换比例为0.5或2),绘制出变换后的几何图形。
三.原理和关键算法:
1. 编辑一个资源,并为其映射一个类cgTransControl。
2. 在Doc下,定义空间变换矩阵
float m_LineTransMatria【3】【2】;
float m_PolyTransMatria【3】【2】.
3. 定义一条空间线段和一个空间多边形,本例为三角形。
4. 二维图形变换主要是基于齐次坐标方程,通过一些简单的矩阵运算来实现:
二维齐次坐标变换的矩阵形式是:
矩阵的每个元素都有特殊含义。其中可以对图形进行缩放,旋转等变换;
是对图形进行平移变换;
则是对图形整体进行缩放变换.
5. 平移变换:
将一个图形在X方向中平移tx个单位,在Y方向平移ty个单位.其实现过程如下:
其中:x1,y1是变换后的坐标,x,y是变换前的坐标,通过上述变换,(x,y)被平移了P(tx,ty). 在二维平面上任何复杂的变换都可以通过上述基本变换的组合来实现.在计算机上主要体现在矩阵的乘法运算,即将各个简单变换的矩阵逆序相乘,就可以得到一个总的变换矩阵.利用这个总的变换矩阵就可以对图形进行复合变换.
6. 旋转变化:
7. 放缩变换:
四.关键代码:
1. 绘制初始直线和多边形,并将变换后的图形绘出:
void CCg_WuPing2DtransView::pDrawScene(CDC* pDC)
{
CCg_WuPing2DtransDoc* pDoc = GetDocument();
// Draw coordinate
pDC->MoveTo(m_wndWidth/2, 0);
pDC->LineTo(m_wndWidth/2, m_wndHeight);
pDC->MoveTo( 0, m_wndHeight/2);
pDC->LineTo(m_wndWidth, m_wndHeight/2);
if (pDoc->m_objSelect < 2) pCalTransMatrix();
// Line Object trans and clip
float tx1,ty1,tx2,ty2;
int itx1,ity1,itx2,ity2;
tx1 = pDoc->x1; ty1 = pDoc->y1;
tx2 = pDoc->x2; ty2 = pDoc->y2;
pTrans2Dpoint(&tx1, &ty1);
pTrans2Dpoint(&tx2, &ty2);
pDC->MoveTo(m_wndWidth/2+tx1, m_wndHeight/2-ty1);
pDC->LineTo(m_wndWidth/2+tx2, m_wndHeight/2-ty2);
pDoc->m_lineVisible = false;
itx1 = tx1; itx2 = tx2;
ity1 = ty1; ity2 = ty2;
if (ClipLine(&itx1, &ity1, &itx2, &ity2)) {
CPen newPen;
CPen *oldPen;
// Create new color pen to Draw Clipping Line
newPen.CreatePen(PS_SOLID, 2, RGB(255, 250, 0));
oldPen = (CPen *)pDC->SelectObject(&newPen);
pDC->MoveTo(itx1+m_wndWidth/2, m_wndHeight/2-ity1);
pDC->LineTo(itx2+m_wndWidth/2, m_wndHeight/2-ity2);
pDC->SelectObject(oldPen);
newPen.DeleteObject();
pDoc->cx1 = itx1; pDoc->cx2 = itx2;
pDoc->cy1 = ity1; pDoc->cy2 = ity2;
pDoc->m_lineVisible = true;
}
// polygon Object trans and clip
float tx[16],ty[16];
for (int i = 0; i < pDoc->m_polyPoints; i++)
{
tx[i] = pDoc->m_polyPointsX[i];
ty[i] = pDoc->m_polyPointsY[i];
}
pTrans2Dpoints(pDoc->m_polyPoints, tx, ty);
pDC->MoveTo(m_wndWidth/2+tx[0], m_wndHeight/2-ty[0]);
for (i = 1; i < pDoc->m_polyPoints; i++)
pDC->LineTo(m_wndWidth/2+tx[i], m_wndHeight/2-ty[i]);
pDoc->m_polyVisible = false;
int points = pDoc->m_polyPoints,xx[16],yy[16],cn,cx[16],cy[16];
for (i = 0; i < pDoc->m_polyPoints; i++)
{
xx[i] = tx[i];
yy[i] = ty[i];
}
if (ClipPolygon(pDoc->m_polyPoints, xx, yy, &cn, cx, cy))
{
CPen newPen;
CPen *oldPen;
// Create new color pen to Draw Clipping Line
newPen.CreatePen(PS_SOLID, 2, RGB(255, 0, 0));
oldPen = (CPen *)pDC->SelectObject(&newPen);
pDC->MoveTo(cx[0]+m_wndWidth/2, m_wndHeight/2-cy[0]);
for (i = 0; i < cn; i++)
pDC->LineTo(cx[i]+m_wndWidth/2, m_wndHeight/2-cy[i]);
pDC->LineTo(cx[0]+m_wndWidth/2, m_wndHeight/2-cy[0]);
pDC->SelectObject(oldPen);
newPen.DeleteObject();
pDoc->m_clipPolyPoints = cn;
for (i = 0; i < cn; i++ )
{
pDoc->m_polyClipPointsX[i] = cx[i];
pDoc->m_polyClipPointsY[i] = cy[i];
}
pDoc->m_polyVisible = true;
}
pDC->MoveTo(m_wndWidth/2+pDoc->m_wndRectangle[0], m_wndHeight/2-pDoc->m_wndRectangle[3]);
pDC->LineTo(m_wndWidth/2+pDoc->m_wndRectangle[1], m_wndHeight/2-pDoc->m_wndRectangle[3]);
pDC->LineTo(m_wndWidth/2+pDoc->m_wndRectangle[1], m_wndHeight/2-pDoc->m_wndRectangle[2]);
pDC->LineTo(m_wndWidth/2+pDoc->m_wndRectangle[0], m_wndHeight/2-pDoc->m_wndRectangle[2]);
pDC->LineTo(m_wndWidth/2+pDoc->m_wndRectangle[0], m_wndHeight/2-pDoc->m_wndRectangle[3]);
// Tell CgTransControl the process finish now.
pDoc->UpdateAllViews(this);
}
2. 变换操作:分别实现四个方向的变换:(-X,+X,-Y,+Y)
void CCg_WuPing2DtransView::pCalTransMatrix()
{
CCg_WuPing2DtransDoc* pDoc = GetDocument();
switch (pDoc->m_transDir) {
case 0: // -X
if (pDoc->m_transMode == 0) pCal2DTranslateMatrix(-10.0, 0.0);
else if (pDoc->m_transMode == 1) pCal2DRotateMatrix(sin(3.14/36), cos(3.14/36));
else pCal2DScaleMatrix(0.5, 1.0);
break;
case 1: // +X
if (pDoc->m_transMode == 0) pCal2DTranslateMatrix(10.0, 0.0);
else if (pDoc->m_transMode == 1) pCal2DRotateMatrix(-sin(3.14/36), cos(3.14/36));
else pCal2DScaleMatrix(2.0, 1.0);
break;
case 2: // +Y
if (pDoc->m_transMode == 0) pCal2DTranslateMatrix(0.0, +10.0);
else if (pDoc->m_transMode == 1) pCal2DRotateMatrix(-sin(3.14/36), cos(3.14/36));
else pCal2DScaleMatrix(2.0, 1.0);
break;
case 3: // -Y
if (pDoc->m_transMode == 0) pCal2DTranslateMatrix(0.0, -10.0);
else if (pDoc->m_transMode == 1) pCal2DRotateMatrix(sin(3.14/36), cos(3.14/36));
else pCal2DScaleMatrix(0.5, 1.0);
break;
}
}
3.平移变换:
void CCg_WuPing2DtransView::pCal2DTranslateMatrix(float Tx, float Ty)//平移变换
{
CCg_WuPing2DtransDoc * pDoc = (CCg_WuPing2DtransDoc*)GetDocument();
if(pDoc ->m_objSelect == 0)
{
pDoc->m_lineTransMatrix[2][0] = pDoc ->m_lineTransMatrix[2][0] + Tx;
pDoc ->m_lineTransMatrix[2][1] = pDoc ->m_lineTransMatrix[2][1] + Ty;
}
if(pDoc ->m_objSelect == 1)
{
pDoc->m_polyTransMatrix[2][0] = pDoc->m_polyTransMatrix[2][0] + Tx;
pDoc->m_polyTransMatrix[2][1] = pDoc->m_polyTransMatrix[2][1] + Ty;
}
}
4. 旋转变换:
void CCg_WuPing2DtransView::pCal2DRotateMatrix(float S, float C)//旋转变换
{
CCg_WuPing2DtransDoc* pDoc = (CCg_WuPing2DtransDoc*)GetDocument();
if(pDoc ->m_objSelect == 0)
{
float temp1,temp2;
temp1 = pDoc ->m_lineTransMatrix[0][0];
temp2 = pDoc ->m_lineTransMatrix[1][0];
pDoc ->m_lineTransMatrix[0][0] = pDoc ->m_lineTransMatrix[0][0]*C-pDoc ->m_lineTransMatrix[0][1]*S;
pDoc ->m_lineTransMatrix[0][1] = temp1*S + pDoc ->m_lineTransMatrix[0][1]*C;
pDoc ->m_lineTransMatrix[1][0] = pDoc ->m_lineTransMatrix[1][0]*C-pDoc ->m_lineTransMatrix[1][1]*S;
pDoc ->m_lineTransMatrix[1][1] = temp2*S+pDoc ->m_lineTransMatrix[1][1]*C;
}
if(pDoc ->m_objSelect == 1)
{
float temp1,temp2;
temp1 = pDoc ->m_polyTransMatrix[0][0];
temp2 = pDoc ->m_polyTransMatrix[1][0];
pDoc ->m_polyTransMatrix[0][0] = pDoc ->m_polyTransMatrix[0][0]*C-pDoc ->m_polyTransMatrix[0][1]*S;
pDoc ->m_polyTransMatrix[0][1] = temp1*S + pDoc ->m_polyTransMatrix[0][1]*C;
pDoc ->m_polyTransMatrix[1][0] = pDoc ->m_polyTransMatrix[1][0]*C-pDoc ->m_polyTransMatrix[1][1]*S;
pDoc ->m_polyTransMatrix[1][1] = temp2*S+pDoc ->m_polyTransMatrix[1][1]*C;
}
}
5. 比例变换:
void CCg_WuPing2DtransView::pCal2DScaleMatrix(float Sx, float Sy)// 比例变换
{
CCg_WuPing2DtransDoc* pDoc = (CCg_WuPing2DtransDoc*)GetDocument();
if(pDoc ->m_objSelect == 0)
{
pDoc ->m_lineTransMatrix[0][0] = pDoc ->m_lineTransMatrix[0][0] * Sx;
pDoc ->m_lineTransMatrix[1][1] = pDoc ->m_lineTransMatrix[1][1] * Sy;
}
if(pDoc ->m_objSelect == 1)
{
pDoc ->m_polyTransMatrix[0][0] *= Sx;
pDoc ->m_polyTransMatrix[1][1] *= Sy;
}
}
6. 实现自动变换操作:
调用以下函数:
void CCg_WuPing2DtransView::OnTimer(UINT nIDEvent)
void CCg_WuPing2DtransView::OnOutoplay()
void CCg_WuPing2DtransView::OnUpdateOutoplay(CCmdUI* pCmdUI)
五.结果及分析:
1. 对话界面:
2. 平移变换:
3. 旋转变换:
4. 比例变换: