(转)MFC中SetWorldTransform函数中XFORM结构体的使用

本文详细介绍了在图形编程中如何使用SetGraphicsMode函数设置不同的图形模式,以及如何利用SetWorldTransform函数进行坐标变换,包括缩放、旋转和平移等操作。

SetGraphicsMode

  函数功能:该函数为指定的设备环境设置图形模式。
  函数原型:int SetGraphicsMode(HDC hdc, int iMode);
  参数:
  hdc:指向设备环境的句柄。
  iMode:指定图形模式,该参数可为下列值之一:
  GM_COMPAIBLE:设置与16位Windows相兼容的图形模式,这是缺省的模式。如果指定此值,应用程序只能通过调用设置窗口视窗范围和原点的函数来改变全局到设备的转换,但不是通过利用SetWorldTransform或ModifyWorldTransform,调用这些函数将失败,设置窗口和视窗范围和原点的函数的例子为SetViewportExtEx和SetwindowExtEx函数。
  GM_ADVANCED:Windows NT和Windows 98:设置高级图形模式,允许全局转换。如果应用程序设置或改变指定设备环境的全局转换,必须规定该值在这种模式中,所有的图形,包括文本输出,全部转换为设备环境规定的全局到设备的转换。
  Windows 95:不支持GM_ADVANCED,当操作增强的元文件时,Windows 95试图使Windows95中的增强的元文件看起来与在Windows NT上操作一样。为完成此功能,Windows 95当操作指定的增强元文件记录时,可以模仿GM_ADVANCED模式。
  返回值:如果调用成功,返回值为老图形模式,调用失败,返回值为零。若想获得更多错误信息,请调用GetLastError函数。
  备注:根据图形模式,有3种不同的表格输出:
  TextOutput:在GM_COMPATIBLE模式中,TrueType(或矢量字体)文本输出时的操作方式就该DC中全局到设备转换而言很象光栅字体文本输出。TrueType文本总是按从左到右和从上到下的顺序写,即使图形的剩余部分在X或Y轴被翻动,只有TrueType(或矢量字体)文本的高被定为合适的高度,在GM_COMPATIBLE模式中写非水平文本的唯一办法,是为该设备环境中选举的字体指定非零表格的大小和方向。
  在GM_ADVANCED模式中TrueType(或矢量字体)文本输出完全转换为设备环境中域到设备的转换,光栅字体只有很受局限的转换能力(通过某些整型系数来伸展)。图形设备界面(GDI)试图创造出最好的输出。
  Rectangle Exclusion:如果设置缺省的GM_COMPATIBLE图形模式,当画长方形时,系统不包括底部和最右的边。GM_ADVANCED图形模式应用于画底边和右边包括在内的长方形。
  Arc Drawing:如果设置缺省的GM_COMPATIBLE图形为模式,GDI用设备空间中当前弧的方向来画弧,根据此协议,弧不管页面到设备的转换,此转换要求沿着X或Y轴的翻动。如果设置了GM_ADVANCED图形模式,GDI总是在逻辑空间逆时针方向画弧。这就是说在GM_COMPATIBLE图形模式中,弧控制点和弧本身,都全遵从设备环境的全局到设备的转换。

SetWorldTransform

  函数功能:该函数为指定的设备环境设置全局空间和页面空间之间的二维的线性转变,此转换可用于比例缩放、旋转、剪切或翻译图形的输出。
  函数原型:BOOL SetWorldTransform(HDC hdc, CONST XFORM *lpXform);
  hdc:指向设备环境的句柄。
  lpxform:指向XFORM结构的指针,此结构含有转换数据。
  返回值:如果函数调用成功,返回值为非零值,否则为零。
  Windows NT:若想获得更多错误信息,请调用GetLastError函数。
  备注:对任何全局空间中的坐标点(X、Y),页面空间中的转换坐标点(X、Y)以下式来决定。
  X'=X*eM11+y*eM21+eDx, Y'+X*eM12+y*eM22+eDy
  转换矩阵为下列矩阵:
  |eM11 eM120|
  |eM21 eM220|
  |eDx eDy | 映射方式(由当前窗口和视口原点定义的)用于定义单位和比例。全局转换常用于以不依靠设备的方式来缩放或旋转逻辑图像。缺省全局转换是偏移为零的等同矩阵。除非先调用SetGraphicsMode函数将给定设备环境的图形模式设置为GM_ADVANCED,否则SetworldTranform函数调用将失败,同样,也不可能重新把设备环境的图形方式设置成缺省的GM_COMPATIBLE方式,除非全局转已经通过调用SetWorldtransform或ModifyworldTransform函数首先重新设置缺省的等同转换。
使用XFORM来控制DC时,需要先设置绘图模式SetGraphicsMode为GM_ADVANCED,再用SetWorldTransform。
否则SetWorldTransform函数会失败
映射后的坐标与映射前的坐标关系为
x' = x * eM11 + y * eM21 + eDx, 
y' = x * eM12 + y * eM22 + eDy, 

若要设置缩放比例,则只需设置eM11和eM22为相应的比例,其余设置为0即可;
若要设置一个逆时针旋转了@度的坐标系映射,则eM11为cos(@), eM12为-sin(@), eM21 为 sin(@), eM22为cos(@)
若要使坐标系平移(a,b),则eDx=a, eDy = b。

若要设置一个缩放比例为0.5,逆时针旋转30度,平移(20,50)的坐标系,则eM11 = 0.5 * cos(30) = 0.4330, eM12 = 0.5 * [- sin( 30 )] = -0.25, eM21 = 0.5 * sin ( 30 ) = 0.25, eM22 = 0.5 * cos( 30 ) = 0.4330, eDx = 20, eDy = 50

注:以上关系只在不改变和原屏幕坐标一样的XY轴关系(X轴正方向为Y轴正方向逆时针旋转90度)的情况下成立。

<think>我们正在讨论MFC(Microsoft Foundation Classes)中的图形变换功能。用户询问了RotateTransform函数SetWorldTransform函数使用方法及区别。 首先,需要明确这两个函数所在的类: - RotateTransform:这是GDI+中的函数,属于Graphics类的方法。在MFC中,当我们使用GDI+时,可以通过CDC::GetDC()获取HDC,然后创建Graphics对象。 - SetWorldTransform:这是GDI(非GDI+)中的函数,属于CDC类的方法。它用于设置设备上下文的世界变换。 由于这两个函数来自不同的图形子系统(GDI+和GDI),因此它们的使用场景和方式有所不同。 ### 1. SetWorldTransform (GDI函数) SetWorldTransform是CDC类的成员函数,用于设置设备上下文(DC)的世界变换矩阵。它属于传统的GDI(Graphics Device Interface)功能,需要配合使用XFORM结构和MODIFY_WORLD_TRANSFORM模式。 **使用方法**: ```cpp // 假设pDC是指向CDC的指针 XFORM xform; // 设置旋角度(弧度) float angle = 30.0f * 3.14159f / 180.0f; xform.eM11 = cos(angle); xform.eM12 = sin(angle); xform.eM21 = -sin(angle); xform.eM22 = cos(angle); xform.eDx = 0; xform.eDy = 0; // 设置世界变换模式为累加(也可以设置为覆盖) pDC->SetGraphicsMode(GM_ADVANCED); pDC->SetWorldTransform(&xform); // 然后进行绘图操作,例如画一个矩形 pDC->Rectangle(50, 50, 150, 100); // 恢复默认变换 pDC->ModifyWorldTransform(NULL, MWT_IDENTITY); ``` **注意**: - 使用SetWorldTransform前必须将图形模式设置为GM_ADVANCED(使用CDC::SetGraphicsMode)。 - 默认情况下,GDI的世界变换是关闭的(GM_COMPATIBLE),所以需要先设置模式。 ### 2. RotateTransform (GDI+函数) RotateTransform是GDI+中Graphics类的方法。GDI+是GDI的增强版,提供了更多高级特性。在MFC中,我们可以使用GDI+,但需要包含头文件和链接库。 **使用方法**: ```cpp #include <gdiplus.h> using namespace Gdiplus; // 在OnDraw或类似函数中 Graphics graphics(pDC->GetSafeHdc()); graphics.TranslateTransform(100.0f, 50.0f); // 改变原点 graphics.RotateTransform(30.0f); // 旋30度(顺时针) // 使用GDI+绘制一个矩形 Pen pen(Color(255, 0, 0, 255)); // 蓝色笔 graphics.DrawRectangle(&pen, 0, 0, 100, 50); // 以变换后的原点为基准 ``` **注意**: - RotateTransform旋的是整个坐标系,旋的中心是当前坐标系的原点(默认是窗口左上角,但可以通过TranslateTransform改变原点)。 - 在GDI+中,变换是累积的,也可以使用ResetTransform重置变换。 ### 3. 两个函数的区别 | 特性 | SetWorldTransform (GDI) | RotateTransform (GDI+) | |------|--------------------------|------------------------| | **所属库** | GDI(传统) | GDI+(较新) | | **使用前提** | 需要设置图形模式为GM_ADVANCED | 直接使用Graphics对象 | | **变换设置** | 通过XFORM结构设置完整的仿射变换矩阵 | 通过独立的方法(如RotateTransform, TranslateTransform)设置变换,也可以使用SetTransform设置整个变换矩阵 | | **变换组合** | 通过ModifyWorldTransform组合变换(提供叠加模式) | Graphics对象维护一个变换矩阵,每次调用变换方法都会将新变换乘到当前矩阵上(除非重置) | | **易用性** | 矩阵操作,需要手动计算旋矩阵 | 更高级,直接提供旋、平移、缩放等方法 | | **功能范围** | 仅支持仿射变换(旋、平移、缩放、错切) | 同样支持仿射变换,还提供更多功能如图像处理、渐变画笔等 | | **性能** | 较低层级,性能较好 | 较高层级,功能丰富但可能稍慢(取决于场景) | ### 4. 如何选择 - 如果项目已经使用GDI并且对性能要求较高,且只需要基本的变换,可以考虑使用SetWorldTransform。 - 如果需要更丰富的图形功能(如渐变、路径、反锯齿等),或者新的项目,建议使用GDI+的RotateTransform等函数。 ### 引用说明 在MFC中,GDI+的使用需要初始化,通常在应用程序类的InitInstance中初始化GDI+,并在ExitInstance中关闭。此外,GDI+需要包含头文件`<gdiplus.h>`和链接库`gdiplus.lib`[^1]。 §§相关问题§§ 1. 使用SetWorldTransform时如何组合多个变换(旋、平移)? 2. 在GDI+中如何重置当前的变换矩阵? 3. GDI和GDI+的主要区别有哪些? 4. 在MFC使用GDI+的基本步骤是什么? [^1]: MSDN文档:SetWorldTransform函数 (Windows) https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-setworldtransform [^2]: MSDN文档:GDI+ Graphics::RotateTransform方法 https://docs.microsoft.com/en-us/windows/win32/api/gdiplusgraphics/nf-gdiplusgraphics-graphics-rotatetransform </think>### MFC中`RotateTransform`与`SetWorldTransform`的使用及区别 在MFC图形编程中,`RotateTransform`(GDI+)和`SetWorldTransform`(GDI)是两种实现坐标系变换的方法,二者在实现机制和使用场景上有显著差异。 --- #### 1. **RotateTransform(GDI+函数)** **所属库**:GDI+(`Graphics`类) **功能**:对坐标系进行旋变换(以左上角为原点,顺时针为正方向) **使用流程**: ```cpp #include <gdiplus.h> using namespace Gdiplus; // 初始化GDI+ GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); // 在绘图函数中 void CMyView::OnDraw(CDC* pDC) { Graphics graphics(pDC->GetSafeHdc()); Pen pen(Color(255, 0, 0), 2); // 红色画笔 // 坐标系旋30度 graphics.RotateTransform(30.0f); graphics.DrawRectangle(&pen, 50, 50, 100, 50); // 绘制旋后的矩形 } ``` **特点**: - 直接操作`Graphics`对象,无需矩阵计算 - 变换叠加:连续调用会累计变换效果 - 需配合`TranslateTransform`调整旋中心(默认绕左上角(0,0)) --- #### 2. **SetWorldTransform(GDI函数)** **所属库**:GDI(`CDC`类) **功能**:设置设备上下文的世界变换矩阵(支持旋、平移、缩放) **使用流程**: ```cpp void CMyView::OnDraw(CDC* pDC) { // 启用高级图形模式 pDC->SetGraphicsMode(GM_ADVANCED); XFORM xform; float angle = 45.0f * 3.14159f / 180.0f; // 弧度 // 构建旋矩阵(绕原点旋45度) xform.eM11 = cos(angle); xform.eM12 = sin(angle); xform.eM21 = -sin(angle); xform.eM22 = cos(angle); xform.eDx = 0; // 平移X xform.eDy = 0; // 平移Y // 应用变换 pDC->SetWorldTransform(&xform); pDC->Rectangle(50, 50, 150, 100); // 绘制旋后的矩形 // 恢复默认矩阵 pDC->ModifyWorldTransform(NULL, MWT_IDENTITY); } ``` **特点**: - 需手动构造`XFORM`矩阵(需数学计算) - 必须调用`SetGraphicsMode(GM_ADVANCED)`启用高级模式 - 直接替换当前变换矩阵(非叠加) --- ### 核心区别总结 | **特性** | **RotateTransform (GDI+)** | **SetWorldTransform (GDI)** | |------------------------|----------------------------------|----------------------------------| | **所属技术** | GDI+(需`gdiplus.lib`) | 原生GDI | | **变换方式** | 增量式叠加变换 | 直接设置完整变换矩阵 | | **易用性** | 高(封装旋/平移/缩放接口) | 低(需手动计算矩阵) | | **旋中心控制** | 需组合`TranslateTransform` | 通过矩阵元素自定义 | | **依赖环境** | 需初始化GDI+ | 仅需GDI支持 | | **性能** | 较高层级API,略慢 | 接近底层,性能更优 | > **关键场景选择**: > - 简单旋/平移 → **`RotateTransform`**(代码简洁) > - 复杂仿射变换或性能敏感场景 → **`SetWorldTransform`** > - 新项目推荐GDI+(功能更丰富,支持抗锯齿等)[^1][^2] ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值