博客园  :: 首页  :: 联系 :: 管理

使用GDI+坐标系统

Posted on 2007-09-18 14:18  sunrack  阅读(2077)  评论(1编辑  收藏  举报

坐标系统分为三类:全局坐标系统、页面坐标系统和设备坐标系统。页面坐标系与设备坐标系都是以设备的左上角为坐标原点,X水平向右为正,Y垂直向下为正。页面坐标与设备坐标系的差异在于XY的单位不同:页面坐标系中的XY单位可以任意设定,如英寸、毫米等;而设备坐标系中,只有一种单位,那就是点或者像素。

全局坐标系就是我们日常工作的坐标系,缺省情况下x轴正方向水平向右,Y轴正方向垂直向下;我们可以将其进行旋转、平移等操作。

页面坐标系是不能更改的,它是一个参照标准,将全局坐标最终转换为设备坐标。

设备坐标系跟具体的设备有关,在显示器中,基本的单位是像素,在打印机中,基本单位是点(point)。

myGraphics.TranslateTransform(2, 0.5F)
myGraphics.SetPageUnit(UnitInch);
myGraphics.DrawLine(&myPen, 0, 0, 2, 1)

全局

(0, 0) (2, 1)

(2, 0.5) (4, 1.5)

设备

(192, 48) (384, 144)

 

我们调用GDI+里的graphics进行操作时,输入的坐标为在全局坐标系统中的坐标,而在屏幕或者打印机上显示的是设备坐标系统中的值。因此,从全局坐标系统中的坐标到设备坐标系统中的坐标需要经过全局坐标到页面坐标的全局变形(world transformation),从页面坐标到设备坐标的页面变形(page transformation)。全局变形通过transform来实现;页面变形通过setpageunitsetpagescaleSetpageunit()指定绘图单位,参数分别为

typedef enum {

    UnitWorld = 0,

    UnitDisplay = 1,

    UnitPixel = 2,

    UnitPoint = 3,

    UnitInch = 4,

    UnitDocument = 5,

    UnitMillimeter = 6

} Unit;

对于不同的单位,可能转换为设备坐标的时候就有不同的结果。但是页面变形需要由setpageunitsetpagescale这两个函数共同来决定。即

graphics.SetPageUnit(UnitInch);//英寸

       graphics.SetPageScale(1.0f);

       graphics.SetPageUnit(UnitMillimeter );//毫米

       graphics.SetPageScale(25.4f);

这两种设置方式的结果是一样的。在这里假定25.4毫米=1英寸

同理,其他几种模式下(除UnitWorld外,在这种模式下没有物理单位,缺省情况下为该模式),设备坐标系的设置也是可以相互转换的。

并且在同一函数段中可以随时改变设备坐标设置。而不会相互影响,见下面程序段所示:

Graphics graphics(hdc);
   // Set the page units to pixels, and draw a rectangle.
   graphics.SetPageUnit(UnitPixel);
   Pen blackPen(Color(255, 0, 0, 0), 0.0f);
   graphics.DrawRectangle(&blackPen, 0, 0, 100, 100);
   // Set the page units to inches, and draw a rectangle.
  graphics.SetPageUnit(UnitInch);
   Pen bluePen(Color(255, 0, 0, 255), 0.0f);
   graphics.DrawRectangle(&bluePen, 2, 0, 1, 1);

全局变形:忽略单位,将坐标值进行转换,下一节详细说明。

页面变形:根据单位将坐标值。页面坐标中,具体的单位是根据基本单位和比例来进行设置的,计算公式为:具体单位=基本单位*比例。

2、全局变形的换算关系

根据第一节的讲解,我们对于这三种坐标系有了一个基本的认识。但对于实际程序开发工作是远远不够的。下面就对所有的变形进行探讨。

(1)    基本变换:平移及旋转

平移及旋转变换是最基本的全局变换,可以通过如下几种方式进行实现:graphics::translatetransformgraphics::settransform

其中,translatetransform(int x,int y);如果x>0则表示正方向移动,反之,向反方向移动。

(2)    改变坐标系,使Y轴垂直向上为正

这种转换,需要利用matrix来进行,称为仿射变形。

Matrix matrix(1.0f,0.0f,0.0f,-1.0f,x,y);

Graphics.SetTransform(&matrix);//即可将Y轴转变成垂直向上为正

且平移(x,y)的距离。注,平移坐标转换是在新的全局坐标系下进行的,即操作的都是全局坐标系。

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

       graphics.SetTransform(&matrix);

       graphics.TranslateTransform(0,-100.0f);//平移是在新的全局坐标系下进行的,平移的也是全局坐标系本身,与页面坐标系没有关系

       graphics.DrawLine(&pen1,0,0,100,100);

如果在matrix中指定的x的比例不是1.0f的话,那就是全局坐标系中,x轴的比例发生了变化,如果大于1,则进行了放大,即相同大小的数值表示的长度增长。反之,则缩小。

3)缩放并平移与缩放后平移的效果是不一样的,即此时的平移还是在原有的基础上进行的,因此,还是向下为正,即100

       GraphicsContainer container3=graphics.BeginContainer();

//X方向放大2倍,并平移100个单位

       Matrix matrix(2.0f,0.0f,0.0f,-1.0f,100.0f,100.0f);

       graphics.SetTransform(&matrix);

       graphics.DrawLine(&pen1,0,0,100,0);

       graphics.EndContainer(container3);

       GraphicsContainer container4=graphics.BeginContainer();

//X方向放大2倍,然后再平移100个单位,这时,新的全局坐标系已经变为向上为正,所以向下为负,即-200。此时

       Matrix matrix1(2.0f,0.0f,0.0f,-1.0f,0.0f,0.0f);

       graphics.SetTransform(&matrix1);

       graphics.TranslateTransform(100,-200.0f);

       graphics.DrawLine(&pen1,0,0,100,0);

       graphics.EndContainer(container4);

缩放的同时平移,只向右平移了在没有放大前的100个单位

输出结果如下图所示:

缩放后平移,向右平移了放大后的100个单位,平移距离是前一种方式的放大倍数倍

3、鼠标输入坐标到全局坐标的转换

鼠标输入的坐标都是设备坐标,要转换为全局坐标,就是一个从全局坐标转换到设备坐标的逆向过程。即相当于Point1*[Matrix]=point2,其中[Matix]为转换矩形,在已知point2的情况下,来求point1。这也就是我们进行坐标转换的真正目的。

转换方式为:

       point1=point2*[Matrix]-1

       在实际的操作中,是这样进行的:

       Matrix matrix(2.0f,0.0f,0.0f,-1.0f,100.0f,0.0f);//定义了一个转换矩阵,转换坐标系

       graphics.SetTransform(&matrix);

       Matrix *pmatrix1=matrix.Clone();

       pmatrix1->Invert();

       pmatrix1->TransformPoints(&m_pt);//m_pt是从屏幕上获得的一个值,经过转换以后成为全局坐标系下的一个值,在屏幕上与取值位置是相一致的。

       delete pmatrix1;

       graphics.DrawLine(&pen,0,0,m_pt.X,m_pt.Y);

上述操作是在一个默认条件下进行的,即页面坐标系与设备坐标系是同一个坐标系。当这两个坐标系不同里,还需要从页面坐标系坐标以设备坐标系坐标的转换,转换过程中,根据设置的单位不同,但总的转换关系为:

页面坐标*每单位包括的像素点=设备坐标

4、矩阵变换。

要进行坐标系的转换,矩阵变换是必不可少的。因此,理解矩阵变换是很重要的,但限于研究得有限,在本文就不再进行阐述。或者待以后再详细阐述。