原创 GDI映射模式—关于窗口和视口 (转)

2012-11-27 19:12 2449 24 26 分类: 工程师职场

最近在学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个单位。

到这里应该就差不多了,有不理解的请仔细琢磨一开始讲的那三条规则,以上是个人理解,希望能有帮助,如有错误请指出。

PARTNER CONTENT

文章评论2条评论)

登录后参与讨论

用户377235 2015-3-28 08:50

bingo

用户377235 2014-9-27 09:09

Erro
相关推荐阅读
mcuandme 2020-03-14 23:15
18位、线性、低噪声、精密双极性±10 V直流电压源
www.analog.com/zh/CN0200...
mcuandme 2020-03-14 21:51
C语言printf("")左对齐和右对齐 (转)
https://blog.csdn.net/abcdu1/article/details/74926375  原文地址1.左对齐方式1printf("%d\n",101010);默认打印格式...
mcuandme 2020-03-14 21:45
放大器电路设计中的常见问题经验总结
源地址:https://www.cnblogs.com/huanzxj/p/5667633.html与分立器件相比,现代集成运算放大器(op amp)和仪表放大器(in-amp)为设计工程师带来了许多...
mcuandme 2015-07-13 15:12
简单的固态继电器具有过零开关功能
本设计实例是一个固态继电器(SSR),它能利用双向晶闸管切换大电流的交流负载(图1)。市场上有大量简单的固态继电器电路,但这个电路可能是最简单的,它只在交流线路电压接近零时才导通和关断。 晶体管Q2...
mcuandme 2014-07-30 08:44
LIB和DLL的区别与使用
共有两种库: 一种是LIB包含了函数所在的DLL文件和文件中函数位置的信息(入口),代码由运行时加载在进程空间中的DLL提供,称为动态链接库dynamic link library。 ...
mcuandme 2013-12-19 22:16
Stellaris LM3S MCUs
今天买了个开发板 EKK LM3S3748 然后上网查资料是 Stellaris LM3S MCUs 系列的芯片 是CORTX M3 内核 但是TI官方网站已经推荐上级到  Upgrade...
EE直播间
更多
我要评论
2
24
关闭 站长推荐上一条 /3 下一条