先从两个奇怪的公式入手:
xViewport = ( xWindow - xWinOrg ) * ( xViewExt ) / ( xWinExt ) + xViewOrg
yViewport = ( yWindow - yWinOrg ) * ( yViewExt ) / ( yWinExt ) + yViewOrg
公式的奇怪关键在于其意义所在,这其实是"用于能使逻辑坐标下画的图形得以在显示器或打印机上显示"的逻辑坐标和视讯坐标的转换关系(好像白说,请注意理解),进一步说正是因为大都GDI函数都使用的都是逻辑坐标(因为其需要设备内容句柄作参数,映像方式将起作用),也就是说在windows下画图可以在自定的坐标系下绘图,但是由于这样可能会导致无法在显示器或打印机上显示(因为其和视口坐标系不和,或称页面坐标系都是采用和设备坐标系一致的坐标系统),这样就需要有一套公式和函数来进行必要的转换,以上公式及其相关的函数就是在这种情况下诞生的
注意:(1) 这里的窗口(Window)是基于“逻辑坐标”的,它的单位可以是象素、mm、英寸、磅、或者其他你自己定义的单位。特别的是,所有的GDI绘图函数使用的都是逻辑坐标,这点很作用。
(2) 视口(Viewport)则是基于设备坐标(象素)的。而通常,视口和窗口的客户区是相同的,而且在视口坐标系中,客户区的左上角的坐标是(0,0),且X轴向右增加,Y轴向下增加。
事实上,SetWindowOrgEx函数和SetViewportOrgEx函数,他们的名字具有一定的欺骗性,他们的作用并不是调整坐标系的原点,对于SetWindowOrgEx函数来说,他的作用是将视口坐标系中的(0,0),映射到窗口坐标系的中指定的一个点;而对于SetViewportEx函数来说,它的作用是设置窗口中的(0,0)点,映射到视口坐标系的中指定的一个点。通过使用上面提及到的两个函数,就可以调整Windows的显示范围,从而使原本不能显示的区域在设备坐标系中显示出来。
补充:(1)不管对窗口和视口原点作什么改变,视口点(0,0)始终是显示区域的左上角(相当重要的一句话,一定要理解)
(2)SetWindowOrgEx函数是视讯坐标系(固定为x向左增加,y向下增加的坐标系),而和SetViewportEx函数是当前逻辑坐标系
(3)窗口和视口的范围,并不真正代表了窗口和视口的真实范围,他们只是一个比值,用来确定窗口到视口映射时的缩放因子,(xViewExt)/(xWinExt)中的两个参数本身其实没 什么意义,他们的比值才有意义,决定着从窗口到视口的转换比例
简而言之:其数学作用机理,其实就是简单的平移坐标系,取原点映射只是方便而已
实际问题1(MM_TEXT下):
SetViewportOrgEx (hdc, cxClient / 2, cyClient / 2, NULL) ;等效于 SetWindowOrgEx (hdc, -cxClient / 2, -cyClient / 2, NULL) ;
这该如何理解呢?SetViewportOrgEx (hdc, cxClient / 2, cyClient / 2, NULL) ;以作用是逻辑点(0,0)将映像为设备点(cxClient/2,cyClient/2),显示区域的右下角为逻辑点(cxClient/2,cyClient/2)。而 SetWindowOrgEx (hdc, -cxClient / 2, -cyClient / 2, NULL) ;逻辑点(-cxClient / 2,-cyClient / 2)映像为设备点(0,0),即显示区域的左上角。
你似乎是明白了,SetViewportOrgEx()的作用是将视讯坐标系下的逻辑原点与视讯原点相映射 (如果只是应用,那么这样简单的分析,理解是够了)
实际问题2(MM_TEXT下):
SetViewportOrgEx (hdc, cxClient / 2, cyClient / 2, NULL) ;
SetWindowOrgEx (hdc, -cxClient / 2, -cyClient / 2, NULL) ;
这意味着逻辑点(-cxClient/2,-cyClient/2)将映像为设备点(cxClient/2, cyClient/2),这又该如何理解呢?
个人认为,其实上述两者函数的作用机理是,总是假定视口或逻辑原点就是(0,0)下,做出判断的,计算机处理时不会考虑两者的关系。当然这没有多大的实际意义,一般不会同时呼叫SetViewportOrg(),ExSetWindowOrgEx()