热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

GDI中的坐标映射问题(3)

3.从程序员的角度来看坐标映射坐标映射在程序员的眼中就是要根据自己实际问题的要求,构造出一个满足要求的逻辑空间。所谓的满足要求就是指每一个我们在程序中使用的点,都能出现在physical

3.从程序员的角度来看坐标映射
   坐标映射在程序员的眼中就是要根据自己实际问题的要求,构造出一个满足要求的逻辑空间。所谓的满足要求就是指每一个我们在程序中使用的点,都能出现在physical device上我们预期的相应位置。由于device空间到physical device空间是一对一的映射,因此,我们完全可以将绘图目的地看成device空间,所构造出的逻辑空间也只需正确映射到device空间就可以了。

3.1 page空间 → device空间

    如果我们不使用world空间,此时的逻辑空间就是page空间。下面来看如何确定它的三个要素:单位刻度值、方向、原点。
首先要使用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 |。

   这表示x轴上一个逻辑单位等于多少个像素。下面举例加以解释。
   比如我们先通过GetDeviceCap(LOGPIXELSX)获得在我们的显示器上每英寸等于多少个像素,设为p,然后我们将它赋给Pwidth,将Lwidth赋成2,即Pwidth / Lwidth=p / 2。那么,此时page空间x轴上的单位刻度就是p / 2个像素;又由于p个像素是代表一个英寸的,所以此时的page空间x轴上的单位刻度同时也是半个英寸。
   请注意这个例子中,虽说viewport的x方向“范围”是p个像素,但是device空间x轴的“范围”决不仅仅是p个像素,而是2^27个像素,至于可视的范围到底是多少,则取决于物理设备空间。

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空间的单位刻度(比如y轴上每逻辑单位200 / 100=2个像素),以及y轴的方向与device空间相同(100与200同号),但是page空间的原点在哪里呢?请看:
首先我们分别在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空间
    有时候我们需要从一个倾斜的角度显示一个圆或者其它什么图形,但是我们在使用绘图语句时,心目中仍然要当这个圆正对着我们来考虑问题,因为只有这样,我们在构造图形时的思维才不至于混乱,怎么实现呢?就可以通过加上world空间达到这个目的。由于一般很少使用这种映射,我在这里只以一个例子简单加以说明。

void CSampleView::DrawShearCircle()

{
       CClientDC dc(this);
       dc.SetMapMode(MM_ANISOTROPIC);  //映射模式设定为各向异性。
       //以下语句将page空间最小刻度值设为1mm,原点位于客户区矩形中心,x正向向右,y正向向上。

       dc.SetWindowExt(1, -1);
       int PperMMX = dc.GetDeviceCaps(HORZRES) / dc.GetDeviceCaps(HORZSIZE);
       int PperMMY = dc.GetDeviceCaps(VERTRES) / dc.GetDeviceCaps(VERTSIZE);
       dc.SetViewportExt(PperMMX, PperMMY);
       CRect cr;
       GetClientRect(&cr);
       dc.SetViewportOrg(cr.right/2, cr.bottom/2);
       dc.SetWindowOrg(0, 0);
       //以下语句设置world空间到page空间的映射规则,将会产生一个y轴的剪切。

SetGraphicsMode(dc.GetSafeHdc(), GM_ADVANCED);   //一定要首先打开GM_ADVANCED。

       XFORM xf;
       xf.eM11 = 1.0;
       xf.eM12 = 1.0;  //y轴方向的剪切常量为1.0
       xf.eM21 = 0.0;  //x轴方向的剪切常量为0.0
       xf.eM22 = 1.0;
       xf.eDx  = 0.0;
       xf.eDy  = 0.0;
       SetWorldTransform(dc.GetSafeHdc(), &xf);
       dc.Rectangle(-50, 50, 50, -50);  //这个矩形的中心在客户区中心,长度为100mm。不过由于设置了world空间,尽管从语句上来看是一个正方形,但是实际显示的却是一个锐角为45°的菱形。
       dc.Ellipse(-50, 50, 50, -50);  //尽管从语句上来看是一个圆,但是实际显示的却是一个椭圆。

}


推荐阅读
  • 如何在HTML中获取鼠标的当前位置
    本文介绍了在HTML中获取鼠标当前位置的三种方法,分别是相对于屏幕的位置、相对于窗口的位置以及考虑了页面滚动因素的位置。通过这些方法可以准确获取鼠标的坐标信息。 ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
  • 本文介绍了解决mysql 5.1启动问题的方法,通过修改my.ini文件中的相关配置,包括innodb_data_home_dir和skip-innodb等,可以解决启动问题。同时还介绍了如何调整内存池来存储metadata信息。 ... [详细]
  • Python字典推导式及循环列表生成字典方法
    本文介绍了Python中使用字典推导式和循环列表生成字典的方法,包括通过循环列表生成相应的字典,并给出了执行结果。详细讲解了代码实现过程。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 本文介绍了django中视图函数的使用方法,包括如何接收Web请求并返回Web响应,以及如何处理GET请求和POST请求。同时还介绍了urls.py和views.py文件的配置方式。 ... [详细]
  • 本文总结了在编写JS代码时,不同浏览器间的兼容性差异,并提供了相应的解决方法。其中包括阻止默认事件的代码示例和猎取兄弟节点的函数。这些方法可以帮助开发者在不同浏览器上实现一致的功能。 ... [详细]
  • 本文介绍了利用ARMA模型对平稳非白噪声序列进行建模的步骤及代码实现。首先对观察值序列进行样本自相关系数和样本偏自相关系数的计算,然后根据这些系数的性质选择适当的ARMA模型进行拟合,并估计模型中的位置参数。接着进行模型的有效性检验,如果不通过则重新选择模型再拟合,如果通过则进行模型优化。最后利用拟合模型预测序列的未来走势。文章还介绍了绘制时序图、平稳性检验、白噪声检验、确定ARMA阶数和预测未来走势的代码实现。 ... [详细]
author-avatar
rhp3465483
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有