逻辑单位与设备坐标(转)

设备坐标逻辑坐标 要用到两个函数:CDC::LPtoDP  将逻辑坐标换为设备坐标CDC::DPtoLP  将设备坐标换为逻辑坐标 设备坐标(Device Coordinate)又称为物理坐标(Physical Coordinate),是指输出设备上的坐标。通常将屏幕上的设备坐标称为屏幕坐标设备坐标用对象距离窗口左上角的水平距离和垂直距离来指定对象的位置,是以像素为单位来表示的,设备坐标的X轴 阅读详情

CDC::SetMapMode 

virtual int SetMapMode( int nMapMode );

函数功能描述:该函数设置指定设备环境的映射方式,映射方式定义了将逻辑单位转换为设备单位的度量单位,并定义了设备的XY轴的方向。

nMapMode:指定新的映射方式,此参数可以是下面列出的任何一个值。

  MM_ANISOTROPIC:逻辑单位转换成具有任意比例轴的任意单位,用SetWindowExtExSetViewportExtEx函数可指定单位、方向和比例。

MM_HIENGLISH:每个逻辑单位转换为0.001英寸X的正方面向右,Y的正方向向上。

  MM_HIMETRIC:每个逻辑单位转换为0.01毫米X正方向向右,Y的正方向向上。

  MM_ISOTROPIC:逻辑单位转换成具有均等比例轴的任意单位,即沿X轴的一个单位等于沿Y轴的一个单位,用和函数可以指定该轴的单位和方向。图形设备界面(GDI)需要进行调整,以保证XY的单位保持相同大小(当设置窗口范围时,视口将被调整以达到单位大小相同)。

  MM_LOENGLISH:每个逻辑单位转换为0.1英寸X正方向向右,Y正方向向上。

  MM_LOMETRIC:每个逻辑单位转换为0.1毫米X正方向向右,Y正方向向上。

  MM_TEXT:每个逻辑单位转换为一个图素,X正方向向右,Y正方向向下。

MM_TWIPS;每个逻辑单位转换为打印点的120(即11400英寸),X正方向向右,Y方向向上。

 

备注:

MM_TEXT方式允许应用程序以设备像素为单位来工作,像素的大小根据设备不同而不同。MM_HIENLISH, MM_HIMETRIC, MM_LOENGLISH, MM_LOMETRICMM_TWIPS方式对必须用物理意义单位(如英寸或毫米)制图的应用程序是非常有用的。MM_ISOTROPIC方式保证了11的纵横比。MM_HIENLISH方式允许对XY坐标分别进行调整。

 

SetViewportOrgSetWindowOrg

 

CDC::SetWindowOrg

CPoint SetWindowOrg(int x ,int y );

CPoint SetWindowOrg(POINT point )

返回值:CPoint对象,是窗口初始位置的前一次取值(逻辑单位)。

参数: x 指定窗口初始位置的X逻辑坐标。

y 指定视图端口初始位置的Y逻辑坐标。

point 指定窗口初始位置。其值必须在设备坐标系统范围内。可以为该参数传递POINT结构或CPoint对象。

 

说明:

设置设备上下文的窗口初始位置。它和设备上下文窗口一起说明了GDI如何将逻辑坐标中的点映射到实际设备坐标中。换言之,它们说明了GDI如何将逻辑坐标转换为设备坐标。窗口初始位置表明在设备坐标系统中的点,GDI将视图端口初始位置与该点映射。窗口初始位置是由SetWindowOrg成员函数在逻辑坐标系统中指定的。GDI在映射其它点时遵从同样的过程,这需要窗口初始位置与视图端口初始位置的映射。例如,所有以窗口初始位置为中心的圆周上的点同样是以视图端口初始位置为中心的圆周上的点。同样地,通过窗口初始位置的直线上的所有点也将形成一条通过视图端口初始位置的直线。

 

CMyStatic::OnPaint() 函数中测试

 

CPaintDC dc(this); // device context for painting

 

// TODO: Add your message handler code here

CRect rect;

GetClientRect(&rect);//取得控件大小

dc.SetMapMode(MM_ANISOTROPIC);//设置成可以改变作标轴方向和比例的,但下面没改变比例

 

.先讨论X轴正向向左,Y轴正向向下的情况,即默认的状态

dc.SetWindowExt(100, 100);//逻辑上是长100个单位,宽100个单位

dc.SetViewportExt(200,200);//设备是长200像素,宽200像素

即一个逻辑单位 = 200 / 100 = 2个像素

 

如果上面第一行改成dc.SetWindowExt(100, 200);//那么,一个逻辑长单位就是2像素,逻辑高单位就是1个像素

同样的dc.Rectangle(0, 0, 10, 10);第一个就是正方形,而第二个就是长是宽2倍的长方形

 

2.现在谈谈关于设备原点和逻辑原点的问题。

我的理解是,设备原点永远在左上角,也就是最初的(0,0)的位置。逻辑原点是可以移动的,Y轴的正向是向上还是向下是可以改变的。

现在考虑Y轴向下为正向时,逻辑原点的移动问题。

dc.SetWindowOrg(0, 0);//这个可省略

dc.SetViewportOrg(rect.right, rect.bottom);

这个就是把设备的(rect.right, rect.bottom)映射为逻辑原点(0, 0)

那就就相当于,把逻辑原点从原来设备原点(0,0)平移到了(rect.right, rect.bottom),即整个作标系,向右平移了rect.right,向下平移了rect.bottom.

dc.SetViewportOrg(0, 0);//这个可省略

dc.SetWindowOrg(rect.right, rect.bottom);

这个是把逻辑的(rect.right, rect.bottom)映射为设备的(0, 0);也可以说是把设备的(0, 0)映射为逻辑的(rect.right, rect.bottom)

可以想像,设备原点(0, 0)永远在左上角,由于Y轴是向下为正,X轴向右为正,那逻辑原点就被向上移动了rect.bottom,向左移动了rect.right,这样,刚好逻辑坐标(rect.right, rect.bottom)落在了右上角的位置。

然而dc.Rectangle(0, 0, rect.right, rect.bottom);画出的长方形,就正好完全落在窗口这外了,要想和dc.SetViewportOrg(rect.right, rect.bottom);达到相同的效果,必须要把逻辑原点向右和向下移动,也就是,移动动后的逻辑坐标(-rect.right, -rect.bottom);落在设备原点上,即把逻辑的(-rect.right, -rect.bottom)映射为设备的(0, 0);

dc.SetWindowOrg(-rect.right, -rect.bottom);

如果SetWindowOrgSetViewportOrg同时使用,例如

dc.SetWindowOrg(x, y);

dc.SetViewportOrg(x1, y1);//不推荐同时用,因为通常会把自己给搞糊涂

即把逻辑坐标(x, y)映射为设备坐标(x1, y1),就相当于把逻辑原点向右移(x1 - x2), 向下移(y1 - y2)

综上所述,X轴正向向右,Y轴正向向下的情况下,

       dc.SetWindowOrg(-rect.right, -rect.bottom);等价于dc.SetViewportOrg(rect.right, rect.bottom);

dc.SetViewportOrg(rect.right, rect.bottom);dc.SetViewportOrg(rect.right, rect.bottom);刚互补,同时运行则效果抵消。

 

.现在讨论X轴正向向左,Y轴正向向上的情况

dc.SetWindowExt(100, -100);//逻辑上是长100个单位,宽100个单位

dc.SetViewportExt(200,200);//设备是长200像素,宽200像素

dc.SetWindowExt(100, 100);//逻辑上是长100个单位,宽100个单位

dc.SetViewportExt(200,-200);//设备是长200像素,宽200像素

 

如果

dc.SetWindowExt(100, -100);//逻辑上是长100个单位,宽100个单位

dc.SetViewportExt(200,-200);//设备是长200像素,宽200像素

Y轴仍向下

以下面为例:

dc.SetWindowExt(100, -100);//逻辑上是长100个单位,宽100个单位

dc.SetViewportExt(200,200);//设备是长200像素,宽200像素

dc.SetWindowOrg(0, 0);//这个可省略

dc.SetViewportOrg(0, rect.bottom);

 

设备(0, rect.bottom)映射为逻辑原点(0, 0),即把逻辑原点,移到左下角了

 

dc.SetViewportOrg(0, 0);//这个可省略

dc.SetWindowOrg(0, rect.bottom);

 

逻辑(0, rect.bottom);映身为设备原点(0,0),即设备原点(0, 0)映射为逻辑(0, rect.bottom);由于Y轴向上,所以相当于把逻辑原点由设备原点,向下移动rect.bottom,这样,逻辑(0, rect.bottom)刚好落在设备原点(0,0)上。即逻辑原点移动到了左下角。

这时可以发现,dc.SetViewportOrg(0, rect.bottom);dc.SetWindowOrg(0, rect.bottom);等价了,推广开来,即dc.SetViewportOrg(x, y);dc.SetWindowOrg(-x, y);等价

 

总结:保持X轴正向向右不变,当Y轴正向向下时

dc.SetViewportOrg(x, y);dc.SetWindowOrg(-x,   -y);等价

Y轴正向向上时

dc.SetViewportOrg(x, y);dc.SetWindowOrg(-x,   y);等价

需要强调一点,设备原点永远不会移动,保持在(0,0),设备的坐标系永远不会变,变的是逻辑原点在设备坐标系中的位置和逻辑坐标轴的方向。

 

SetWindowExtSetViewportExt

CRect rectClient;

GetClientRect(rectClient);

pDC->SetMapMode(MM_ANISOTROPIC);

pDC->SetWindowExt(CSize(1000,1000));

pDC->SetViewportExt(rectClient.right,-rectClient.bottom);

pDC->SetViewportOrg(rectClient.right/2,rectClient.bottom/2);

pDC->Ellipse(-500,-500,500,500);

可变比例映射模式,看到这一段的时候,一开始就把我的弄糊涂了。我一直没弄明白中间加红的几行代码是什么意思。把其注释掉,又没有原先的效果。在网上百度了半天。得出以下注释说明:

//SetWindowExe设定窗口尺寸,SetViewportExt设定视口尺寸。

//窗口尺寸以逻辑单位计算,视口尺寸以物理单位计算。

    CRect rectClient;

    GetClientRect(rectClient);//取窗口物理尺寸(单位:像素)

    pDC->SetMapMode(MM_ANISOTROPIC);

    pDC->SetWindowExt(1000, 1000);//窗口逻辑大小:1000*1000,

    pDC->SetViewportExt(rectClient.right, -rectClient.bottom);//改变Y坐标方向--viewport使用物理大小

    pDC->SetViewportOrg(rectClient.right / 2, rectClient.bottom / 2);//设置窗口中心点为坐标系原点--Viewport使用物理大小 

    pDC->Ellipse(CRect(-500, -500, 500, 500));//以逻辑单位画图---普通GDI API使用逻辑单位

//默认方式下,物理/逻辑值是11关系,可换用。但使用SetWindowExt/SetViewportExt后两者不可混用。

以上红色部分,我的解释是以物理的原点为坐标系,以逻辑的大小为单位画圆。后面的代码中会说明这一问题。

后来经过自己的捉摸,我想我终于搞清楚是怎么一回事情了。

所谓映射就是物理和逻辑的映射。使用GetClientRect方法后,获取到窗口的物理大小;然后再使用SetWindowExt,设置了窗口的逻辑大小,与之相对应的是SetViewportExt,也就是说在这里作了一个映射。SetWindowExt中的第一个参数

cx Specifies the x-extent (in logical units) of the window.

X宽度(可以这么理解吗?)与 SetViewportExt中的第一个参数

Cx Specifies the x-extent of the viewport (in device units).

相对应起来。好像中学的比例一样。逻辑宽度和物理宽度映射,逻辑高度和物理高度映射。这样,一旦映射关系确立之后,再使用后面的方法进一步的操作。

一开始的代码是在窗口中显示一个与之限定的圆,并且会随着窗口大小的改变亦会跟着改变。

       我现在稍稍把其中的参数改变一下。

CRect rectClient;

GetClientRect(rectClient);

pDC->SetMapMode(MM_ANISOTROPIC);

 

pDC->SetWindowExt(CSize(800,800));

pDC->SetViewportExt(rectClient.right,-rectClient.bottom);

pDC->SetViewportOrg(rectClient.right/2,rectClient.bottom/2);

pDC->Ellipse(-500,-500,500,500);

注意上面红色突出显示的代码。我现在将逻辑大小变小了一些。现在注意一下实际在画图的代码中(绿色显示),我并没有修改其参数。现在将其编译运行。会发现,实现中的圆的轨迹会超出窗口。

只是把物理与逻辑之前的映射调整了一下。

CRect rectClient;

       GetClientRect(rectClient);

pDC->SetMapMode(MM_ANISOTROPIC);

pDC->SetWindowExt(CSize(1000,1000));

pDC->SetViewportExt(rectClient.right,-rectClient.bottom);

       pDC->SetViewportOrg(rectClient.right/2,rectClient.bottom/2);

       pDC->Ellipse(0,0,500,500);

再调整一下参数,画出来的图你会发现,真正的成了二维坐标图。

经过以上一番测试,我想我应该明白每行代码的意思了。转换成自己的注释,应该更容易理解和记忆些。

          CRect rectClient;

          GetClientRect(rectClient); //获取物理设备大小

          pDC->SetMapMode(MM_ANISOTROPIC); //设置映射模式

          pDC->SetWindowExt(CSize(1000,1000));      //设备逻辑窗口大小(可能与物理窗口大小不一样)

          pDC->SetViewportExt(rectClient.right,-rectClient.bottom); //设置物理设备范围,为设定圆点作准备

          pDC->SetViewportOrg(rectClient.right/2,rectClient.bottom/2); //设置物理设备坐标原点,当然是在上一行代码的基础之上

         pDC->Ellipse(-500,-500,500,500); //以物理设置坐标原点为基础,以逻辑为单位,画圆。

 

可以改造一下,原来的代码,使之后容易理解一些:

          CRect rectClient;

          GetClientRect(rectClient);

          pDC->SetMapMode(MM_ANISOTROPIC);

          pDC->SetWindowExt(CSize(1000,1000));

          pDC->SetViewportExt(rectClient.right,-rectClient.bottom);

          pDC->SetViewportOrg(rectClient.left,rectClient.bottom); //设置窗口左下角为原点坐标

 

          pDC->Ellipse(0,0,1000,1000);

From:http://www.360doc.com/content/10/0803/12/1066008_43348939.shtml

 

GDI MM_HIMETRIC映射模式为逻辑单位毫米而非像素 GDI MM_HIMETRIC映射模式为逻辑单位毫米而非像素.7z 立即下载

相关推荐

VC中坐标系的建立

建立一个合适的 坐标系可以为我们的绘图带来很大的方便 。下面介绍一下如何在VC中建立我们想要的坐标系。一 设备坐标逻辑坐标  设备坐标(Device Coordinate)又称为物理坐标(Physical Coordinate),是指输出设备上的坐标。通常将屏幕上的设备坐标称为屏幕坐标设备坐标用对象距离窗口左上角的水平距离和垂直距离来指定对象的位置,是以像素为单位来表示的,设备坐标的X

Augusdi的专栏 2235

MM_HIMETRIC映射模式下文字倒的问题解决代码如下:

// 对绘制矩阵进行临时的变换来解决     Graphics m_pGp(hDC);     Matrix matrixOld, matrixNow;     m_pGp->GetTransform(&matrixOld);    m_pGp->GetTransform(

Mdesigner的专栏 716

理解SetMapMode,SetWindowOrg,SetViewportOrg,SetWindowExt,SetViewportExt

CDC::SetMapMode  virtual int SetMapMode( int nMapMode ); 函数功能描述:该函数设置指定设备环境的映射方式,映射方式定义了将逻辑单位换为设备单位的度量单位,并定义了设备的X、Y轴的方向。 nMapMode:指定新的映射方式,此参数可以是下面列出的任何一个值。   MM_ANISOTROPIC:逻辑单位换成具有任意比例轴的任意单位,用...

爬行的菜鸟的博客 2169

windows画图常用函数 二

SetMapMode() 简介   函数功能描述:该函数设置指定设备环境的映射方式,映射方式定义了将逻辑单位换为设备单位的度量单位,并定义了设备的X、Y轴的方向。   函数原型:int SetMapMode(HDC hdc, int fnMapMode); 编辑本段 参数:   hdc:指向设备环境的句柄。   fnMapMode:指定新的映射方式,此参数可

嵌入式学习小生! 2858

逻辑坐标设备坐标——全窗口坐标、屏幕坐标、客户区坐标的总结

Windows应用程序绘制图形时使用的是一种逻辑单位,每个逻辑单位的大小由映射模式决定,这个逻辑单位既可以设备单位(屏幕或打印机上的一个像素点)相同,也可以是一种物理单位(如毫米),还可以是用户自定义的一种单位。在Windows应用程序中,只要输出有关系,都要使用映射模式。   首先谈谈映射模式基本知识,当Windows应用程序在其客户区绘制图形时,必须给出在客户区的位置,其位置用x和y ...

爬行的菜鸟的博客 1359

[MFC]逻辑坐标系和设备坐标

建立一个合适的坐标系可以为我们的绘图带来很大的方便。下面介绍一下如何在VC中建立我们想要的坐标系。 (1) 设备坐标(Device Coordinate)又称为物理坐标(Physical Coordinate)。设备坐标用对象距离客户区窗口左上角的水平距离和垂直距离来指定对象的位置,是以像素为单位来表示的。 逻辑坐标(LogicalCoordinate)是系统用作记录的坐标

Love_Basketballer的博客 2321

MFC-设备坐标逻辑坐标

MFC-设备坐标逻辑坐标

博客文章说明 5444

理解映射方式、设备坐标系、逻辑坐标系、设置逻辑坐标原点设备坐标原点

 在VC下进行GDI编程,理解映射方式、设备坐标系、逻辑坐标系、设置逻辑坐标原点和设备坐标原点,真的把我折磨的够厉害的,花了很多时间,终于弄明白一些了,在此记录下,以便以后温习。   一、关于映射方式 参考的网络文章地址:http://blog.csdn.net/xuyongbeijing2008/article/details/8063801  映射方式定义了将逻辑单位换为设备单位的...

爬行的菜鸟的博客 800

VC的逻辑坐标设备坐标

 以前看了一点windows程序设计还有VC一点东西,对windows坐标系好像就是有一点迷惑.现在开始系统的学习MFC,又涉及到了这个问题,确实有些不解,于是搜到一些资料:  所谓设备坐标逻辑坐标只是相对的概念。     比如点pt(1000,1000),如果你认为他是     设备坐标,那么经过下变换,他就变成逻辑     坐标:      dc.DPtoLP(&pt);     如果你

nizainade的专栏 2292

搞不清MFC 绘图逻辑坐标设备坐标关系的请进

SetWindowExt和SetViewportExt函数可以确定窗口(代表逻辑坐标系,各轴单位逻辑单位)和视口(代表设备坐标系,各轴单位为像素)的范围,还有逻辑坐标系轴的方向。当窗口和视口指定的宽度符号相同则逻辑坐标系X轴正向朝右,相反则正向朝左。Y轴也同理,同号正向朝下,异

shineseth的专栏 1101

窗口,视口,逻辑坐标设备坐标

查了一晚上资料,终于把窗口视口的映射搞明白了。 窗口是指一个虚拟存在的屏幕,看不到的,而视口是在屏幕上看到的视图客户区域。Windows绘图时,并不是把图形直接绘制到屏幕上去,而是以各种方式下的坐标系将图形绘制到序幕的窗口中,然后将这个窗口的内容映射到视口中,如果映射到屏幕,就实现了图形的显示,如果映射到打印机,就实现了图形的打印。 坐标系分三种:整屏幕坐标,整窗口坐标,客户区坐标

1650
上一篇: 位运算和移位运算(转)
下一篇: 在ctex中出现texify failed to create a dvi file怎么办(转)
cg_csu
博客等级 码龄16年 3粉丝 6原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值