理解Windows坐标系概念及其转换

1. Windows坐标系统

坐标系主要分为两种:

  1. 逻辑坐标系:主要是在“虚拟界面”中绘图,是绘制到设备坐标系的准备阶段。
  2. 设备坐标系:由客户区坐标、窗口坐标、屏幕坐标组成,主要和显示设备有关。

在不同的空间中,各个坐标系及其坐标表示方法稍有不同。世界空间和页面空间的坐标系为平时熟悉的方式,x轴向右为正,y轴向上为正,设备空间中,y轴改为向下为正(要问为什么这么定,emm,自己问MS去)。

理解Windows坐标系概念及其转换_第1张图片

MS其实对绘制的流程进行了明确的定义,且在不同空间中进行操作时的职能进行了分离,使不同层级下的操作内容更明确。先说逻辑坐标系中的绘制,windows定义的绘图流程如下:

  • 窗口上绘制大小和原点配置(可使用默认值);
  • 世界空间上绘制(允许对图形的缩放、平移、旋转、裁剪、镜像);
  • 页面空间绘制(设置映射模式SetMapMode,确定怎么画到设备空间上);

接下来是设备坐标系的绘制,流程如下:

  • 视口上绘制大小和原点配置(可使用默认值);
  • 设备空间绘制(仅允许进行平移操作);
  • 物理设备显示(最终显示在对应的区域)。

 

注意点:viewPort 和 windowsPort,这两者的翻译是视口,窗口。视口是基于设备坐标(像素的),窗口是基于逻辑坐标的,默认情况下两者重合,但可设置视口坐标系的原点以及窗口坐标系的原点。

  • 要注意区分视口坐标系原点跟视口原点的区别,窗口坐标系原点跟窗口原点的区别。
  • 视口坐标系其实就是设备坐标系,它是固定不变的,因此设备原点永远是(0,0)。
  • 视口原点是可变的,它默认处于设备原点,但是可以更改。
  • 窗口坐标系指定了在窗口绘图时的参考点,参考点就是窗口坐标系的原点。
  • 窗口原点默认等于窗口坐标系原点,但是窗口原点可以改变。
  • 窗口原点永远跟视口原点匹配映射。//这个是最主要的

2. 常见函数及参数

世界空间绘制的常用函数:

函数 主要参数 作用
SetWorldTransform CONST XFORM *lpXform 对图形处理,包括缩放、平移、旋转、裁剪、镜像
SetGraphicsMode

int iMode:

GM_COMPATIBLE(默认)

GM_ADVANCED(可使用SetWorldTransform)

设置特定设备上下文的图形模式

页面空间绘制常用参数:

函数 主要参数 作用
SetMapMode

int fnMapMode:

MM_ANISORTOPIC:自定义缩放比例

MM_HIENGLISH:0.001inch-->1像素;x正轴向右,y正轴向上

MM_HIMETRIC:0.01毫米-->1像素;x正轴向右,y正轴向上

MM_ISOTROPIC:x和y方向的缩放比例相同

MM_LOENGLISH:0.01inch;x正轴向右,y正轴向上

MM_LOMETRIC:0.1毫米-->1像素;x正轴向右,y正轴向上

MM_TEXT:1:1拷贝;x正轴向右,y正轴向下

MM_TWIPS:1/1440inch-->1像素;x正轴向右,y正轴向上

设置映射模式SetMapMode,确定怎么画到设备空间上
SetWindowExtEx int nXExtent, int nYExtent; 设置绘制区域大小
SetWindowOrgEx int X, int Y; 设置绘制的窗口原点

设备空间常用参数:

函数 主要参数 作用
SetViewportExtEx int nXExtent, int nYExtent; 设置绘制区域大小
SetViewportOrgEx int X, int Y; 设置显示的视口原点

 


3. Examples

  • 修改窗口原点
    • SetWindowOrgEx(dc.m_hDC, 200, 200, NULL);
      TextOut(dc.m_hDC, 200, 200, "123456", 6);

      先在窗口中绘制, 最终转换到视口中显示。

       理解Windows坐标系概念及其转换_第2张图片

       

  • 修改视口原点
    • // viewpoint 
      SetViewportOrgEx(dc.m_hDC, 100, 100, NULL);
      TextOut(dc.m_hDC, 200, 200, "123456", 6);

      在窗口中的坐标点(200,200)绘制文字,而视口中原点坐标变为(100,100),经一定量的偏移,最终绘制在界面坐标(300,300) 处。

      理解Windows坐标系概念及其转换_第3张图片

  • 窗口和视口同时配置
    • // hybird
      SetWindowOrgEx(dc.m_hDC, 200, 200, NULL);
      SetViewportOrgEx(dc.m_hDC, 100, 100, NULL);
      TextOut(dc.m_hDC, 200, 200, "123456", 6);

      绘制在坐标(100,100)的位置。这里为什么是这样呢?首先在窗口中绘制图形,之后以(200,200)为起点位置,将窗口中的内容复制到视口以(100,100)为起点的位置。

    • 这里,假设本文的绘制位置更改为(250,300),在窗口和视口中绘制的位置又是多少呢?——窗口为(250,300),视口为(150,200),视口中的计算方法:150=(250-200)+100; 200=(300-200)+100;(这里SetMapMode为默认参数MM_TEXT,未配置缩放系数或修改坐标轴方向)。

    • 理解Windows坐标系概念及其转换_第4张图片
  • 配置缩放系数为0.5,即从窗口中2个单位的位置,在视口中表示为一个1单位。
    • CRect rect;
      GetClientRect(&rect);
      
      SetMapMode(dc.m_hDC, MM_ANISOTROPIC);
      SetWindowExtEx(dc.m_hDC, rect.Width()*2, rect.Height()*2, NULL);
      SetViewportExtEx(dc.m_hDC, rect.Width(), rect.Height(), NULL);
      TextOut(dc.m_hDC, 200, 200, "123456", 6);
      可以看到,绘制的位置还是(100,100)。因为现在窗口中的(200,200)位置绘制了文本,但转换到视口(即显示设备)时,位置信息缩小了1倍。
    • 从窗口的页面空间转换到设备空间的公式,原文请见此:
    • Dx = ((Lx - WOx) * VEx / WEx) + VOx
      
      其中:
      Dx     x value in device units 
      Lx     x value in logical units (also known as page space units) 
      WOx     window x origin 
      VOx     viewport x origin 
      WEx     window x-extent 
      VEx     viewport x-extent

       

    • 理解Windows坐标系概念及其转换_第5张图片
      •  
  • 使用世界空间进行转换
    • // world transform
      int nGraphicsMode = SetGraphicsMode(dc.GetSafeHdc(), GM_ADVANCED);
      
      XFORM xForm;
      xForm.eM11 = (FLOAT) 0.5; 
      xForm.eM12 = (FLOAT) 0.0; 
      xForm.eM21 = (FLOAT) 0.0; 
      xForm.eM22 = (FLOAT) 0.5; 
      xForm.eDx  = (FLOAT) 0.0; 
      xForm.eDy  = (FLOAT) 0.0; 		
      SetWorldTransform(dc.GetSafeHdc(), &xForm);
      //Rectangle(dc.GetSafeHdc(), 0, 0, 200, 300);
      TextOut(dc.m_hDC, 200, 200, "123456", 6);

       另一种把图绘制在(100,100)处的方法就是使用世界空间,因为说来说去,图形最开始画的地方就在这里,而且在世界空间中能进行多种的图形操作。这里用到了SetWorldTransform、XFORM和SetGraphicsMode,这是必须使用的函数或者参数,具体使用方法各请看MSDN,那里有非常详细的介绍。

      理解Windows坐标系概念及其转换_第6张图片

  • 综合使用WindowOrg和ViewPortOrg
    • // using windowpoint & viewpoint
      SetMapMode(dc.m_hDC, MM_TEXT);
      SetViewportOrgEx(dc.GetSafeHdc(), 0, rect.bottom/10, NULL);
      SetWindowOrgEx(dc.GetSafeHdc(), -100, 0, NULL);
      dc.Rectangle(0, 0, 200, 300);
      TextOut(dc.m_hDC, 200, 200, "123456", 6);

       主要明白绘图现在窗口上绘,再是在视口上显示,这个过程即可,转换过程中可能会有一定比例的缩放。

       理解Windows坐标系概念及其转换_第7张图片

       


4. 引用 

 

1. Using SetWorldTransform() to Rotate Basic Shapes by Any Angle

2. MSDN(官方文档,最最权威!)

3. 其他文档

你可能感兴趣的:(代码精进之路)