MFC中坐标空间与映射

来源:互联网 发布:幼儿园美工区域计划 编辑:程序博客网 时间:2024/06/05 02:46

有不对的地方十分欢迎指正,谢谢。

转载请注明出处,谢谢。

参考文献:

1、孙鑫老师《VC++深入详解

2、作者: 刘涛 http://tech.sina.com.cn/s/2005-06-20/1143640450.shtml

3、作者:

maybe_kid

http://blog.csdn.net/maybe_kid/article/details/1749549

首先需要知道的知识点:

1、GDI函数,图像操作,画图等等几乎都是在逻辑坐标下进行。极个别有几个不是,比如GetDeviceCaps,是GDI函数,但用的设备坐标。由window完成从逻辑坐标转换为设备坐标的工作。

2、几乎所有的非GDI函数,都使用的设备坐标。另外,MFC接收到的消息,鼠标移动WM_MOUSEMOVE,鼠标点击WM_LBUTTONDOWN,还有窗口重绘WM_SIZE等等,都用的设备坐标。所以点击鼠标得到的点位置,一般需要使用DpToLp函数将其转换为逻辑坐标以后再使用。

3、不管对窗口和视口原点作什么改变,设备原点(0,0)始终是客户区的左上角。

4、设备原点(0,0)与视口原点(ViewPortOrg)不是一个概念,他俩默认是相同的,但使用SetViewPortOrg函数后,就不相同了。

一、坐标空间

Win32应用程序设计接口(API)使用四种坐标空间:世界坐标系空间、页面空间、设备空间、和物理设备空间。


Used optionally as the starting coordinate space for graphics transformations. It allows scaling, translation, rotation, shearing, and reflection. World space measures 2^32 units high by 2^32 units wide.
世界坐标可以选作图像变换的起始坐标系,可以完成缩放,旋转,斜切(shearing),反射(reflection)操作。世界坐标系宽高都为2^32个单位。但一般不怎么使用。
Page space works with device space to provide applications with device-independent units, such as millimeters and inches. This overview refers to both world space and page space as logical space.

页面空间可以作为图像变换的起始坐标系,也可以作为第二个坐标系(位于世界坐标系之后),主要设置映射模式页面空间与设备空间相互配合,给应用程序提供了一种设备无关的单位,比如毫米或英尺。

概念上将世界坐标空间页面空间称为逻辑空间

Used as the next space after page space. It only allows translation, which ensures the origin of the device space maps to the proper location in physical device space. Device space measures 2^27 units high by 2^27 units wide.

设备空间位于页面空间之后,只用作保证设备空间的原点,映射到物理设备坐标空间中一个合适的位置(可以参考上面图)。

The final (output) space for graphics transformations. It usually refers to the client area of the application window; however, it can also include the entire desktop, a complete window (including the frame, title bar, and menu bar), or a page of printer or plotter paper, depending on the function that obtained the handle to the device context. Physical device dimensions vary according to the dimensions set by the display, printer, or plotter technology.

物理设备空间是图像变换的终点。一般指代应用程序的窗口,但它也包括整个桌面,完整的窗口(包括窗口框,标题栏,tool bar等),或打印机的一页或绘图仪的一页纸。物理设备的尺寸随显示器、打印机或绘图仪所设置的尺寸而变化。

To depict output on a physical device, the system copies (or maps) a rectangular region from one coordinate space into the next using a transformation until the output appears in its entirety on the physical device. Mapping begins in the application's world space if the application has called the SetWorldTransform function; otherwise, mapping occurs in page space. As the system copies each point within the rectangular region from one space into another, it applies an algorithm called a transformation. A transformation alters (or transforms) the size, orientation, and shape of objects that are copied from one coordinate space into another. Although a transformation affects an object as a whole, it is applied to each point, or to each line, in the object. 

要在物理设备上绘制输出,系统把一个矩形区域从一个坐标空间拷贝或映射到另一个坐标空间,直至最终完整的输出呈现在物理设备上(通常是屏幕或打印机)。
如果应用程序调用了SetWorldTransform函数,那么映射就从应用程序的世界坐标系空间开始否则,映射由页面空间开始进行。在Windows把矩形区域的每一点从一个空间拷贝到另一个空间时,它采用了一种被称作转换的算法,转换算法是把对象从一个坐标空间拷贝到另一个坐标空间时改变(或转变)这一对象的大小、方位、和形态,尽管转换把对象看成一个整体,但它也作用于对象中的每一点或每条线。
上面的图就是典型的一个矩形图像的映射的过程,这里调用了SetWorldTransform函数,所以转换由世界坐标空间开始进行。

以上来自msdn中 Transformation of coordinate spaces。可以看看。

补充:

设备空间到物理空间的转换只限于平移,并由Windows的窗口管理部分控制,这种转换的唯一用途是确保设备空间的原点被映射到物理设备上的适当点上。没有函数能设置这种转换,也没有函数可以获取有关数据。

页面空间 向 设备空间转换时,需要确定一种映射模式(map mode)。这种映射模式是设备相关的。它用来确定一个逻辑单位(就是世界坐标和页面坐标中的单位)与一个特定的设备的设备坐标空间中一个单位之间的对应关系。以及确定坐标系中x , y轴的方向。特定设备指打印机或显示器等。

就像上面介绍的,映射就是为了让图像与特定的设备解耦,这样我们只要图形正确,不管用什么样的设备,都能输出正确的图像。比如我在显示器上画一幅图,多少多少毫米,然后我用这个图像文件进行打印,打印出来的图像与我显示器上显示的图像完全一样。

二、”窗口“ window和 “视口” viewport

从页面空间 向 设备空间转换,即将窗口原点(windowOrg)映射到视口原点(viewPortOrg),将窗口范围(windowExt)映射到视口范围(viewPortExt)。这四个是转换中重要的属性。
“窗口”(window) 是基于逻辑坐标的,逻辑坐标可以是象素、毫米、英寸等单位
“视口”(viewPort) 是基于设备坐标(象素)的。通常,视口和客户区是相同的。



上图自认为最重要的是明白,视口原点与设备空间原点不一定相同,窗口原点与页面空间原点也不一定相同。

窗口(逻辑)坐标转换为视口(设备)坐标的两个公式:
xViewport=(xWindow - xWinOrg) * ( xViewExt / xWindowExt ) + xViewOrg
yViewport=(yWindow - yWinOrg) * ( yViewExt / yWindowExt ) +yViewOrg
 
视口(设备)坐标转换为窗口(逻辑)坐标的两个公式:
xWindow=(xViewPort-xViewOrg) * ( xWindowExt / xViewExt ) +xWinOrg
yWindow=(yViewPort-yViewOrg) * ( yWindowExt / yViewExt ) +yWinOrg
 
CDC中提供了两个成员函数函数SetViewportOrgSetWindowOrg,用来改变视口和窗口的原点。
 
如果将视口原点设置为(xViewOrg,yViewOrg),则逻辑点(0,0)就会被映射为设备点(xViewOrg,yViewOrg)。
如果将窗口原点改变为(xWinOrg,yWinOrg),则逻辑点(xWinOrg,yWinOrg)将会被映射为设备空间坐标原点(0,0),即左上角。
 
 
上面两句话怎么理解呢,画个图:
[cpp] view plaincopyprint?
 
 


显示在显示器上如上图所示,显示出来的圆的圆心在(xViewPortOrg,yViewPortOrg)处。用GDI函数画的图形,都用的逻辑坐标上面那个圆画的时候圆心虽然为(0,0),但是这是逻辑坐标,要经过映射变为设备坐标,最终变为物理设备坐标后,才能显示到用户的屏幕上。因为改动过视口的原点,窗口原点要映射到设备空间的视口原点,映射后图像显示出来的圆,圆心位于(xViewPortOrg,yViewPortOrg)。这个(xViewPortOrg,yViewPortOrg)是设备空间坐标系下(CD 设备上下文的由来)的坐标值。

在显示器上显示出来的是设备空间的样子,上面画圆的代码中,没有对窗口原点进行改动,所以可以看到页面空间原点与窗口原点同为一点。而语句dc.SetViewPortOrg(xViewPortOrg,yViewPortOrg)将视口原点改为了(xViewPortOrg,yViewPortOrg)。即告诉系统,我现在画在页面空间的这个以页面空间坐标系(0,0)点为圆心的圆,你要显示到设备空间坐标下设备空间坐标系的 (xViewPortOrg,yViewPortOrg)点处。

再次提醒:不管对窗口和视口原点作什么改变,设备空间(设备上下文)坐标原点(0,0)始终是客户区的左上角
同理,改变窗口原点也是一样的。就是要知道,这里ViewPortOrg不是设备空间原点,窗口原点也不是页面空间原点。SetWindowOrg和SetViewPortOrg无法改动各空间坐标系的原点。
这块可参看参考文献2,写的非常好的,作者很用心。十分感谢作者提供这么好的文章。
缺省的映射模式为MM_TEXT。在这种映射模式下,逻辑单位和设备单位相同。
0 0
原创粉丝点击