Qt坐标变换详解

文章目录

Qt坐标变换详解

在图形编程中,坐标变换是非常重要的概念,它可以帮助我们方便地进行平移、旋转、缩放和剪切等操作。在Qt中,QPainter 提供了丰富的坐标变换功能,使得复杂的图形操作变得简单。本文将通过具体的示例代码,详细讲解Qt中常用的坐标变换方法。

初始化 QPainter

在开始绘制之前,我们需要创建一个 QPainter 对象并启用抗锯齿功能,以提高绘图的质量。以下代码展示了如何初始化 QPainter

cpp 复制代码
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::TextAntialiasing);

通过设置抗锯齿和文本抗锯齿,可以使绘制的图形和文字更加平滑,避免锯齿现象。Antialiasing 主要用于平滑图形边缘,而 TextAntialiasing 则用于平滑文本的边缘。

设置画笔和字体

在绘制图形和文字之前,需要设置画笔和字体的属性。以下代码展示了如何设置画笔和字体:

cpp 复制代码
QPen pen;
pen.setWidth(4);
pen.setColor(Qt::red);
painter.setPen(pen);

QFont font;
font.setPointSize(20);
painter.setFont(font);

这里我们创建了一个 QPen 对象,并将其宽度设置为4,颜色设置为红色。然后将该画笔应用于 QPainter。同时,我们创建了一个 QFont 对象,并将其大小设置为20,然后将该字体应用于 QPainter。这使得接下来绘制的图形使用红色线条,并且绘制的文本使用大小为20的字体。

坐标平移

坐标平移是将绘图的原点从一个位置移动到另一个位置。以下代码展示了如何使用 translate() 方法进行坐标平移:

cpp 复制代码
QRect imageRect(100, 100, 400, 300);
QImage image(":/JINGMAO.jpg");
painter.drawImage(imageRect, image);

// 坐标平移
painter.translate(400, 300);
painter.drawImage(imageRect, image);

在这段代码中,第一次绘制图片时使用了原始坐标 (100, 100)(500, 400) 的矩形区域。然后,使用 painter.translate(400, 300) 将坐标系平移到 (400, 300) 位置,再次绘制相同的图片。通过这种方式,图片会被绘制到新的位置 (500, 400)(900, 600)。坐标平移使我们可以方便地改变绘图的位置,而不需要更改具体的绘制代码。

坐标旋转

坐标旋转是将整个坐标系绕原点旋转一定的角度。以下代码展示了如何使用 rotate() 方法进行坐标旋转:

cpp 复制代码
painter.resetTransform(); // 重置变换
painter.drawImage(imageRect, image);

// 坐标旋转
painter.rotate(30); // 旋转30度
painter.drawImage(imageRect, image);

在这段代码中,首先绘制了原始图片。然后,使用 painter.rotate(30) 将坐标系顺时针旋转30度,再次绘制相同的图片。通过这种方式,图片会以原点为中心进行旋转。需要注意的是,旋转是以当前坐标系的原点为中心进行的,原点的位置也会随平移操作而改变。旋转操作通常用于需要绘制特定角度的图形或在特定角度绘制文本的场景。

坐标扭转

坐标扭转(剪切)是将坐标系中的网格线进行倾斜。以下代码展示了如何使用 shear() 方法进行坐标扭转:

cpp 复制代码
painter.resetTransform(); // 重置变换
painter.drawImage(imageRect, image);

// 坐标扭转
painter.shear(0.1, 0.1); // x方向和y方向各剪切0.1
painter.drawImage(imageRect, image);

在这段代码中,首先绘制了原始图片。然后,使用 painter.shear(0.1, 0.1) 将坐标系的x方向和y方向各剪切0.1,再次绘制相同的图片。通过这种方式,图片会发生倾斜。剪切变换可以用来创建逼真的透视效果或斜体文本效果。剪切操作改变了坐标系的形状,使得水平和垂直方向上的网格线不再平行,从而产生倾斜效果。

坐标缩放

坐标缩放是将坐标系按比例放大或缩小。以下代码展示了如何使用 scale() 方法进行坐标缩放:

cpp 复制代码
painter.resetTransform(); // 重置变换
painter.drawImage(imageRect, image);

// 坐标缩放
painter.scale(0.5, 0.5); // 缩小到50%
painter.drawImage(imageRect, image);

在这段代码中,首先绘制了原始图片。然后,使用 painter.scale(0.5, 0.5) 将坐标系缩小到原来的50%,再次绘制相同的图片。通过这种方式,图片会按比例缩小。缩放操作可以用来改变图形或文本的大小,而无需修改其定义。需要注意的是,缩放会同时影响水平和垂直方向,因此可以实现各种比例的放大或缩小效果。

保存和恢复坐标状态

在进行多次复杂的变换时,保存和恢复坐标状态非常有用。以下代码展示了如何使用 save()restore() 方法进行操作:

cpp 复制代码
QRect imageRect(0, 0, 400, 300);
QImage image(":/JINGMAO.jpg");
painter.drawImage(imageRect, image);

// 保存坐标状态
painter.save();

// 进行变换
painter.shear(0.1, 0.1);
painter.drawImage(imageRect, image);

// 恢复坐标状态
painter.restore();
painter.drawImage(imageRect, image);

在这段代码中,首先绘制了原始图片。然后,使用 painter.save() 保存当前的坐标状态。接下来,进行剪切变换并绘制图片。最后,使用 painter.restore() 恢复到保存的坐标状态,再次绘制相同的图片。通过这种方式,可以方便地在复杂变换之间切换,而无需手动恢复每一步变换。保存和恢复坐标状态特别适用于需要在同一绘制操作中应用多种变换的情况。

复位所有的坐标变换

在某些情况下,需要复位所有的坐标变换,使坐标系回到初始状态。以下代码展示了如何使用 resetTransform() 方法复位坐标变换:

cpp 复制代码
painter.resetTransform(); // 复位所有的坐标变换
painter.drawImage(imageRect, image);

在这段代码中,使用 painter.resetTransform() 方法复位所有的坐标变换。通过这种方式,坐标系将回到初始状态,之后的绘制操作将不受之前变换的影响。resetTransform() 方法清除了所有的平移、旋转、缩放和剪切变换,使得坐标系恢复到默认状态。这在需要清除所有变换并重新开始绘制时非常有用。

综合示例:绘制五角星

最后,我们将以上的知识点结合起来,绘制一个五角星。以下代码展示了如何计算五角星的顶点并进行绘制:

cpp 复制代码
qreal r = 200;
qreal PI = 3.14159;
qreal unit = 72 * PI / 180;
QPoint points[5] = {
    QPoint(r, 0),
    QPoint(r * cos(unit), -r * sin(unit)),
    QPoint(r * cos(2 * unit), -r * sin(2 * unit)),
    QPoint(r * cos(3 * unit), -r * sin(3 * unit)),
    QPoint(r * cos(4 * unit), -r * sin(4 * unit))
};
QPainterPath starPath;
starPath.moveTo(points[0]);
starPath.lineTo(points[2]);
starPath.lineTo(points[4]);
starPath.lineTo(points[1]);
starPath.lineTo(points[3]);
starPath.closeSubpath();

starPath.addText(points[0], font, "0");
starPath.addText(points[1], font, "1");
starPath.addText(points[2], font, "2");
starPath.addText(points[3], font, "3");
starPath.addText(points[4], font, "4");

painter.save();
painter.translate

(r * 1.2, r * 1.1);
painter.rotate(-18);
painter.drawPath(starPath);
painter.restore();

解释

  1. 计算五角星顶点:使用三角函数计算五角星的五个顶点坐标。通过将极坐标转换为直角坐标,计算出每个顶点的位置。
  2. 创建路径 :使用 QPainterPath 对象定义五角星的路径,并连接各个顶点。moveTo 方法将路径起点移动到第一个顶点,然后使用 lineTo 方法依次连接其他顶点。
  3. 添加文本标签 :在每个顶点位置添加相应的文本标签。使用 addText 方法在路径上添加文本,标记每个顶点的位置。
  4. 保存状态并变换坐标系 :使用 painter.save() 保存当前坐标状态,使用 painter.translate()painter.rotate() 进行平移和旋转变换。
  5. 绘制五角星并恢复状态 :使用 painter.drawPath() 绘制五角星,然后使用 painter.restore() 恢复到保存的坐标状态。

通过以上代码,我们成功绘制了一个红色的五角星,每个顶点上标有相应的数字。利用Qt提供的坐标变换功能,使得绘制复杂图形变得更加简单和直观。

总结

Qt提供了丰富的坐标变换功能,包括平移、旋转、剪切和缩放等,使得图形编程更加灵活和强大。通过 save()restore() 方法,可以方便地管理和切换不同的变换状态。掌握这些坐标变换方法,将极大地提升我们在Qt中进行图形绘制的能力。

相关推荐
wainyz3 分钟前
Java NIO操作
java·开发语言·nio
喵叔哟11 分钟前
重构代码之用委托替代继承
开发语言·重构
lzb_kkk17 分钟前
【JavaEE】JUC的常见类
java·开发语言·java-ee
SEEONTIME17 分钟前
python-24-一篇文章彻底掌握Python HTTP库Requests
开发语言·python·http·http库requests
Zfox_18 分钟前
【Linux】进程信号全攻略(二)
linux·运维·c语言·c++
起名字真南36 分钟前
【OJ题解】C++实现字符串大数相乘:无BigInteger库的字符串乘积解决方案
开发语言·c++·leetcode
少年负剑去36 分钟前
第十五届蓝桥杯C/C++B组题解——数字接龙
c语言·c++·蓝桥杯
cleveryuoyuo37 分钟前
AVL树的旋转
c++
tyler_download1 小时前
golang 实现比特币内核:实现基于椭圆曲线的数字签名和验证
开发语言·数据库·golang
小小小~1 小时前
qt5将程序打包并使用
开发语言·qt