设备坐标(DP)、客户坐标(Client)、逻辑坐标(LP)
时间:2011-03-20 来源:情有独钟
1.逻辑坐标
逻辑坐标是独立于设备的,它与设备点的大小无关。使用逻辑单位,是实现"所见即所得"的基础。当程序员在调用一个画线的GDI函数LineTo,画出25.4mm(1英寸) 长的线时,他并不需要考虑输出的是何种设备。若设备是VGA显示器,Windows自动将其转化为96个像素点;若设备是一个300dpi的激光打印机,Windows自动将其转化为300个像素点。
2.设备坐标
Windows将GDI函数中指定的逻辑坐标映射为设备坐标,在所有的设备坐标系统中,单位以像素点为准,水平值从左到右增大,垂直值从上到下增大。
Windows中包括以下3种设备坐标,以满足各种不同需要:
(1)客户区域坐标,包括应用程序的客户区域,客户区域的左上角为(0,0)。
(2)屏幕坐标,包括整个屏幕,屏幕的左上角为(0,0)。屏幕坐标用在WM_MOVE消息中(对于非子窗口)以及下面的Windows函数中:CreateWindow和MoveWindow(都对于非子窗口)、GetMessage、GetCursorPos、GetWindowRect、WindowFromPoint和SetBrushOrg中。用函数ClientToScreen和ScreenToClient可以将客户区域坐标转换成屏幕区域坐标,或反之。
(3)全窗口坐标,包括一个程序的整个窗口,包括标题条、菜单、滚动条和窗口框,窗口的左上角为(0,0)。使用GetWindowDC得到的窗口设备环境,可以将逻辑单位转换成窗口坐标。
3.逻辑坐标与设备坐标的转换方式
映射方式定义了Windows如何将GDI函数中指定的逻辑坐标映射为设备坐标。要继续讨论映射方式我们要介绍Windows有关映射模式的一些术语:我们将逻辑坐标所在的坐标系称为"窗口",将设备坐标所在的坐标系称为"视口"。
"窗口"依赖于逻辑坐标,可以是像素点、毫米或程序员想要的其他尺度。
"视口"依赖于设备坐标(像素点)。通常,视口和客户区域等同。但是,如果程序员用GetWindowDC或CreateDC获取了一个设备环境,则视口也可以指全窗口坐标或屏幕坐标。点(0,0)是客户区域的左上角。x的值向右增加,y的值向上增加。
对于所有映射模式,Windows都用下面两个公式将窗口坐标转换成视口坐标:
xViewport=(xWindow-xWinOrg)*(xViewExt/xWinExt)+xViewOrg
yViewport=(yWindow-yWinOrg)*(yViewExt/yWinExt)+yViewOrg
其中,(xWindow,yWindows)是待转换的逻辑点,(xViewport,yViewport)是转换后的设备点。如果设备坐标是客户区域坐标或全窗口坐标,则Windows在画一个对象前,还必须将这些坐标转换成屏幕坐标。
这两个公式使用了分别指定窗口和视口原点的点:(xWinOrg,yWinOrg)是逻辑坐标的窗口原点;(xViewOrg,yViewOrg)是设备坐标的视口原点。在缺省的设备环境中,这两个点均设置为(0,0),但它们可以改变。此公式意味着,逻辑点(xWinOrg,yWinOrg)总被映射为设备点(xViewOrg,yViewOrg)。
Windows还能将视口(设备)坐标转换为窗口(逻辑)坐标:
xWindow=(xViewport-xViewOrg)*(xWinExt/xViewExt)+xWinOrg
yWindow=(yViewport-yViewOrg)*(yWinExt/yViewExt)+yWinOrg
可以使用Windows提供的两个函数DPtoLP和LPtoDP在设备坐标及逻辑坐标之间互相转换
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
视口
绘图操作只能在客户区中进行。除客户区以外的部分都叫非客户区 在 Windows的作图函数中,涉及逻辑坐标到设备坐标的转换。这里提到的窗口(window)、视口(viewport)是对应的概念。视口是与设备相关的一个矩形区域,坐标单位是与设备相关的。窗口的坐标是逻辑坐标,与设备无关。窗口坐标的原点与视口坐标的原点始终对应于同一点。对于同一个图形,用窗口坐标系统表达的该区域的长和宽与视口的坐标系统表达的长和宽是不同的。二者就定义了这两个坐标系统的比例关系。程序作图时,使用的坐标总是是窗口坐标。而实际的显示或输出设备却各有自己的坐标。例如,有的打印机设备水平和垂直分辨率不同,其象素实际上是长方形。程序编写画一个圆,若不经任何坐标转换,在打印机上输出的就是个椭圆。下面程序示范了如何将窗口逻辑坐标的x,y向象素宽度均映射为输出设备中的 1/64 英寸。 [code] SetMapMode(hDC, MM_ISOTROPIC); SetWindowExtEx(hDC, 64, 64, NULL); SetViewportExtEx(hDC, GetDeviceCaps(hDC, LOGPIXELSX), GetDeviceCaps(hDC, LOGPIXELSY), NULL); [/code] 调用SetWindowExt()函数后,紧接着应调用SetViewportExt()函数,它的任务是规定水平及垂直坐标轴的单位。可以这样认为,SetWindowExt()函数对应着“窗口”,SetViewportExt()函数对应着“视口”。几点:
1.窗口是基于逻辑坐标的. 2.视口是基于设备坐标. 3.设备坐标是以像素为单位的,逻辑坐标是以.cm,m,mm,..... 4.系统最后一定要把逻辑坐标变为设备坐标. 5.设备坐标有3种: a.GetDC() 客户区坐标. b.GetWindowDC().窗口坐标. c.GetDC(NULL),or CreateDC() .屏幕坐标.
问题如下: void CMyView::OnDraw(CDC *pDC) { ... (1):pDC->SetMapMode(MM_ISOTROPIC); (2):pDC->SetWindowExt(4000,3000); (3):AfxGetMainWnd()->GetClientRect(cRect); (4):pDC->SetViewportExt(cRect.Width(),-cRect.Height()); (5):pDC->DPtoLP(cRect); (6):pDC->SetWindowOrg(-(cRect.Width()/2),-(cRect.Height()/2)); (7):pDC->TextOut(-850,1400,"abc"); ... } 我想问一下:上面每一步执行完后,窗口和视口的原点、范围分别是多少?屏幕分辨率是(800,600)。谢谢! --------------------------------------------------------------- 第一句:定义逻辑单位和具体的设备单位的映射模式 第二句:设置与设备上下文关联的窗口的X和Y坐标的范围。其中4000和3000是逻辑坐标。此时窗口大小为(4000,3000),视口大小未知。 第三句:得到客户区尺寸。此尺寸就是当前视口尺寸。如果(800,600),在最大化时此尺寸为(800,5XX). 第四句:设置视口的范围,第二个参数为负数,表示视口坐标往下移了cRect高度的一半。 第五句:将设备坐标转换成逻辑坐标。因为GetClientRect得到的设备坐标 第六句:设置设备上下文窗口的起始坐标。 最后一句:在第六句的基础上,在逻辑坐标位置输出文本abc. 记住两个原则: 1.总是由窗口原点映射为视口原点。即无论你窗口的原点和视口的原点怎么变,窗口的原点总是映射到视口的原点。(记住:映射方向是窗口到视口,而不是视口向窗口映射) 2.不管利用函数(如:SetViewportOrgExt和SetWindowOrgEx)对窗口和视口的原点做怎么改变,设备点(0,0)始终是客户区的左上角。 |