您的位置:首页 > 其它

GDI绘图坐标系映射的理解

2013-01-28 15:04 162 查看
GDI绘图坐标系映射的理解



一. 坐标单位

        Windows的GDI/GDI+的绘图函数绘制图形时使用的是逻辑坐标系, 逻辑坐标系的单位是逻辑单位. 例如: pDC->MoveTo(100, 300); 这里的100和300的单位就是逻辑单位, 我们可以这么说 100逻辑单位, 300逻辑单位, 我觉得"逻辑单位"这4个字又长又臭, 很绕口, 所以我喜欢这么叫 100 猪屎, 300猪屎. 那么pDC->MoveTo(100, 300);的意思就是pDC的在逻辑坐标的当前点移动到(100猪屎, 300猪屎)这个点.

       设备坐标和设备单位: 例如屏幕或打印机的单位像素. 

通常我们是使用GDI函数绘图, 然后在屏幕上显示. 但是逻辑坐标和设备坐标的单位不同, 逻辑坐标的单位是"猪屎", 而设备的坐标是"像素". 所以需要转换, 怎么转换? 例如2猪屎相当于屏幕的1像素, 那么这两个坐标系的转换当量是 2 猪屎/像素.

那么pDC->MoveTo(100, 200); 如果是在屏幕是绘图, 相当于移动到屏幕 (50像素, 100像素) 这个点的位置. 

50像素 = 100猪屎 / 当量 = 100猪屎 / 2 猪屎/像素 = 50像素

100像素 = 200猪屎 / 当量 = 200猪屎 / 2 猪屎/像素 = 100像素

如下图: Windows绘图过程



那么怎么设置这个当量值?

通过CDC的 SetWindowExt和SetViewportExt (看MSDN)

例1. 某屏幕的单位是像素: 10猪屎等于该屏幕的1像素, 那么当量就是10猪屎/1像素 = 10猪屎/像素

可以这么设置pDC->SetWindowExt(10, 10); pDC->SetViewportExt(1, 1);

例2. 某屏幕的单位是像素: 10猪屎等于该屏幕的2像素, 那么当量就是10猪屎/2像素 = 5猪屎/像素

可以这么设置pDC->SetWindowExt(10, 10); pDC->SetViewportExt(2, 2);

为什么要使用两个函数来设置? pDC->SetXXXXXExt(5), 直接把5传给pDC不行吗? 看例3

例3. 某屏幕的单位是像素: 10猪屎等于该屏幕的3像素, 那么当量就是10猪屎/3像素 = 10/3猪屎/像素 = 3.3333...猪屎/像素. 

当量是一个浮点数, 我个人了解是为了不影响绘图的速度, 因为绘图时, 两个坐标系频繁的映射也是需要时间的, 使用浮点数会加长这个时间.

例4. 某屏幕的单位是像素: 10猪屎等于该屏幕的3像素, 而且Y轴向下是负方向, 向上才是正方向. 

默认方式下, 逻辑坐标系X轴是向右为正方向, Y轴是向下为正方向. 此时可以这么设置

X轴的当量是 10猪屎/3像素 = 10/3猪屎/像素

Y轴的当量是 - 10猪屎/3像素 = -10/3猪屎/像素(因为Y轴与逻辑坐标系的方向是相反的.)

可以这么设置pDC->SetWindowExt(10, -10); pDC->SetViewportExt(3, 3);

或者pDC->SetWindowExt(10, 10); pDC->SetViewportExt(3, -3);

二. 坐标系

        Windows的GDI/GDI+的逻辑坐标系, 默认是以窗口区域的左上角为原点(0猪屎, 0猪屎)这个点. X轴是向右为正方向, Y轴是向下为正方向. 通常屏幕也是这样, 所以我们一般在屏幕上绘图不需要设置映射关系. Windows提供的映射关系有:

映射方式                       逻辑单位                    X轴增加            Y轴增加
          当量

1. MM_TEXT                 像素点                       右                                   下
                                1 猪屎/猪屎

2. MM_LOMETRIC      0.1mm                      右 
                                 上                                 10猪屎/mm

3. MM_HIMETRIC        0.01mm                   右            
                       上                                100猪屎/mm

4. MM_LOENGLISH    0.254mm                 右                                  上
                                 (1000/254)猪屎/mm

5. MM_HIENGLISH     0.0254mm              右                                    上
                                (10000/254)猪屎/mm

6. MM_TWIPS              0.0176mm               右                                   上
                                 (10000/176)猪屎/mm

7. MM_ISOTROPIC    任意(x=y)                  可选     
                         可选                              可设

8. MM_ANISOTROPIC 任意(x!=y)              可选                               可选
                               可设

        个人理解的映射模式: 默认情况下映射模式是MM_TEXT. 而对于模式2, 3, 4, 5, 6, 7, 8可以说是特殊的MM_TEXT模式. 都可以通过SetWindowExt和SetViewportExt设置实现. 只是某些映射关系使用比较频繁, 所以GDI直接作为一种模式使用例如这里的模式2, 3, 4, 5, 6.

映射模式使用SetMapMode来设置.

MM_LOMETRIC相当于:

pDC->SetMapMode(MM_ANISOTROPIC);

pDC->SetWindowExt(10, 10); 

pDC->SetViewportExt(1, -1);

MM_HIMETRIC相当于:

pDC->SetMapMode(MM_ANISOTROPIC);

pDC->SetWindowExt(100, 100); 

pDC->SetViewportExt(1, -1);

MM_LOENGLISH相当于:

pDC->SetMapMode(MM_ANISOTROPIC);

pDC->SetWindowExt(1000, 1000); 

pDC->SetViewportExt(254, -254);

如此类推....

所以使用模式MM_ANISOTROPIC是最强大的, 可以任意设置当量和方向.

三. 坐标原点

        其实所谓的原点都是相对的, 使用SetWindowOrg和SetViewportOrg设置, 我觉得这样理解更简单: 逻辑坐标系默认原点是(0猪屎, 0猪屎), 这是固定的, SetWindowOrg是用来设置偏移量的(或者叫平移量.)(XOffset和YOffset).

        那么pDC->MoveTo(10, 30); 绘图过程可以这么理解: 在MoveTo内部, 总是会执行10 - XOffset和10 - YOffset.

SetViewportOrg也是一样的理解.

四. 坐标系之间的映射.

现在理解坐标系的映射就非常简单了. 你只需要知道如下的内容.

1. 逻辑坐标与设备坐标的当量(EqueX和EqueY).

2. 逻辑坐标的偏移(LogicXOffset, LogicYOffst)和设备坐标的偏移(DeviceXOffset, DeviceYOffst).

例如现在有某一种狗屎设备, 单位是"狗屎", 12猪屎等于该设备的1狗屎. 而且该设备Y轴向上位正方向. 那么在GDI坐标系中点(5猪屎, 6猪屎) 在狗屎设备中的坐标系是哪一点?

DeviceX - DeviceXOffset = (LogicX - LogicXOffset) / EqueX;

DeviceY - DeviceYOffset = (LogicY - LogicYOffset) / EqueY;

其中

EqueX = 12猪屎/1狗屎 = 12猪屎/狗屎

EqueY = - 12猪屎/1狗屎 = -12猪屎/狗屎

这条公式GDI会帮我们自己执行的, 我们只需要调用对应的函数, 把参数设置好.

pDC->SetMapMode(MM_ANISOTROPIC);

pDC->SetWindowExt(12, 12);

pDC->SetViewportExt(1, -1);

pDC->SetWindowOrg(LogicXOffset, LogicYOffset);

pDC->SetViewportOrg(DeviceXOffset, DeviceYOffset);

五. 小结

其实就是坐标缩放和平移. 还没有旋转呢.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: