3.从程序员的角度来看坐标映射
3.1 page空间 → device空间
首先要使用SetMapMode(int)函数选择映射模式。这其中有6种事先已经定义好了的模式,可以直接拿来就用,比如MM_HIMETRIC模式表示page空间的单位刻度是0.01毫米,x轴正向向右,y轴正向向上,原点与device空间的原点重合。如果此时程序中有一条值为10的线段,那么在程序员的眼中,这就是一条10×0.01=0.1毫米的线段,不管使用多大分辨率的显示器它都是这么长,我们甚至可以用尺子在屏幕上量量试试。如果选择预定义的映射模式,相当于微软已经为我们构造好了page空间,下面的事我们就都不用做了。
但是很多时候,微软的东西不一定适合我们,此时就要将映射模式设定为MM_ISOTROPIC或者MM_ANISOTROPIC,使用下面的四个函数定义我们自己的坐标系:
SetWindowExt(int Lwidth, int Lheight) //参数的单位为逻辑单位(Logical),如果参数为负值表示window相应的坐标轴与page空间相反。
SetViewportExt(int Pwidth, int Pheight) //参数的单位为像素(Pixel),如果参数为负值表示viewport相应的坐标轴与device空间相反。
SetWindowOrg(int Lx, int Ly)。
SetViewportOrg(int Px, int Py)。
这四个函数提出了两个新的概念:window和viewport,它们分别与page空间和device空间对应,但请记住并不是对等。引入它们的目的仅仅是为了确定page空间的单位刻度、方向、原点。
1.x轴的单位刻度=| Pwidth | / | Lwidth |。
2.x轴的方向:这个好确定,Lwidth与Pwidth同号,则page空间的x轴方向与device空间x轴方向相同,否则相反。
3.原点。这个就有一点麻烦了,我们需将window与viewport进行重叠,包括原点和坐标轴方向,然后才可以确定page空间的原点。下面通过一个例子来加以说明。
例:假设我们通过下面的语句构造了一个page空间:
SetMapeMode(MM_ANISOTROPIC);
SetWindowExt(10, 100);
SetWindowOrg(0, -100);
SetViewportExt(20, 200);
SetViewPortOrg(0,-200);
(由于100个逻辑单位相当于200个像素,因此我将它们的示意长度画成一样。)
首先我们分别在page空间中画出window坐标系、在device空间中画出viewport坐标系(如图2的左边部分)。然后由于例子中的window坐标方向与viewport相反,还需将page空间翻转(见图2中间部分)。最后将window与viewport重叠(见图2右边部分),使它们的原点和坐标方向都一致。此时我们可以清楚地看到,page空间的原点就对应于device空间的原点,而且方向也和它相同。
通过以上的1、2、3点我们就可以完全确定一个适合我们自己要求的page空间,当我们不要world空间时,它就是逻辑空间。
另外还有一个问题就是要注意MM_ANISOTROPIC与MM_ISOTROPIC的区别。对于前者来说,x方向的单位刻度与y方向的单位刻度可以不同(当然也可以相同),但是后者x方向的单位刻度与y方向的单位刻度一定是相同的,如果通过计算window与viewport范围的比值得到两个方向的单位刻度值不同,那么将会以较小的那个为准。
3.2 world空间 → page空间
void CSampleView::DrawShearCircle()
{
SetGraphicsMode(dc.GetSafeHdc(), GM_ADVANCED);
}