逻辑坐标与物理坐标.docx
《逻辑坐标与物理坐标.docx》由会员分享,可在线阅读,更多相关《逻辑坐标与物理坐标.docx(8页珍藏版)》请在冰豆网上搜索。
逻辑坐标与物理坐标
谢谢fuban(蚹蝂)和yqfu(浩然正气),我已经弄明白了,下面是我的理解,把它贴出来请大家指教,因为这个问题使我迷糊了整整一天,所以我暂时不结帖,把它放在论坛里让有同样迷惑的同好看一看。
如果理解有错误,千万请指正出来,以免误人子弟。
谢谢:
--------------------
在P171面的解释是针对当时的一个确定数32767,因为Windows98是16位,所以坐标的值最高不超过32767,因此书里说"Windows98不允许在客户区超越轴的范围之外显示任何东西"。
而在下面这段代码中:
SetMapMode(hdc,MM_ANISOTROPIC);
SetWindowExtEx(hdc,1,1,NULL);
SetViewportExtEx(hdc,cxChar,cyChar,NULL);
TextOut(hdc,3,2,TEXT("Hello"),5);
由于TextOut的坐标值是3和2,在Windows98允许的范围32767之内,所以还是可以显示出"Hello"字符串。
又因为程序把窗口的范围定义为1,而视口的范围定义为cxChar和cyChar(字符的平均宽度和平均高度),因此在显示时,Windows会在(3*(cxChar/1),2*(cyChar/1))的地方(也就是第二行的第三个字符处)显示字符串"Hello"。
我们通过改一改数值来证明一下:
SetMapMode(hdc,MM_ANISOTROPIC);
SetWindowExtEx(hdc,4,4,NULL);//设窗口范围为4个逻辑单位
SetViewportExtEx(hdc,8,8,NULL);//设视口范围为8个物理单位(也就是8个像素)
TextOut(hdc,1,1,TEXT("Hello"),5);//在坐标(1,1)处显示"Hello"
从上面的代码我们得出X轴的逻辑与物理比值为2,Y轴的逻辑与物理比值也为2,1*(8/4)=2,因此,Windows事实上会在客户区的左上角往右2个像素、往下2个像素的地方显示"Hello"。
我们仍然可以把TextOut中的值进行修改:
TextOut(hdc,10,10,TEXT("Hello"),5);
10明显超出了我们定义的逻辑范围4,但是因为它并没有超过坐标值的上限32767,因此,10*(8/4)=20,Windows仍然会在客户区的左上角往右20个像素、往下20个像素的地方显示"Hello"。
实例如下:
:
:
VC中坐标系的建立逻辑坐标,物理坐标,设备坐标
建立一个合适的坐标系可以为我们的绘图带来很大的方便。
下面介绍一下如何在VC中建立我们想要的坐标系。
一设备坐标和逻辑坐标
设备坐标(DeviceCoordinate)又称为物理坐标(PhysicalCoordinate),是指输出设备上的坐标。
通常将屏幕上的设备坐标称为屏幕坐标。
设备坐标用对象距离窗口左上角的水平距离和垂直距离来指定对象的位置,是以像素为单位来表示的,设备坐标的X轴向右为正,Y轴向下为正,坐标原点位于窗口的左上角。
逻辑坐标(LogicalCoordinate)是系统用作记录的坐标。
在缺省的模式(MM_TEXT)下,逻辑坐标的方向和单位与设备坐标的方向和单位相同,也是以像素为单位来表示的,X轴向右为正,Y轴向下为正,坐标原点位于窗口的左上角。
逻辑坐标和设备坐标即使在缺省模式下其数值也未必一致,除了在以下两种情况下:
1.窗口为非滚动窗口
2.窗口为滚动窗口,但垂直滚动条位于滚动边框的最上端,水平滚动条位于最左端,但如果移动了滚动条这两种坐标就不一致了。
在VC中鼠标坐标的坐标位置用设备坐标表示,但所有GDI绘图都用逻
坐标表示,所以用鼠标绘图时,那么必须将设备坐标转换为逻辑坐标,可以使用CDC函数DptoLP()将设备坐标转化为逻辑坐标,同样可以用LptoDP()将逻辑坐标转化为设备坐标。
二坐标模式
为了在不同的领域使用逻辑坐标,Windows提供了以下8种坐标模式:
分别为MM_TEXT、MM_HIENGLISH、MM_LOENGLISH、MM_HIMETRIC、MM_LOMETRIC、MM_TWIPS、MM_ANISOTROPIC和MM_ISOTROPIC。
三实例解析
(一)建立以左上角为原点,X轴和Y轴为1000的坐标,如下图
我们可以用以下代码:
voidCTtView:
:
OnDraw(CDC*pDC)
{
CTtDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
CRectrect;
GetClientRect(&rect);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetViewportOrg(0,0);
pDC->SetViewportExt(rect.right,rect.bottom);
pDC->SetWindowOrg(0,0);
pDC->SetWindowExt(1000,1000);
pDC->MoveTo(50,50);
pDC->LineTo(50,950);
pDC->LineTo(950,950);
pDC->LineTo(50,50);
}
代码分析:
1.GetClientRect(&rect);取得客户区矩形区域,将其存放在rect中
2.用pDC->SetMapMode(MM_ANISOTROPIC);设置映射模式
3.通过pDC->SetViewportOrg(0,0);设置逻辑坐标的原点
4.通过pDC->SetViewportExt(rect.right,rect.bottom);和
pDC->SetWindowExt(1000,1000);来确定逻辑坐标下和设备坐标下的尺寸对应关系
5.在MM_ANISOTROPIC模式下,X轴单位和Y轴单位可以不相同
6.坐标方向的确定方法是如果逻辑窗范围和视口范围符号相同,则逻辑坐标的方向和视口的方向相同,即X轴向右为正,Y轴向下为正。
7.如果将显示模式改为MM_ISOTROPIC,那么X轴单位和Y轴单位一定相同,感兴趣的读者可以自己使一下。
(二)建立以视窗中心为原点的坐标,如下图
用如下代码:
voidCTtView:
:
OnDraw(CDC*pDC)
{
CTtDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
CRectrect;
GetClientRect(&rect);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetViewportOrg(rect.right/2,rect.bottom/2);
pDC->SetViewportExt(rect.right,rect.bottom);
pDC->SetWindowOrg(0,0);
pDC->SetWindowExt(1000,-1000);
pDC->MoveTo(150,150);
pDC->LineTo(-150,-200);
pDC->LineTo(150,-150);
pDC->LineTo(150,150);
}
代码分析:
1.用pDC->SetViewportOrg(rect.right/2,rect.bottom/2);设置视口的原点。
2.用pDC->SetViewportExt(rect.right,rect.bottom);和pDC->SetWindowExt(1000,-1000);来确定设备坐标和逻辑坐标的单位对应关系。
3.因为逻辑窗范围和视口范围的符号不一致,纵坐标取反,所以Y轴向上为正。
逻辑坐标,设备坐标,窗口,视口
2009-11-2216:
47:
40| 分类:
windows编程| 标签:
|字号大中小 订阅
1.画图在逻辑坐标中画,使用逻辑单位,显示图形在物理坐标中显示
2.屏幕上有三种不同的物理坐标,每种物理坐标是固定死的,原点,XY轴方向都不变
1、客户区域坐标,包括应用程序的客户区域,客户区域的左上角为(0, 0)。
2、屏幕坐标,包括整个屏幕,屏幕的左上角为(0, 0)。
屏幕坐标用在WM_MOVE消息中(对于非子窗口)以及下面的Windows函数中:
CreateWindow 和MoveWindow(都对于非子窗口)、GetMessage、GetCursorPos、GetWindowRect、WindowFromPoint 和SetBrushOrg 中。
用函数ClientToScreen 和ScreenToClient可以将客户区域坐标转换成屏幕区域坐标,或反之。
3、全窗口坐标,包括一个程序的整个窗口,包括标题条、菜单、滚动条和窗口框,窗口的左上角为(0,0)。
使用GetWindowDC得到的窗口设备环境,可以将逻辑单位转换成窗口”坐标。
3.逻辑坐标有多种映射模式,可以改变坐标方向和每个像素点的大小,一旦固定了映射模式,就固定死了,原点,XY轴方向都不变
4.视口是物理坐标的一部分,默认初始状态下,它的中心点和物理坐标原点重叠
窗口是逻辑坐标的一部分,默认初始状态下,它的中心点和逻辑坐标中心点重叠
默认初始状态下,窗口中心点,视口中心点,逻辑坐标中心点,物理坐标原点在同一个位置重叠
视口、窗口和逻辑坐标的原点都是中心点
5.对图像的移动,包括用滚动条移动图像,都是调整视口(或窗口,一般是视口)实现的,比如滚动条向下拉10个单位, 变化的是视口的坐标原点(即视口矩形的中心点)相当于SetViewportOrg(0,-10)函数的功能
如果是移动窗口原点的话,是在逻辑坐标中移动图像,方向是逻辑坐标指定映射模式的轴方向。
SetViewportOrg(x,y)把窗口的原点(中心点)映射到视口的(x,y)点
SetWindowOrg(x,y)把窗口的(x,y)点映射到视口的原点
默认映射下:
SetViewportOrg(x,y)=SetWindowOrg(-x,-y)
6.画图并移动图像的步骤
1.在脑海中建立4个坐标(窗口坐标,视口坐标,逻辑坐标,物理坐标),窗口中心点,视口中心点,逻辑坐
标原点,物理坐标原点在同一个位置重叠
2.确定逻辑坐标的映射模式(即确定轴方向和像素点大小)
3.用CDC函数开始在逻辑坐标中画图
4.使用视口或窗口原点来移动图像到想要的位置。
(设置视口或窗口原点)
7.MM_ANISOTROPIC和MM_ISOTROPIC用于自定义逻辑坐标和物理坐标的映射
使用MM_ISOTROPIC模式时,如果通过计算window与viewport范围的比值得到两个方向的单位刻度值不同,那么将会以较小的那个为准
MM_ANISOTROPIC允许两个坐标的刻度不一样
默认下,即没有用SetWindowExt来设定一个逻辑单位对应多少个像素的时候,MM_ANISOTROPIC和MM_ISOTROPIC使用MM_LOMETRIC映射模式,即Y向上,X向右,一个逻辑单位映射成0.1毫米 8.SetWindowExt(int Lwidth,int Lheight) //参数的单位为逻辑单位(Logical);
SetViewportExt(int Pwidth,int Pheight) //参数的单位为像素(Pixel);
以x轴为例(y轴类似),逻辑坐标系中的x轴的单位刻度=|Pwidth| / |Lwidth|。
这表示x轴上一个逻辑单位等于多少个像素。
还有一点要注意的是,如果Lwidth与Pwidth同号,逻辑坐标的x轴方向与设备坐标系中的x轴方向相同,否则相反。
SetWindowExt设定的都是正值,则是X右Y下,负值相反。
SetViewportExt也一样。
SetViewportExt和SetWindowExt设定的坐标值符号相反,则表示把窗口的轴方向映射到视口的反方向
SetWindowExt,SetViewportExt最好成对出现,不然会有一个默认的不确定的映射
问:
当滚动条右向拉10个单位,逻辑坐标的(0,0)到什么地方去了呢?
答:
还是(0,0)
分析:
1.滚动条移动是视口移动了.变化的是视口的坐标原点(即视口矩形的中心点)相当于SetViewportOrg(10,0)函数的功能.
2.绘图中坐标涉汲几个概念:
逻辑环境(画布)、窗口、设备环境、视口(设备环境大中的一部分)、坐标系、坐标转换(映像)。
逻辑环境:
位置在想象中的并不存在;使用逻辑坐标(映像模式全是指逻辑坐标)坐标Y轴方向由设置的逻辑坐标模式来决定坐标。
原点位置在逻辑环境的中心点,不可改动!
坐标值可以有负值的!
窗口:
逻辑环境中的一小部分,是一个矩形框;坐标系是逻辑坐标,SetWindowOrg()设置窗口矩形框的中心点(即窗口的原点,不是窗口矩形的左上角)的坐标,默认值为逻辑坐标的原点。
设备环境:
显示器、打印机等等。
坐标系为设备坐标系,正Y轴向下,正X轴向右,原点在左上角,固定不变,不可修改,其X、Y的负半轴为虚设,无法显示或无法打印图形。
视口:
设备环境中的一部分,一个矩形框;坐标系同设备环境。
SetViewportOrg()设置视口矩形框的中心点,默认值为坐标原点。
视口是窗口的按比例的映像(投影),因设备环境的坐标系X、Y负半轴是虚设无法显示,故要常常平移视口。
//逻辑环境与窗口在一个平面上(联想:
电影胶卷),设备环境与视口在一个平面上(联想:
放映的屏幕)
//映像过程就是电影放映时图像的转换过程
坐标转换:
编程时的“设备无关性”决定了绘图函数用的全是逻辑坐标,这就需要坐标转换语句来自动完成逻辑坐标单位向逻辑坐标单位的转换,因此要常常用到pDC->LPtoDP。
坐标转换的过程是一个映像的过程,与坐标系方向无关,逻辑环境中画出的图与设备环境中显示的图形方向大小(各向同性和各向异性模式是按比例缩放;宽屏显示器横向自动放大比例)是一样的,画多大显示多大。
注意可以用SetViewportOrg()和SetWindowOrg()在任何绘图模式下进行平移,但是,SetViewportExt()和SetWindowExt()是为各向同性和各向异性模式预留的,其它模式用不用没什么区别,可以省略!
当SetViewportExt(),SetWindowExt()中的参数出现负数,说明坐标轴方向反向。
对于各向同性和各向异性模式使用SetViewportExt()前先用SetWindowExt(),然后用pDC->LPtoDP()映像,最后就可以选画笔绘图了
LPtoDP()只对各向同性与各向异性模式(自定义模式)起作用,其它模式自带这个功能。
其它模式不需要用LPtoDP(),自动含这个功能.
(2)
dc.SetViewportOrg(100,100);
CRectrect(0,0,200,200);
dc.rectangle(rect);
将设备坐标的原点设置到(100,100);即设备坐标的原点不在(0,0)处,而是在(100,100)处;此时若执行映射的话,逻辑坐标的原点(0,0)需要与设备坐标的原点(100,100)重合;那么此时绘制的矩形(0,0,200,200)的坐标(为逻辑坐标)在设备坐标中就会映射为(100,100,300,300),最终我们在显示器上看到的会是一个向右下方偏移(100,100)的一个边长为200的正方形(用户看到的点是在设备坐标中的)
(3)
dc.SetWindowOrg(100,100);
CRectrect(0,0,200,200);
dc.rectangle(rect);
将逻辑坐标的原点设置到(100,100);即逻辑坐标的原点不在(0,0)处,而是在(100,100)处;此时若执行映射的话,设备坐标的原点(0,0)需要与逻辑坐标的原点(100,100)重合;那么此时绘制的矩形(0,0,200,200)的坐标(为逻辑坐标)在设备坐标中就会映射为(-100,-100,100,100),最终我们在显示器上看到的会是一个只有1/4个大小的矩形的一部分(事实上相当于向左上方偏移(100,100)的一个边长为200的正方形。
注意:
用户看到的点是在设备坐标中的)