全部博文(158)
分类: WINDOWS
2009-12-29 19:28:55
绘图操作只能在客户区中进行。除客户区以外的部分都叫非客户区
在
Windows的作图函数中,涉及逻辑坐标到设备坐标的转换。这里提到的窗口(window)、视口(viewport)是对应的概念。视口是与设备相关
的一个矩形区域,坐标单位是与设备相关的。窗口的坐标是逻辑坐标,与设备无关。窗口坐标的原点与视口坐标的原点始终对应于同一点。,窗口原点是与视口原点
相同的,(也就是说,位于屏幕上的同一个位置),为了体会不窗口坐标与视口坐标的转换,先用SetwindowtOrg(100,
-300)将视口移到(100,-300),这相当于把 逻辑点(100,-300)映射到设备点(0,0)
(注意:如果改用SetviewportOrg移动原点,则其原点的移动尺寸与映射模式无关,其300个长度单位等于9厘米)
(注:这个设备点也是相对于当前的DC而言,如果当前的DC是整个屏幕,那么设备点(100,-300)的原点就在屏幕的左上角,如果当前的DC是某个应用程序的客户区,那么设备点(100,-300)的原点就是应用程序的客户区的左上角,)
现在假设当前DC是某个应用程序的客户区,映射模式为 MM_LOMETRIC
(在这种映射模式下,设备坐标以0.1 毫米为一个长度单位,Y轴的正方向为向上,也就是说,屏幕上的左上角的Y坐标为0,下面的Y坐标均小于0),当使用语句:
MoveTo(100,-600);
LineTo(100,-800);//Y轴负方向向下,所以用负值
进行画图时,它的转换过程如下:
1)窗口与视口坐标转换,由于窗口坐标(100,-300 ),映射为设备坐标(0,0),所 以
窗口(100,-600)映射为视口(0,-300)
窗口(100,-800)视映射为视口(0,-500)
2)逻辑与设备坐标转换
由于是 MM_LOMETRIC 映射模式,设备坐标的单位长度为 0.1mm,而在输出时用的是视口坐标,所以视口坐标(100,-600)输出到屏幕上时,该点的位置
距客户区左边 0 厘米,距客户区上边 3厘米。这就是直线的起点;
再把直线终点的视口坐标(100,-800)输出到距客户区左边0厘米,距客户区上边 5厘米处。对于同一个图形,用窗口
坐标系统表达的该区域的长和宽与视口的坐标系统表达的长和宽是不同的。二者就定义了这两个坐标系统的比例关系。程序作图时,使用的坐标总是是窗口坐标。而
实际的显示或输出设备却各有自己的坐标。例如,有的打印机设备水平和垂直分辨率不同,其象素实际上是长方形。程序编写画一个圆,若不经任何坐标转换,在打
印机上输出的就是个椭圆。下面程序示范了如何将窗口逻辑坐标的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");
...
}
第一句:定义逻辑单位和具体的设备单位的映射模式
第二句:设置与设备上下文关联的窗口的X和Y坐标的范围。其中4000和3000是逻辑坐标。此时窗口大小为(4000,3000),视口大小未知。
第三句:得到客户区尺寸。此尺寸就是当前视口尺寸。如果(800,600),在最大化时此尺寸为(800,5XX).
第四句:设置视口的范围,第二个参数为负数,表示视口坐标往下移了cRect高度的一半。
第五句:将设备坐标转换成逻辑坐标。因为GetClientRect得到的设备坐标
第六句:设置设备上下文窗口的起始坐标。
最后一句:在第六句的基础上,在逻辑坐标位置输出文本abc. 记住两个原则:
1.总是由窗口原点映射为视口原点。即无论你窗口的原点和视口的原点怎么变,窗口的原点总是映射到视口的原点。(记住:映射方向是窗口到视口,而不是视口向窗口映射)
2.不管利用函数(如:SetViewportOrgExt和SetWindowOrgEx)对窗口和视口的原点做怎么改变,设备点(0,0)始终是客户区的左上角。
现将其关键点归纳如下:
1、 视口等同客户区,使用设备坐标。
2、 窗口与视口为同一区域,但使用逻辑坐标。
3、 窗口与视口使用不同的坐标系,但是两套坐标系的原点始终为同一点。但该点坐标(不管是视口坐标原点还是窗口坐标原点)不一定为(0,0)。
4、 坐标点的位置(相对于客户区左上角)仅仅由SetViewportOrgEx (x,y)
函数来移动(x,y相对于客户区左上角的设备坐标,即像素),而SetWindowOrgEx(x,y)仅仅设置该原点作为窗口坐标原点时所对应的逻辑坐
标为(x,y),而不会改变其相对于客户区左上角的位置。
5、 理解窗口与视口的坐标 转换公式:
Xviewport=(Xwindow-Xwinorg)* Xviewext / Xwinext + Xvieworg;
Yviewport=(Ywindow-Xwinorg)* Yviewext / Ywinext + Yvieworg;
此公式初看上去不好理解,变形如下:
(Xviewport-Xvieworg)/(Xwindow-Xwinorg)= Xviewext / Xwinext;
(Yviewport-Yvieworg)/(Ywindow-Xwinorg)= Yviewext / Ywinext;
如此就很好理解了:基于上述1、2、3点,在这个区域的任意一点到原点的距离之比,就是其逻辑坐标单位与设备坐标单位的比,即比例因子。
6、 对于定义的客户区域大于程序所创建的窗口时,就需要有滚动条来滚动显示,才能显示完整的客户区域。
7、 处理滚动窗口:假设未滚动窗口时,客户区左上角对应 窗口和视口的原点坐标,且默认均为(0,0),
如果滚动窗口时,水平方向向右滚动了X个像素,垂直方向向下滚动了Y个像素,则应该认为客户区域的左上角为窗口原点(同时也是视口原点)一起滚动,并且窗
口原点的坐标始终为(0,0)不变,但是视口的原点所影射的坐标应该发生变化,且为(-X,-Y)。可以通过SetViewportOrgEx
(-X,-Y)。通过调试MFC中CSrollView类函数,发现,它就是通过SetViewportOrgEx
(X,Y)函数改变视口的坐标原点来实现窗口的滚动。
8、 坐标原点(不论是视口还是窗口)不等于坐标零点(必需明白)。
9、视口的坐标原点可以任意移动,但其零点始终在客户区左上角。
10、窗口原点和零点均可任意移动。
不正确之处,欢迎各位高手指正!
在 Windows
的作图函数中,涉及逻辑坐标到设备坐标的转换。这里提到的窗口(window)、视口(viewport)是对应的概念。视口是与设备相关的一个矩形区
域,坐标单位是与设备相关的。窗口的坐标是逻辑坐标,与设备无关。窗口坐标的原点与视口坐标的原点始终对应于同一点。对于同一个图形,用窗口坐标系统表达
的该区域的长和宽与视口的坐标系统表达的长和宽是不同的。二者就定义了这两个坐标系统的比例关系。程序作图时,使用的坐标总是是窗口坐标。而实际的显示或
输出设备却各有自己的坐标。例如,有的打印机设备水平和垂直分辨率不同,其象素实际上是长方形。程序编写画一个圆,若不经任何坐标转换,在打印机上输出的
就是个椭圆。下面程序示范了如何将窗口逻辑坐标的x,y向象素宽度均映射为输出设备中的 1/64 英寸。
SetMapMode(hDC, MM_ISOTROPIC);
SetWindowExtEx(hDC, 64, 64, NULL);
SetViewportExtEx(hDC, GetDeviceCaps(hDC, LOGPIXELSX),
GetDeviceCaps(hDC, LOGPIXELSY), NULL);
所谓视口代表设备,比如屏幕。
窗口代表我们的思维。
我们对windows说在(5,6)处画个点(调用GDI函数)。windows认为是在我们的思维的(5,6) 处画了个点。(也就是说5,6是逻辑坐标,GDI函数中的大部分都是逻辑坐标)
那么,要把它映射到屏幕上,必须作一些解释。
解释包括:
原点在哪里?5,6代表什么?注意,解释5,6时不光是距离问题,还有方向呢!
SetViewportOrgEx和SetWindowOrgEx是管第一个问题的。
设置X轴Y轴方向(SetMapMode),还有SetViewportExtEx和SetWindowExtEx是管第二个问题的。
其实想象一下也可以知道,5和6应该是乘上一个比率来变成像素单位。而后根据原点并按照X轴Y轴方向去画就可以了。
SetViewportExtEx和SetWindowExtEx就是决定比率的函数。(他们的第二个和第三个参数分别相除来代表横纵坐标的比率。)
句个例子:我希望使用笛卡尔坐标系(也就是X向右增加,Y向上增加),并且坐标单位是厘米,那么此时就应该有某个比率来把5,6厘米变成是多少个像素(在
windows提供的某种映射模式中确实有这个比率)。再去画。(此时你也不能乱改比率,毕竟一厘米多少像素是个常数,你设置了映射模式后也就决定了比
率)
在我们的例子中,
SetWindowExtEx(hDC, 64, 64, NULL);
SetViewportExtEx(hDC, GetDeviceCaps(hDC, LOGPIXELSX),
GetDeviceCaps(hDC, LOGPIXELSY), NULL);
这样之后,5代表5* (64/GetDeviceCaps(hDC, LOGPIXELSX)这么多个像素。
6代表6* (64/GetDeviceCaps(hDC, LOGPIXELSX)这多个像素。
我们修改了比率,由此可知映射模式也是我们自定义的。(各向同性,各向异性,英文是啥记不得了)