[MFC]映射模式、坐标转换、原点移动

原创 2015年07月08日 13:11:45

1. 映射模式的概念:

    1) 也是DC的重要属性之一,它和绘图时的尺寸有关;

    2) 在没有映射模式的时候绘图只能以像素点为单位长度进行绘图,但是这样做有一个明显的坏处就是,不同显示器分辨率、屏幕大小各不相同,在一个屏幕上画1000像素长的线很长,同样像素点的长度换到另一个屏幕上看上去却可能很短,这无法达到不同屏幕绘制的图形效果相同的目的,因此要引入映射模式这个功能来解决上述问题;

    3) 映射模式规定,在利用GDI绘图的时候统一使用逻辑长度单位,然后通过某种方法(公式)将逻辑尺寸映射成实际物理屏幕的像素点长度,不同映射模式决定了一个逻辑单位代表多少个像素点长;

    4) 映射模式的两个对象:

         i. 逻辑坐标:即传递给绘图API函数的坐标值,是一种抽象、统一、设备无关的人为假定的坐标值;

         ii. 设备坐标:即屏幕上的具体像素点坐标;

         iii. 映射模式决定了如何从逻辑坐标转化成设备坐标,因为具体的物理设备只认识像素点位置这个东西,就好像计算机只认识01一样;

    5) 映射模式属性的操作:SetMapMode、GetMapeMode,默认值是MM_TEXT,MM即MapMode的缩写,默认的MM_TEXT映射模式不做任何映射,逻辑单位1就代表1个像素点;


2. 常用的GDI映射模式:

    1) 有了映射模式就可以选择诸如“一逻辑单位等于1厘米”之类的映射模式了,这样则在绘图时长度、尺寸等就和屏幕分辨率无关了,不同屏幕之间的调整完全都是自动的,MFC内部全部都实现了,比如在一块屏幕上一厘米等于100个像素点,而另一块屏幕上一厘米等于135个像素点,这这些映射工作MFC都在内部自动完成了,这样就可以实现按比例的缩放,并且与屏幕分辨率、大小无关;

    2) 常用的映射模式:其中原点都是左上角,x轴都是朝右的

MM_TEXT:1 pixel / 1 lg,y+

MM_LOMETRIC:0.1 mm / 1 lg,y-

MM_HIMETRIC:0.01 mm / 1 lg,y-

MM_LOENGLISH:0.01 in / 1 lg,y-

MM_HIENGLISH:0.001 in / 1 lg,y-

MM_TWIPS:1/1440 in / 1 lg,y-

!!0.01 in / 1 lg就表示1逻辑单位但与0.01英寸,一起类推,lg就是logical的意思,而y+表示y轴朝下,y-表示y轴朝上;

!!公制映射模式:就是指以上所有y-的映射模式,公制就是指国际定标的长度单位,如厘米、米、英寸等,并且公制习惯坐标轴的y轴朝上;

!!所以一定要注意,在使用公制映射模式时y轴坐标一定要传负的,否则图形会不见的!

!!同样也要注意,在公制和非公制的映射模式之间转换的时候,y轴坐标一定要取反,否则模式改变后绘制的图形也会不见的!

    3) 用户自定义类型映射模式:

         i. 有两种,这两种的映射比例可以自定义,而且x轴和y轴的方向也可以自定义;

         ii. MM_ISOTROPIC:各向同性,x轴和y轴的映射比例必须相同;

         iii. MM_ANISOTROPIC:各向异性,x轴和y轴的映射比例可以不同;


3. 可编程映射模式:

    1) 即用户自定义映射模式,即MM_ISOTROPIC和MM_ANISOTROPIC这两种;

    2) 一个典型的用法:

GetClientRect(&rcClient); // 在改变模式以前是MM_TEXT,即逻辑单位等于像素单位
dc.SetMapMode(MM_ANISOTROPIC); // 以各向异性为例
dc.SetWindowExt(500, 500); // 指定逻辑窗口为500×500的逻辑单位
dc.SetViewportExt(rcClient.Width(), rcClient.Height()); // 指定设备视口为width×height的像素单位
// 完成后,x轴比例为(width/500) pixel / 1 lg,y轴比例为(height/500) pixel / 1 lg
dc.Ellipse(0, 0, 500, 500); // 所有的绘图输入的都是逻辑单位
!其中Window Port为窗口,View Port为视口,窗口使用的是逻辑单位,而视口使用的是设备尺寸,单位即为像素;

    3) 设置比例的两个函数:

         i. virtual CSize CDC::SetWindowExt(int cx, int cy);

         ii. virtual CSize CDC::SetViewportExt(int cx, int cy);

!!两者的返回值都是修改之前的cx和cy,CSize其实就是一个结构体,里面有cx和cy两个域;

!!cx为宽,cy为高,参数也可以直接传CSize或SIZE结构体,MFC都重载过了;

!!Ext即为Extend的缩写,即范围的意思,只不过SetWindowExt设定的是逻辑窗口的范围,而SetViewportExt设定的是设备视口的范围(单位为像素点);

    4) 上面的这个例子只是自定义了映射比例,但是没有自定义轴的方向,默认情况下x轴朝右y轴朝下,如果想让某一个轴反向,只需要在两个SetExt函数中选一个为目标轴的参数传负数即可,注意!!必须是两选一,不能两个都函数的那个参数都传负数,选哪个函数无所谓,都是对称的,比如:

SetWindowExt(-500, 500);
SetViewportExt(10000, 10000);
!这就让x轴反向了,y轴反向同理;

    5) ANISOTROPIC和ISOTROPIC的区别:后者强制要求x轴和y轴的映射比例相同,如果在使用两个SetExt函数时故意让两个比例不相同,则MFC将强制将比例设为“逻辑单位:设备单位”较大的那个;

!!ISOTROPIC特别适合画圆、正方形等正则图形,当然MM_TEXT本身也是各向同性的,x轴和y轴都是1:1的像素点;


4. 坐标转换:

    1) 问题背景:设想,你一直在一种公制的映射模式下编程,但是诸如鼠标击中测试之类的消息携带的击键坐标都是设备坐标(即像素点的位置),想要知道鼠标是否击中了某个区域那肯定得现将击中的设备坐标转化成公制坐标后才能进行判断,不可能拿设备坐标和公制坐标这两个不能相提并论的东西进行比较吧;

    2) 逻辑坐标和设备坐标转换的函数:

         i. 逻辑坐标转化成设备坐标:void CDC::LPtoDP(LPPOINT lpPoints, int nCount = 1) const; 

         ii. 设备坐标转化成逻辑坐标:void CDC::DPtoLP(LPPOINT lpPoints, int nCount = 1) const;

!!LP即Logical Points的简称,DP即Device Points的简称;

!!第一个参数是一个点的数组,也可以是CPoint的数组,第二个参数是要转换的点的个数,结果直接修改在原数组中,默认情况下就只有一个点;

    3) 示例:

原设备坐标,欲得到LOENGLISH的公制坐标,目标是窗口中心位置:

CRect rcClient;
GetClientRect(&rcClient);
CPoint point(rcClient.Width() / 2, rcClient.Height() / 2);
CClientDC dc(this);
dc.SetMapMode(MM_LOENGLISH);
dc.DPtoLP(&point);
原设备坐标,欲得到公制LOENGLISH坐标(100, 100)对应的设备坐标:

CPoint point(100, 100);
CClientDC dc(this);
dc.SetMapMode(MM_LOENGLISH);
dc.LPtoDP(&point);


5. 移动原点:

    1) 问题背景:就像通常的数学研究都是将坐标系放在平面中心或者平面左下角,而不是一般计算机画面的左上角,因此有时为了方便或者说是顺眼,需要将原点移动到其它位置;

    2) 有两种方法:一种是移动逻辑窗口的原点,还有一种是移动设备视口的原点,两者只要移动其中之一即可,不能同时移动这两个口的原点,否则会混乱的

         i. 移动逻辑窗口原点:CPoint CDC::SetWindowOrg(int x, int y);

         ii. 移动设备视口原点:virtual CPoint CDC::SetViewportOrg(int x, int y);

         iii. 返回值是修改前的原点坐标,参数还可以穿CPoint和POINT结构体,Org即Origin“原点”的缩写;

!!为什么两者只需要设定一个就可以了,因为只要一个设定过了,则MFC底层的映射公式就会自动将两个口的原点的移动统一在一起了;

!!比如,利用SetViewOrg将视口的(0, 0)移动到了(x, y),这就相当于将逻辑点(0, 0)映射到了设备点(x, y)上,因此不用再移动逻辑点,里面的映射关系已经包含了;

!!若利用SetWindowOrg将逻辑点(0, 0)移动到了(x, y),就相当于将逻辑点(x, y)映射到了设备点(0, 0)上,所有的一切都可以用逻辑坐标到设备坐标的映射上来;

    3) 示例:假设目前处于MM_TEXT,接下来要在MM_HIMETRIC模式下画图,并且原点要在平面的左下角,那么根据上面说的只需设定一个口即可,通常设定视口最方便,因此范例代码如下

CRect rcClient;
GetClientRect(&rcClient);
dc.SetViewportOrg(0, rcClient.Height);
dc.SetMapMode(MM_HIMETRIC);
...


MFC 逻辑坐标原点与设备坐标原点的移动

转自http://blog.sina.com.cn/s/blog_6ab0b9a80101dwud.html --------------------------------------------...
  • dy106
  • dy106
  • 2013年04月09日 19:28
  • 1403

设置MFC坐标系

注意一点:把设置代码放在画图类的前面。即可显示。一味的放在OnDraw()里有时候是没用的。设置MFC坐标系,读懂以下函数: CRect   rect; GetClientRect(&rect); p...
  • awsqsh
  • awsqsh
  • 2010年11月15日 15:20
  • 7505

梁友栋-Barsky裁剪算法

Cyrus和Beck用参数化方法提出了比Cohen-Sutherland更有效的算法。后来梁友栋和Barsky独立地提出了更快的参数化线段裁剪算法,也称为Liany-Barsky(LB)算法。   ...

MFC中TeeChart插件绘图

TeeChart绘图:   通过CTchart 的get_SeriesCount函数获得所有图像序列,再全部清除 1.   for(long i = 0;i 2.      {   3...

Windows编程中的映射模式和坐标转换

Windows编程中的映射模式和坐标转换    一、Windows中的映射模式    1、Windows定义映射模式的目的    经过我的综合,Windows定义映射模的目的又以下几个方面:...

Windows编程中的映射模式和坐标转换02

一、Windows中的映射模式 1、Windows定义映射模式的目的 经过我的综合,Windows定义映射模的目的又以下几个方面:1、不同人的使用习惯。不同国家的,不同地区,以及不同的人因为习惯喜...

MFC绘图映射模式设备坐标问题

  • 2014年03月07日 22:55
  • 183KB
  • 下载

MFC 图形编程基础——映射模式和坐标变换

1.设备坐标系和逻辑坐标系 在MFC绘图中,存在两种坐标系,一是设备坐标系,二是逻辑坐标系。 1.1 设备坐标系 设备坐标系以视图区的左上角为原点,向右为X轴正方向,向下为Y轴正方向。其度量单位...
  • gll028
  • gll028
  • 2013年03月05日 15:42
  • 702

MFC 打印预览 映射模式 坐标变换

 MFC提供了一个框架性的打印和打印预览功能代码,它的基本思想是将实际显示和打印文档的代码合二为一,即都由此文档关联的CView中的OnDraw(CDC *pDC)来处理,由MFC框架根据用户的...

MFC CScrollView中的设备坐标和逻辑坐标转换

CView派生类的说明 CEdit View 实现像便签多行正文编辑器的视图 CFormView 使用对话框控件模板资源来定义用户应用程序接口的滚动视图 CListView 支持重点在列...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[MFC]映射模式、坐标转换、原点移动
举报原因:
原因补充:

(最多只允许输入30个字)