GDI+学习之路7--坐标系统和转换

   GDI+ 提供世界变换和页面变换功能,可让您转换 (旋转、缩放、平移等) 所绘制的项目。这两种转换功能适用于各种坐标系统。

坐标系统类型(Types of Coordinate Systems)

GDI+使用三个坐标空间:世界、页面和设备。世界坐标 (World Coordinate) 是用来制作特定绘图自然模型的坐标。页面坐标 (Page Coordinate) 则是指绘图接口 (例如窗体或控件) 使用的坐标系统。设备坐标 (Device Coordinate) 是在其上进行绘图的实体装置 (例如屏幕或纸张) 所使用的坐标。调用 myGraphics.DrawLine(&myPen, 0, 0, 160, 80) 时,传递至DrawLine方法的点(0, 0)和(160, 80)位于世界坐标空间。在 GDI+可以在屏幕上绘制线条之前,坐标会先经过一系列转换。“世界变换”会将世界坐标转换为页面坐标,而“页面变换”则是将页面坐标转换为设备坐标。

假设您想要在一个原点置于客户区域中心处而非左上角的坐标系统中工作。例如,您希望原点位于距离工作区左边缘100像素和距离工作区顶端50像素的位置。下图将显示此坐标系统。

   

         调用 myGraphics.DrawLine(&myPen, 0, 0, 160, 80) 时,您会得到下图中所显示的线条。

         在这三个坐标空间中,您线条的终点坐标位置如下:

世界坐标

(0, 0) - (160, 80)

页面坐标

(100, 50) - (260, 130)

设备坐标

(100, 50) - (260, 130)

         请注意,页面坐标空间的原点一律位于工作区的左上角。此外,由于度量单位为像素,因此设备坐标和页面坐标是相同的。如果您将度量单位设为像素以外的单位 (例如英吋),则设备坐标便与页面坐标不同。

将世界坐标映射到页面坐标称为“世界变换”,由Graphics对象来进行。上例中,全局转换是指在 X方向平移100个单位和在Y方向平移50个单位。下列范例将设定Graphics对象的世界变换,然后使用该Graphics对象来绘制上图所显示的线条:

myGraphics.TranslateTransform(100.0f, 50.0f);

myGraphics.DrawLine(&myPen, 0, 0, 160, 80);

 

注意事项:如果建构画笔时未指定画笔宽度,则上述范例将绘制出一条宽为一英吋的线条。您可以在Pen构造函数的第二个自变量中指定画笔宽度:

Pen myPen(Color(255, 0, 0, 0), 1/myGraphics.GetDpiX()).

 

         如果假设显示设备的水平方向每英吋有 96 个点,且其垂直方向每英吋有 96 个点,则上述范例的线条结束点会分别在三种坐标空间中使用下列坐标:

世界坐标

(0, 0) to (2, 1)

页面坐标

(0, 0) to (2, 1)

设备坐标

(0, 0, to (192, 96)

         您可以结合世界和页面变换来达到各种效果。例如,假设您想要使用英吋做为度量单位,而且想要您的坐标系统的原点位于工作区左边缘的2英吋和工作区顶端的1/2英吋处。下列范例将设定Graphics对象的世界变换和页面变换,然后从(0, 0)到(2, 1)绘制出一条线:

myGraphics.TranslateTransform(2.0f, 0.5f);

myGraphics.SetPageUnit(UnitInch);

myGraphics.DrawLine(&myPen, 0, 0, 2, 1);

如果假设显示设备的水平方向每英吋有 96 个点,且其垂直方向每英吋有 96 个点,则上述范例的线条结束点会分别在三种坐标空间中使用下列坐标:

世界坐标

(0, 0) - (2, 1)

页面坐标

(2, 0.5) - (4, 1.5)

设备坐标

(192, 48) - (384, 144)

以矩阵来表示转换(Matrix Representation of Transformations)

         m×n 阶矩阵是按照 m 行和 n 列排列的一组数字。下图将显示几种矩阵。

您可以利用将各独立的元素相加的方法来实现两个大小相同的矩阵相加。下图将显示两个矩阵加法范例。

         m×n 阶矩阵可乘以 n×p 阶矩阵,其产生的结果便为 m×p 阶矩阵。第一个矩阵的列数目必须和第二个矩阵的数据列数目相同。例如,4×2 阶矩阵可乘以 2×3 阶矩阵以产生 4×3 阶矩阵。

平面上的点和矩阵的行列都可视为向量。例如,(2, 5) 是具有两个分量的向量,而 (3, 7, 1) 是具有三个分量的向量。两个向量的点乘定义如下:

(a, b) • (c, d) = ac + bd

(a, b, c) • (d, e, f) = ad + be + cf

例如,(2, 3) 和 (5, 4)的点乘等于 (2)(5) + (3)(4) = 22。(2, 5, 1) 和 (4, 3, 1) 的点乘等于 (2)(4) + (5)(3) + (1)(1) = 24。请注意,这两种向量的点乘是数字,而非另一个向量。此外,只有当这两个向量拥有相同的分量数目时,您才可以进行点乘运算。

假设 A(i, j) 是矩阵A第i行和第j列的项目。例如A(3, 2)是矩阵A第3行和第2列的项目。假设 A、B 和 C 都是矩阵,而AB = C。则C项目的计算结果如下:

C(i, j) = (A的第i行) • (B的第j列)

下图将显示几个矩阵乘法的范例。


 

         如果将平面中的点视为一个1×2阶矩阵,您可以将该矩阵乘以2×2阶矩阵以进行转换。下图将说明数个应用于点(2, 1)的转换。

         上图所显示的所有转换皆为线性转换。当然其它转换(例如平移)是非线性的,而且无法乘以 2×2 矩阵来表示。假设您想要以点(2, 1)做为开始、将它旋转90度、在X方向平移3个单位和在Y方向平移4个单位。您可以使用矩阵乘法之后再使用矩阵加法来达到这个目的。

         在线性变换(乘以2×2阶矩阵)后再进行平移变换(加上一个1×2阶矩阵)的变换称为仿射变换。另一种将仿射变换储存为矩阵组 (其中一个做为线性部分,另一个做为平移部分) 的方法是将整个转换储存在3×3矩阵中。若要执行这项工作,平面的其中一点必须以虚设的第三坐标储存于1×3阶矩阵中。常用的技巧是让所有第三坐标都为1,例如,点(2, 1)便以矩阵[2 1 1]表示。下图将显示仿射变换 (旋转90度;在X方向平移3个单位、在Y方向平移4个单位) 将乘以 3×3 矩阵来表示。

         例中,点 (2, 1) 将映射到点 (2, 6)。请注意,3×3 阶矩阵的第三个列包含数字 0, 0, 1。仿射变换的 3×3 阶矩阵一律都是这样。第1列和第2列中的六个数字非常重要。矩阵的左上2×2部分代表转换的线性部分,而第三个数据列的前两个项目则代表转换。

         在GDI+中,您可以将仿射变换储存在Matrix对象中。由于用来表示仿射转换的矩阵第三列永远为 (0, 0, 1),因此在建立Matrix对象时,您只能指定前两个数据行中的六个数字。语句Matrix myMatrix = new Matrix(0, 1, -1, 0, 3, 4) 表示构造上图中显示的矩阵。

复合转换

         复合转换由一系列转换构成,一个接着另一个。举下表的矩阵和转换为例:

矩阵 A

旋转 90 度

矩阵 B

在 X 方向缩放 2 个系数

矩阵 C

在 Y 方向平移 3 个单位

         如果我们从点 (2, 1) 开始 (以矩阵 [2 1 1] 代表),并且乘以 A,然后乘以 B,再乘以 C,则点 (2, 1) 将会依照列出的顺序经历三种转换。

         [2 1 1]ABC = [ –2 5 1]

如果不想将复合转换的三个部分分别储存在三个矩阵中,您可以同时乘以 A、B 和 C 以取得储存整个复合转换的单个 3×3 阶矩阵。假设 ABC = D。则任何一个点乘以 D 所得的结果都等于任何一个点乘以 A、然后 B、然后 C。

[2 1 1]D = [ –2 5 1]

下图将显示矩阵 A、B、C 和 D。

         因为乘以单个转换矩阵可形成复合转换的矩阵,这表示仿射转换的任何序列都可以储存在单个Matrix对象中。

注意

复合转换的顺序非常重要。通常,旋转、然后缩放、然后转换与缩放、然后旋转、然后在转换并不相同。同样的,矩阵乘法的顺序也很重要。一般而言,ABC 与 BAC 并不相同。

Matrix类提供几个方法,用来构建复合转换:Multiply、Rotate、RotateAt、Scale、Shear和Translate。下列范例建立复合转换矩阵,它会先旋转30度、然后在Y方向缩放2个系数,然后在X方向平移5个单位:

Matrix myMatrix;

myMatrix.Rotate(30.0f);

myMatrix.Scale(1.0f, 2.0f, MatrixOrderAppend);

myMatrix.Translate(5.0f, 0.0f, MatrixOrderAppend);

全局和局部转换(Global and local Transformations)

         全局转换应用于特定Graphics对象绘制的所有项目。相对地,区域转换只应用于要绘制的特定项目。如果要建立全局转换,请建立Graphics对象,然后调用它的Graphics::SetTransform方法。Graphics::SetTransform方法处理一个与Graphics对象相关的Matrix对象。储存在Matrix对象的变换称为世界变换。世界变换可以是一个简单的仿射变换或者一系列复杂的仿射变换,但是不管有多复杂,世界变换都只存储在单独一个Matrix对象中。

Graphics类提供几个方法,用来建置复合的全局转换:Graphics::MultiplyTransform、Graphics::RotateTransform、Graphics::ScaleTransform和Graphics::TranslateTransform。下列范例会绘制两次椭圆形:一次是在建立世界变换之前,一次是在建立之后。转换会先在 Y 方向缩放 0.5 个系数,然后在 X 方向转换 50 个单位,然后再旋转 30 度。

myGraphics.DrawEllipse(&myPen, 0, 0, 100, 50);

myGraphics.ScaleTransform(1.0f, 0.5f);

myGraphics.TranslateTransform(50.0f, 0.0f, MatrixOrderAppend);

myGraphics.RotateTransform(30.0f, MatrixOrderAppend);

myGraphics.DrawEllipse(&myPen, 0, 0, 100, 50);

         下图显示了原始椭圆和变形后的椭圆:

         下图将显示转换所使用的矩阵。

注意事項

在上述范例中,椭圆形会绕着坐标系统的原点旋转,该原点位于工作区的左上角。该操作产生的结果和在椭圆形中心点旋转并不相同。

局部转换应用于要绘制的特定项目。例如,GraphicsPath对象的GraphicsPath::Transform方法可用来转换该路径的数据点。下列范例绘制一个未转换的矩形和一个经过旋转变换的路径 (假设没有世界变换)。

Matrix myMatrix;

myMatrix.Rotate(45.0f);

myGraphicsPath.Transform(&myMatrix);

myGraphics.DrawRectangle(&myPen, 10, 10, 100, 50);

myGraphics.DrawPath(&myPen, &myGraphicsPath);

         您可以结合全局转换和局部转换来达到各种效果。例如,您可以使用全局转换来修订坐标系统,并可使用局部转换来旋转和缩放新坐标系统所绘制的对象。

假设您想要使用一个坐标系统,其原点距离工作区左边缘 200 像素和工作区顶端 150 像素处。此外,假设您想使用像素做为度量单位,其 x 轴指向右方,且其 y 轴指向上方。预设坐标系统的 y 轴指向下方,因此您必须沿着水平轴执行反射。下图将显示此类反射的矩阵。

         接下来,假设您必须执行向右200单位和向下150 单位的平移。

下列范例会建立上述说明的坐标系统,使用的方法是设定 Graphics 对象的全局转换。

Matrix myMatrix(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);

myGraphics.SetTransform(&myMatrix);

myGraphics.TranslateTransform(200.0f, 150.0f, MatrixOrderAppend);

下列程序代码 (放到上述范例的结束处) 建立单一矩形组成的路径,其中该矩形的左上角位于新坐标系统的原点。该矩形将填入色彩两次,其中一次并未使用区域转换,另外一次则使用区域转换。区域转换包括水平缩放 2 个系数,随后进行 30 度的旋转。

// Create the path.

GraphicsPath myGraphicsPath;

Rect myRect(0, 0, 60, 60);

myGraphicsPath.AddRectangle(myRect);

 

// Fill the path on the new coordinate system.

// No local transformation

myGraphics.FillPath(&mySolidBrush1, &myGraphicsPath);

 

// Transform the path.

Matrix myPathMatrix;

myPathMatrix.Scale(2, 1);

myPathMatrix.Rotate(30, MatrixOrderAppend);

myGraphicsPath.Transform(&myPathMatrix);

 

// Fill the transformed path on the new coordinate system.

myGraphics.FillPath(&mySolidBrush2, &myGraphicsPath);

         下图将显示新的坐标系统和两个矩形。

http://blog.csdn.net/backo880607/article/details/6439957
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值