图13-13 伸缩(1.5, 0.5)
图13-14 镜像文本
Graphics graph(pDC->m_hDC);
Font font(L\宋体\
ifont(L\宋体\
SolidBrush textBrush(Color::Blue), mirrorBrush(Color::Gray); // 普通文本输出
CString str(L\镜像文本\
graph.DrawString(str, str.GetLength(), &font,
PointF(200.0f, 10.0f), &textBrush);
// 垂直镜像文本输出(上下倒置) graph.ScaleTransform(1, -1); graph.TranslateTransform(0, -120);
graph.DrawString(str, str.GetLength(), &ifont,
PointF(200.0f, 10.0f), &mirrorBrush);
// 水平镜像文本输出(左右倒置) graph.ResetTransform(); graph.ScaleTransform(-1, 1); graph.TranslateTransform(-220, 0);
graph.DrawString(str, str.GetLength(), &font,
PointF(0.0f, 10.0f), &mirrorBrush);
// 垂直+水平镜像文本输出(上下左右全倒置) graph.ResetTransform(); graph.ScaleTransform(-1, -1);
graph.TranslateTransform(-220, -120);
graph.DrawString(str, str.GetLength(), &ifont,
PointF(0.0f, 10.0f), &mirrorBrush);
又例如(镜像图像,参见图13-15):
21
Graphics graph(pDC->m_hDC); Image img(L\金泰熙.bmp\
REAL w = REAL(img.GetWidth()), h = REAL(img.GetHeight()); graph.DrawImage(&img, PointF(w, 0)); graph.ScaleTransform(1, -1);
graph.TranslateTransform(0, -2 * h); graph.DrawImage(&img, PointF(w, 0)); graph.ResetTransform(); graph.ScaleTransform(-1, 1); graph.TranslateTransform(-w, 0); graph.DrawImage(&img, PointF(0, 0)); graph.ResetTransform(); graph.ScaleTransform(-1, -1);
graph.TranslateTransform(-w, -2 * h); graph.DrawImage(&img, PointF(0, 0));
图13-15 镜像图像
4.混合变换
也可以将者3种变换结合起来,形成混合变换。注意变换的顺序,顺序不同,结果可能页不一样。
1)先旋转后伸缩——对应齐次坐标矩阵变换为:
?x'??sx00??cosα?sinα0??x??sx?cosα?sx?sinα0??x?????????????y'?0sy0sinαcosα0y?sy?sinαsy?cosα0???????????y? ?1??001??0?????01?001????????1????1?例如(参见图13-16):
Graphics graph(pDC->m_hDC);
Rect rectSquare(30, 10, 100, 100),
rectCircle(140, 10, 100, 100);
graph.DrawRectangle(&Pen(Color::Green), rectSquare); graph.DrawEllipse(&Pen(Color::Green), rectCircle); graph.ScaleTransform(1.5f, 0.5f);
22
graph.RotateTransform(30.0f);
graph.DrawRectangle(&Pen(Color::Red), rectSquare); graph.DrawEllipse(&Pen(Color::Red), rectCircle);
图13-16 旋转30度后再伸缩(1.5, 0.5) 图13-17 伸缩(1.5, 0.5)后再旋转30度 2)先伸缩后旋转——对应齐次坐标矩阵变换为:
?x'??cos?????y'???sin??1??0????sin?cos?00??sx00??x??sx?cos???????0??0sy0??y???sx?sin??????1?0??001??1???sy?sin?sy?cos?00??x????0??y? ??1???1?例如(参见图13-17):
Graphics graph(pDC->m_hDC);
Rect rectSquare(80, 10, 100, 100),
rectCircle(190, 10, 100, 100);
graph.DrawRectangle(&Pen(Color::Green), rectSquare); graph.DrawEllipse(&Pen(Color::Green), rectCircle); graph.RotateTransform(30.0f); graph.ScaleTransform(1.5f, 0.5f);
graph.DrawRectangle(&Pen(Color::Red), rectSquare); graph.DrawEllipse(&Pen(Color::Red), rectCircle);
上面的粗体代码部分,也可以替换为:
graph.ScaleTransform(1.5f, 0.5f);
graph.RotateTransform(30.0f, MatrixOrderAppend); // 右乘,后变换
又例如(旋转正方形,参见图13-18):
Graphics graph(pDC->m_hDC); CRect crect;
GetClientRect(&crect); // 获取当前客户区矩形 PointF cp(REAL(crect.CenterPoint().x),
23
REAL(crect.CenterPoint().y)); // 中心点
RectF rect(cp.X - 10.0f, cp.Y - 10.0f, 20.0f, 20.0f); // 原始矩形 REAL scale = 1.0f; // 初始放大倍数
//REAL scale = 0.0f, ds = 10.0f; // 用于矩形膨胀 for (int i = 0; i <= 360; i += 20) { // 循环 }
graph.TranslateTransform(cp.X, cp.Y); // 设置旋转中心 //rect.Inflate(scale * ds, scale * ds); // 膨胀矩形 graph.ScaleTransform(scale, scale); // 放大 graph.RotateTransform(REAL(i)); // 旋转
graph.TranslateTransform(-cp.X, -cp.Y); // 还原坐标原点 graph.DrawRectangle(&Pen(Color::Green), rect); // 绘制矩形 Sleep(100); // 暂停100毫秒(0.1秒)
graph.ResetTransform(); // 重置所有变换(还原为恒等变换) //rect.Inflate(-scale * ds, -scale * ds); // 还原矩形原大小 scale += 1.0f; // 放大倍数加1
图13-18 旋转并放大矩形
图13-19 旋转并膨胀矩形
在上例中,因为矩形的框线随矩形一起被放大,所以边框越来越粗。如果注释掉语句:
//REAL scale = 1.0f; 和 //graph.ScaleTransform(scale, scale);
并去掉原来的三个注释符,把对整个图形的放大改为只有矩形本身膨胀(inflate):
rect.Inflate(scale * ds, scale * ds);
则框线将保持单个像素粗,输出结果如图13-19。
这里使用了矩形类Rect和RectF的方法Inflate(膨胀):
24
VOID Inflate(INT dx, INT dy); VOID Inflate(const Point& point); VOID Inflate(REAL dx, REAL dy); VOID Inflate(const PointF& point);
将原矩形的左右和上下分别膨胀dx和dy个逻辑单位(默认为像素),矩形的中心不变。
5.矩阵变换
除了上面所讲的3种基本变换外,图形类还可以设置复杂的矩阵变换。有关的方法为:
Status SetTransform(const Matrix *matrix); // 设置变换矩阵为matrix
Status ResetTransform(VOID); // 设置变换矩阵为单位矩阵(恒等变换)(还原) 例如(相当于前面的先旋转后伸缩,参见图13-20):
Graphics graph(pDC->m_hDC);
REAL radian = 3.1415926f / 180.0f;
Rect rectSquare(80/*30*/, 10, 100, 100),
rectCircle(190/*140*/, 10, 100, 100);
REAL sx = 1.5f, sy = 0.5f, a = 30.0f;
REAL m11 = sx * cos(a * radian), m12 = sy /*-sx*/* sin(a * radian),
m21 = -sx/*sy*/ * sin(a * radian), m22 = sy * cos(a * radian), m31 = 0.0f, m32 = 0.0f;
Matrix m(m11, m12, m21, m22, m31, m32);
graph.DrawRectangle(&Pen(Color::Green), rectSquare); graph.DrawEllipse(&Pen(Color::Green), rectCircle); graph.SetTransform(&m);
graph.DrawRectangle(&Pen(Color::Red), rectSquare); graph.DrawEllipse(&Pen(Color::Red), rectCircle);
若将上面rectSquare的X值改为30、rectCircle的X值改为140、m12中的sy改为sx、m21中的-sx改为-sy,则输出结果如图13-21所示(相当于前面的先伸缩后旋转)。
25