6.1、GDI映射模式

一、设备坐标和逻辑坐标
在Windows应用程序中,有两种坐标系统:设备坐标和逻辑坐标。
	设备坐标:又称物理坐标,指输出设备上的坐标。通常将屏幕上的设备坐标称为屏幕坐标,以像素为度量单位。水平轴(X轴)的正方向从左向右,垂直轴(Y轴)的方向从上向下,并且整个坐标轴的单位和方向固定不变。windows包括三种设备坐标,以满足不同需要:1、客户区坐标  2、全窗口坐标  3、屏幕坐标
	Win对所有的消息,所有的非GDI函数,甚至某些GDI函数,永远使用设备坐标。映谢方式是一种设备内容属性,只有对需要设备内容句柄作参数的GDI函数,映射方式才会起作用。

	逻辑坐标:独立于设备,与设备点大小无关。缺省模式下(MM_TEXT)下,方向和单位和设备坐标相同。坐标轴方向,单位,原点都可以重定义。以cm  mm  in等为单位。所有GDI函数都使用逻辑坐标表示。
 
二、窗口和视口
	我们将逻辑坐标所在的坐标系称为“窗口”,设备坐标所在的坐标系称为“视口”。
	窗口和视口是WindowsGDI中两个很重要的概念,从逻辑坐标映射为设备坐标实际上就是从窗口到视口的映射

        视口是基于设备坐标的,它以像素为单位(也就是我们看到的),且有视口原点视口范围两个基本属性。在使用客户区设备坐标时,视口与客户区相同,视口原点在默认情况下位于客户区的左上角,Y轴向下为正方向。可以更改视口原点的位置,也可改变坐标轴方向。

        窗口是基于逻辑坐标的,窗口逻辑坐标的单位可以是像素、英寸等,还可以自定义。窗口也有窗口原点和窗口范围两个基本属性,窗口原点被映射到视口原点,窗口范围与视口范围的比值定义为映射的换算因子。
 
三、设备坐标和逻辑坐标的转换关系
Windows定义了8中映射模式,在WINGDI.H中定义的标识符如下:
 
 

映射模式

逻辑单位

值增加方向

X轴

Y轴

MM_TEXT

像素

MM_LOMETRIC

0.1mm

MM_HIMETRIC

0.01mm

MM_LOENGLISH

0.01in

MM_HIENGLISH

0.001in

MM_TWIPS

1/1440in

MM_ISOTROPIC

任意(x=y)

可选

可选

MM_ANISOTROPIC

任意(x!=y)

可选

可选

  MM_TEXT是最常用的也是最容易理解的,默认映射模式(和我们看书相同,从左到右,从上到下)。在MM_TEXT下,逻辑单位与设备单位相同,都以像素为单位;y轴坐标向下增长,与设备坐标系相同。该模式下,内定的 窗、视口原点(0,0)可以改变。窗、视口范围(1,1),不可改变
SetViewportOrg  //设置视口原点
SetWinodwOrg   //设置窗口原点 ,一般用一个就能达到想要效果,用两个不大好调整
GetViewportOrg  
GetWindowOrg  //获取当前窗口原点
窗口->视口
        xViewport=(xWindow-xWindowOrg)*(xViewEx/xWinExt)+xViewOrg
	yViewport=(yWindow-yWindowOrg)*(yViewEx/yWinExt)+yViewOrg
	(xWindow,yWindow)待转换逻辑点,(xViewport,yViewport)是转换后的设备点(一般情况下是显示区域坐标)。(xViewOrg,yViewOrg)是设备的坐标的视口原点。在缺省的环境中,这两个点均为(0,0)。这个公式说明,逻辑点(xWindow,yWindow)总被映射为设备点(xViewport,yViewport)。
	如果窗口和视口原点都是默认值(0,0),公式就可以简化为:
	xViewport=(xWindow-xWindowOrg)*(xViewEx/xWinExt)
	yViewport=(yWindow-yWindowOrg)*(yViewEx/yWinExt)
	//(xWinExt,yWinExt)是逻辑坐标的窗口范围
	//(xWinExt,yWinExt)是设备坐标的窗口范围,每个范围自身没有什么意义,只是比例用于换算因子
        GetClientRect(hwnd,&rect);
        DPtoLP(hdc,(PPOINT)&rect,2);   //设备坐标到逻辑坐标
        LPtoDP(hdc,pPoints,iNumber);
视口->窗口 xWindow=(xViewport-xViewOrg)*(xWinExt/xViewExt)+xWinOrg

举例理解上述转换:
视口(0,0)指客户区左上角(也可以是屏幕或全窗口)。x向右增,y向下增。
1、使用MM_LOMETRIC映射模式,x向右增,y值向下减。设定视口范围为(1024,-768), 即xViewExt=1024,yViewExt=-768,窗口范围是(3200,2400),即xWinExt=3200,yWinExt=2400。这里的范围请只把它理解成一个数而不是一个区间,因为它只是要用来求xViewExt/xWinExt这样一个比值而已。
初始设置视口和窗口原点都为(0,0),xWinOrg,yWinOrg,xViewOrg,yViewOrg的值都是0。
	a、调用SetPixel(hdc,100,-100)(GDI使用逻辑坐标,通过转换为(xViewport,yViewport)找到在客户区的位置):
 	xViewport=(100-0)*(1024/3200)+0=32
	yViewport=(100-0)*(1024/3200)+0=32
这个位置为在客户区左上角右数32,下数32个像素点的位置画点。

       b、调用SetPix(hdc,100,100)
	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)仍然在客户区左上角,这一点一定要理解清楚。
 
2、现在我们使用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个单位。
 
四、自定义映射模式
1、自定义映射模式为MM_ISOTROPIC或MM_ANSIOTROPIC
如SetMapMode(MM_ANSIOTROPIC);

2、逻辑坐标和设备坐标的换算因子(比例系数)。下述两函数必须成对存在,单一调用没有任何意义。
SetWindowExtEx(hdc,1,1,NULL)
SetViewportExtEx(hdc,4,-4,NULL)

3、设置坐标原点
SetViewportOrgEx(hdc,cxClient/2,cyClient/2,NULL);
 
代码实例:
 

CPaintDC dc(this);
dc.TextOut(100,100,_T("MM_TEXT:(100,100)"));//默认MM_TEXT 窗视口默认原点都为(0,0)
dc.SetViewportExt(1024,-768);
dc.SetWindowExt(3200,2400);
dc.SetMapMode(MM_LOMETRIC);  //y轴向上(100,-100)为逻辑坐标,转换为视口坐标(32,32)
dc.TextOut(100,-100,_T("MM_LOMETRIC:(100,-100)"));
//逻辑点(100,100)显示 即视口(32,-32),很明显超出显示范围 
//dc.SetViewportOrg(0,64);   //方法1,改变视口原点 正常显示
dc.SetMapMode(MM_ISOTROPIC);  //方法2,使用MM_ISOTROPIC改变窗口和视口范围
dc.SetViewportExt(1024,768);
dc.TextOut(250,250,_T("MM_ISOTROPIC:(250,250)"));


 


输出结果如下:两次输出位置不同是因为MM_TEXT 和MM_LOMETRIC使用单位的不同


//上述由网络资料整理修改

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值