第五章 使用变换
Graphics类的Transformation方法提供了变换。主要的变换方法有TranslateTransform、ScaleTransform和RotateTransform,分别实现平移、缩放和旋转。
平移变换
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics gr = e.Graphics;
Pen p = new Pen(Color.Red, 5);
Rectangle rect = new Rectangle(0, 0, 200, 150);
gr.DrawRectangle(p, rect);
gr.TranslateTransform(150, 50);
p.Color = Color.Blue;
gr.DrawRectangle(p, rect);
gr.Dispose();
p.Dispose();
}
缩放变换
//下面的函数使用形参gr在-1 <= x <= 1, -1 <= y <= 1内绘制一个笑脸
private void DrawSmiley(Graphics gr)
{
using (Pen thin_pen = new Pen(Color.Blue, 0))
{
gr.FillEllipse(Brushes.Yellow, -1, -1, 2, 2);
gr.DrawEllipse(thin_pen, -1, -1, 2, 2);
gr.DrawArc(thin_pen, -0.75f, -0.75f, 1.5f, 1.5f, 0, 180);
gr.FillEllipse(Brushes.Red, -0.2f, -0.2f, 0.4f, 0.6F);
gr.FillEllipse(Brushes.White, -0.5f, -0.6f, 0.3f, 0.5F);
gr.DrawEllipse(thin_pen, -0.5f, -0.6f, 0.3f, 0.5F);
gr.FillEllipse(Brushes.Black, -0.4f, -0.5f, 0.2f, 0.3F);
gr.FillEllipse(Brushes.White, 0.2f, -0.6f, 0.3f, 0.5F);
gr.DrawEllipse(thin_pen, 0.2f, -0.6f, 0.3f, 0.5F);
gr.FillEllipse(Brushes.Black, 0.3f, -0.5f, 0.2f, 0.3F);
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
// Draw 50x50 pixels.
e.Graphics.ScaleTransform(50, 50);
e.Graphics.TranslateTransform(60, 60, MatrixOrder.Append);
DrawSmiley(e.Graphics);
e.Graphics.ResetTransform();
}
效果如下:
先将其放大了50倍,然后平移过来,最后重设变换。
旋转变换
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.TranslateTransform(150, 150);
Rectangle rect=new Rectangle(0,0,100,100);
for (int i = 0; i < 36; i++)
{
e.Graphics.RotateTransform(10);
e.Graphics.DrawArc(Pens.Blue, rect, 0, 360);
}
e.Graphics.ResetTransform();
}
注意变换是一个累积过程。如果进行一下组合,将会有许多奇妙的图形出现,下图是在旋转后添加了一个语句:e.Graphics.ScaleTransform(1.1f, 0.9f);
如果是在前面添加:
可以发现效果是不一样的。所以,顺序很重要。
世界坐标系的映射
将世界坐标系映射到设备坐标系(图形对象)上去。这样画图将会简单多了。
下面的方法将实现世界坐标系到设备坐标系的矩形映射。
private void MapRectangles(Graphics gr, RectangleF WorldRect, RectangleF DeviceRect)
{
PointF[] DevicePoints=new PointF[3];
//三点分别是设备坐标系的左上、右上和左下
DevicePoints[0] = new PointF(DeviceRect.Left, DeviceRect.Top);
DevicePoints[1] = new PointF(DeviceRect.Left + DeviceRect.Width, DeviceRect.Top);
DevicePoints[2] = new PointF(DeviceRect.Left, DeviceRect.Top + DeviceRect.Height);
//映射矩形到点
gr.Transform = new Matrix(WorldRect, DevicePoints);
}
然后是绘制数据的窗口:
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
const int MIN_YEAR = 1990;
const int MAX_YEAR = 2001;
const int MIN_SALES = 0;
const int MAX_SALES = 30000000;
MapRectangles(e.Graphics, new RectangleF(MIN_YEAR,MIN_SALES,MAX_YEAR-MIN_YEAR,MAX_SALES-MIN_SALES), this.ClientRectangle);
// 数据
Point[] sales_data = {
new Point(1990, 4000000),
new Point(1991, 3000000),
new Point(1992, 5000000),
new Point(1993, 10000000),
new Point(1994, 9000000),
new Point(1995, 14000000),
new Point(1996, 19000000),
new Point(1997, 18000000),
new Point(1998, 22000000),
new Point(1999, 27000000),
new Point(2000, 30000000)};
using (Pen thin_pen = new Pen(Color.Green, 0))
{
foreach (Point pt in sales_data)
{
e.Graphics.FillRectangle(Brushes.PaleGreen, pt.X, 0, 1, pt.Y);
e.Graphics.DrawRectangle(thin_pen, pt.X, 0, 1, pt.Y);
}
//画连线
e.Graphics.TranslateTransform(0.5f, 0f, MatrixOrder.Prepend);
thin_pen.Color = Color.Red;
e.Graphics.DrawLines(thin_pen, sales_data);
}
}
效果如下:
现在的问题是,图形画反了,如果能够将上下倒过来就OK了,可以修改一下MapRectangles方法中的映射点:
DevicePoints[0] = new PointF(DeviceRect.Left, DeviceRect.Top + DeviceRect.Height);
DevicePoints[1] = new PointF(DeviceRect.Left + DeviceRect.Width, DeviceRect.Top + DeviceRect.Height);
DevicePoints[2] = new PointF(DeviceRect.Left, DeviceRect.Top);
再运行一下:
另外,可以实现垂直翻转和水平翻转的功能。
private void VerticalFilp(Graphics gr,Rectangle rect)
{
PointF[] PArr = new PointF[3];
PArr[0] = new PointF(rect.Left, rect.Top + rect.Height);
PArr[1] = new PointF(rect.Left + rect.Width, rect.Top + rect.Height);
PArr[2] = new PointF(rect.Left, rect.Top);
gr.Transform = new Matrix(rect, PArr);
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Pen p = new Pen(Color.BlueViolet,5f);
Point[] ps = new Point[4];
ps[0] = new Point(0, 0);
ps[1] = new Point(100, 0);
ps[2] = new Point(0, 100);
ps[3] = new Point(100, 100);
e.Graphics.DrawLines(p, ps);
VerticalFilp(e.Graphics,new Rectangle(0,0,100,100));
e.Graphics.TranslateTransform(150, 0, MatrixOrder.Append);
e.Graphics.DrawLines(p,ps);
}
这将输出垂直翻转的Z:
变换也可运用到文字和图片上。