热度 26
2012-11-27 19:12
2423 次阅读|
2 个评论
最近在学Windows编程,在学到GDI的时候给映射模式,尤其是窗口和视口之间怎么转换给搞得头大,现在总结一下,希望能给其他人一些帮助。 关于什么是设备坐标,什么是逻辑坐标,还有什么是设备坐标系统很多书上都有,这里就不再赘述,重点只讲一下窗口和视口是怎么转换的。首先讲一下三条规则,这是关键中的关键,一切的变化都由此而来。 映射模式被定义为从“窗口”(逻辑坐标)到“视口”(设备坐标)的映射。 xViewport=(xWindow-xWinOrg)*xViewExt/xWinExt+xViewOrg yViewport=(yWindow-yWinOrg)*yViewExt/yWinExt +yViewOrg 视口的(0,0)指的是客户区的左上角(也可以是屏幕或全窗口),x值向右增加,y值向下增加,这是不会改变的。 我们通过几个例子来解释。 一、 首先我们使用MM_LOMETRIC映射模式,它的x值向右增加,y值向下减小,视口范围是(1024,-768),意思是指xViewExt=1024,yViewExt=-768,窗口范围是(3200,2400),意思是xWinExt=3200,yWinExt=2400。这里的范围请只把它理解成一个数,而不要理解成一个区间,因为它只是要用来求xViewExt/xWinExt这样一个比值而已。 一开始的时候,xWinOrg,yWinOrg,xViewOrg,yViewOrg的值都是0。 所以当我们调用函数SetPixel(hdc,100,-100,0)时(GDI函数使用的参数是逻辑坐标,通过转换为(xViewport,yViewport)找到在客户区的位置) xViewport=(100-0)*(1024/3200)+0=32 yViewport=(-100-0)*(-768/2400) +0=32 也就是在客户区左上角右数32个像素点,下数32个像素点的位置画点。 而如果调用函数SetPixel(hdc,100,100,0),则 yViewport=(100-0)*(-768/2400) +0=-32,对应的点在客户区上方,显示不出来。 因为MM_LOMETRIC模式不能修改范围,只能修改xViewOrg和yViewOrg,所以我们可以使用函数SetViewportOrgEx(hdc,0,64,NULL)修改yViewOrg,这样就有 yViewport=(100-0)*(-768/2400) +64=32,即又显示在客户区左上角右数32个像素点,下数32个像素点的位置,直观上看是把坐标系的原点位置往下移动了64个像素点,可以这样想象一下,然而实质上的原因是yViewOrg的改变导致计算结果不同,设备点(0,0)仍然在客户区左上角,这一点一定要理解清楚。 二、上面的例子比较简单,为了加深理解,现在我们使用MM_ISOTROPIC模式,这个模式一开始的窗口范围和视口范围和MM_LOMETRIC相同,不同的是在这个模式下我们可以自己改变窗口范围和视口范围,且是各向同性的,也就是水平方向和竖直方向的每一个单位对应的像素点个数相同,。 和上面同样的问题在这个模式下我们有另外一种解决的方法,使用函数SetViewportExtEx(hdc,1024,768,NULL)改变yViewExt,则调用SetPixel(hdc,100,100,0)有 yViewport=(100-0)*(768/2400) +0=32,这样又可以正常显示了。 这里要注意一点,改变了yViewExt之后,现在向下的方向成了y值增加的方向,因为yViewExt/yWinExt的值为正,所以点(0,100)和点(0,200)算出来后点(0,200)在点(0,100)下方,而原来向下的方向是y值减小的方向,因为yViewExt/yWinExt的值为负,点(0,-100)和点(0,-200)算出来后点(0,-200)在点(0,-100)的下方,这就是为什么说MM_ISOTROPIC模式x,y值增加的方向可选的原因。 MM_ISOTROPIC模式比较灵活,理解了它之后对于GDI映射就能比较好的理解,最后以构建笛卡尔坐标系为例来分析帮助理解。 (1)SetMapMode(hdc,MM_ISOTROPIC); (2)SetWindowExtEx(hdc,1000,1000,NULL); (3)SetViewportExtEx(hdc,cxClient/2,-cyClient/2,NULL); (4)SetViewportOrg(hdc,cxClient/2,cyCleient/2,NULL); (2)将窗口大小设定为1000,(3)把视口范围宽度设定为客户区宽度的一半,高度设定为客户区高度的一半的负数,此时xViewExt/xWinExt为正数,yViewExt/yWinExt为负数,整个客户区只可以显示x值为正数,y值为负数的点,相当于坐标系的第四象限。因为要保持各项同性,所以窗口大小1000就对应于客户区高度的一半(因为高度比宽度小)。(4)把xViewOrg设为cxClient/2,把xViewOrg设为cyClient/2,相当于把坐标系的原点移动到客户区中心。这样最终就创建了一个以客户区中心为原点的笛卡尔坐标系,并向各方向延展1000个单位。 到这里应该就差不多了,有不理解的请仔细琢磨一开始讲的那三条规则,以上是个人理解,希望能有帮助,如有错误请指出。