Qt坐标系统之坐标变换矩阵(QTransform类)

Qt坐标系统之坐标变换矩阵(QTransform类)

本文为原创文章,转载请注明出处,或注明转载自“黄邦勇帅(原名:黄勇)

本文出自本人原创著作《Qt5.10 GUI完全参考手册》网盘地址:
https://pan.baidu.com/s/1iqagt4SEC8PUYx6t3ku39Q
《C++语法详解》网盘地址:https://pan.baidu.com/s/1dIxLMN5b91zpJN2sZv1MNg

若对C++语法不熟悉,建议参阅本人所著《C++语法详解》一书,电子工业出版社出版,该书语法示例短小精悍,对查阅C++知识点相当方便,并对语法原理进行了透彻、深入详细的讲解,可确保读者彻底弄懂C++的原理,彻底解惑C++,使其知其然更知其所以然。此书是一本全面了解C++不可多得的案头必备图书。

注:本小节需要一些数学知识和计算机图形学方面的知识
12.12.1 基本数学知识

1、齐次坐标

二维空间中的点可使用(x, y)表示,但在计算机图形学中使用齐次坐标表示点更为方便,齐次坐标把点表示为三元组,即在(x,y)基础上增加一维表示为(x, y, w),其中w是一个非零值
每个点有很多个不同的齐次坐标表示(只要其中一个是另一个的倍数即可),比如(1, 2, 5),(2,4, 10),(4, 8, 20);都表示同一个点,通常会使用w去除齐次坐标,从而一个点被表示为(x/w, y/w, 1),这样,每一个二维坐标点都可以使用三维的齐次坐标来表示,同理,三维坐标点(x,y,z);可使用四维的齐次坐标表示为(x, y, z, 1);比如(2,5,9)的齐次坐标为(2,5,9,1);
使用齐次坐标后,所有的坐标变换公式都可以使用如下矩阵相乘的形式来表示,
在这里插入图片描述

2、坐标变换公式
以下各式中,dx和dy表示平移距离,Sx和Sy表示缩放系数,θ表示绕原点逆时针旋转的角度,P1(x1, y1)为坐标变换后的点,P(x,y)为变换前的点。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3、坐标的复合变换
坐标的复合变换是指多个坐标变换序列的组合。
①、连续平移变换(其结果是平移相加)
把点P平移至点P1再平移至P2,则其平移公式的推导步骤为
在这里插入图片描述
由以上推导过程可见,对复合的坐标变换序列,只需计算其变换矩阵即可,以上规则同样适用于其他更复杂的复合变换,对于之后的变换,将只写出变换矩阵的计算。
下面为坐标平移复合变换后的计算过程。
在这里插入图片描述

在这里插入图片描述

5、总结
由以上讲解可知,只要给出变换矩阵,便可对其进行坐标变换,因此在计算机编程中,通常只需给出一个变换矩阵,然后给矩阵各元素赋予需要的值便可对其进行各种坐标变换。
6、其他
对于三维空间的坐标变换,其原理与二维类似,其坐标变换矩阵为
在这里插入图片描述

12.12.2 使用QPainter类中的基本变换函数进行坐标变换

默认情况下,QPainter是在自已所关联的绘制设备的坐标系(通常为像素)上运行的,绘制设备默认坐标系的原点位于左上角,X轴向右增长,Y轴向下增长。
2、QPainter类中的基本坐标变换函数如下
在这里插入图片描述
3、QPainter类中与绘制状态有关的函数如下
在这里插入图片描述

示例12.20:使用QPainter类中的基本坐标变换函数变换坐标

void paintEvent(QPaintEvent *e){
    QPainter pr(this);
    QBrush bs(QColor(1,111,1));    pr.setBrush(bs);    QRectF r(0,11,22,55);
pr.drawRect(r);
    pr.translate(50,10);		pr.drawRect(r);  	//变换1:平移(50,10)
pr.save();									//保存状态
//变换2:平移(50,50),缩放2倍(Y向),逆时针旋转60度
pr.translate(50,50);    pr.scale(1,2);    pr.rotate(-60);    pr.drawRect(r);
QTransform t=pr.transform();					//获取变换2的变换矩阵
qDebug()<<t;		//输出的矩阵为
					//(11=0.5,12=-1.73205,13=0,21=0.866025,22=1,23=0,31=100,32=60,33=1)
					//其中11表示第1行1列,12表示第一行2列
    pr.restore();     							//恢复状态,此时坐标系位于变换1处。
pr.translate(100,0);    pr.drawRect(r);   		//变换3:平移(100,0)
//变换4:平移(50,0),逆时针旋转60度,缩放2(Y向倍),注意与变换2的顺序。
    pr.translate(50,0);    pr.rotate(-60);    pr.scale(1,2);    pr.drawRect(r);
    pr.resetTransform();   						//重置为初始状态
    pr.translate(200,50);   pr.drawRect(r);}		//变换5:平移(200,50);

运行结果(见图12-55)
在这里插入图片描述

现以变换2计算其变换矩阵
注意:在使用QPainter类中的基本坐标变换函数进行复合坐标变换时,其变换矩阵应按相反的顺序进行计算。因此计算变换2的矩阵时应按旋转、缩放、平移的顺序进行计算,如下所示
在这里插入图片描述

12.12.3 使用变换矩阵(QTransform类)进行坐标变换

1、QPainter类中与QTransform类有关的函数如下
在这里插入图片描述

2、QTransform类
QTransform类主要用于创建一个3*3的变换矩阵,该矩阵用于坐标系的2D变换。该类取代了QMatrix类(此类已过时)。QTransform类通过操控变换矩阵来实现坐标变换。另外QTransform类还可对矩阵进行操作,比如可进行矩阵的加、乘等运算,还可对矩阵类型进行判断(比如是否是满秩矩阵等)。
QTransform类除了可通过操控其矩阵进行坐标变换外,还可使用QTransform类中内置的基本变换函数(比如QTransform::scale()、QTransform::scale()等)对坐标进行变换,这些函数的使用方法与QPainter类中的相应函数是相同的。简单的坐标变换完全可使用QPainter类中的基本坐标变换函数来完成,使用QTransform类可以把多个坐标变换组织在一起,然后在需要时使用。
QTransform类的变换矩阵如下
在这里插入图片描述

注:公式18~22其实就是使用的如下矩阵乘法计算出来的(读者可自行计算),在没有投影变换的情形下,w1直接取整数值1即可。因此在使用QTransform类进行坐标变换时,也可使用如下的矩阵形式计算变换后的坐标值。
在这里插入图片描述
把QTransform类的变换矩阵与坐标变换矩阵相对比,可得出如下规律m31和m32用于平移,m11和m22用于缩放,m21和m12用于错切(shear),m13和m23用于投影变换,m33是一个额外的投影因子,设置m11,m12,m21,m22可实现旋转变换。注:投影变换是一个比较复杂的变换,包括透视投影(图12-56为透视投影的一个简图)和平行投影,关于投影变换的内容请参阅《计算机图形学》课程。
在这里插入图片描述

12.12.4 QTransform类中的函数

1、构造函数
在这里插入图片描述
2、设置和获取变换矩阵的元素
在这里插入图片描述
3、QTransform内置的基本坐标变换函数
在这里插入图片描述
4、对变换矩阵的判断
在这里插入图片描述
5、构建变换矩阵
在这里插入图片描述
6、与线性代数有关的函数
在这里插入图片描述
7、使用变换矩阵转换图形坐标
以下函数用于转换坐标,比如QPoint p1=matrix.map(point);表示把点使用变换矩阵matrix进行转换,然后返回该点的副本。等效于p1= point*matrix;具体应用见示例12.22
在这里插入图片描述

8、下面为重新实现的操作符函数
在这里插入图片描述

示例12.21:使用QTransform类(变换矩阵)进行坐标变换(见图12-57)

注意:变换矩阵应按设计的相反顺序计算,比如若设计为平移T、旋转R、缩放S,则矩阵计算应为S∙R∙T
void paintEvent(QPaintEvent *e){
    QPainter pr(this);    QBrush bs(QColor(1,111,1));    pr.setBrush(bs);
QRectF r(0,55,22,55);
//变换1(平移、旋转)
    QTransform t(1,0,0,1,20,0); 	//x方向平移20
    t.rotate(-60);       		//使t再逆时针旋转60度。
    pr.setTransform(t);  		//设置变换矩阵为t
qDebug()<<t;				//输出内容为:QTransform(type=TxRotate,
// 11=0.5 12=-0.866025 13=0 21=0.866025 22=0.5 23=0 31=20 32=0 33=1)
pr.drawRect(r);    			//绘制矩形
//变换2(缩放)
    QTransform t1;    		t1.setMatrix(1,0,0,0,2,0,0,0,1);  //Y方向放大两倍。
    pr.setTransform(t1);    pr.drawRect(r);
//变换3(平移、旋转、缩放)
t1=t1*t;    				//使用QTransform重载的*运算符进行矩阵乘运算,此时t1的变换如下:
            				//首先向X方向平移20,再逆时针旋转60度,最后把Y轴方向放大两倍。
pr.setTransform(t1);  
qDebug()<<t1;      			//输出内容为:QTransform(type=TxShear,
                      			// 11=0.5 12=-0.866025 13=0 21=1.73205 22=1 23=0 31=20 32=0 33=1)
    pr.drawRect(r);
    t1.reset();        			//重置矩阵为单位矩阵。
    pr.setTransform(t1);  		//变换矩阵的值更改后需要使用QPainter重新设置变换矩阵,
qDebug()<<t1;     			//输出内容为:QTransform(type=TxNone, 
//11=1 12=0 13=0 21=0 22=1 23=0 31=0 32=0 33=1)    
pr.drawRect(r);}

在这里插入图片描述

示例12.22:QTransform::map()函数的使用(见图12-58)
void paintEvent(QPaintEvent *e){
QPainter pr(this);    QBrush bs(QColor(1,111,1));   
pr.setBrush(bs);
    QRectF r(0,55,22,55);   QLineF n(50,0,50,555);
    pr.drawLine(n);    		pr.drawRect(r);
    QTransform t;    		t.translate(50,0);	//x方向平移50
    QRectF r1=t.mapRect(r);   				//使用t转换r的坐标。
QLineF n1=t.map(n);     					//使用t转换n的坐标
//n1也可使用如下等效语句创建,更简洁
//QLineF n1=n*t;   						//注意t*n是错误的
    pr.drawRect(r1);	pr.drawLine(n1);}   	//绘制转换后的图形

在这里插入图片描述

示例12.23:使用变换矩阵计算变换后的坐标值(见图12-59)
void paintEvent(QPaintEvent *e){
    QPainter pr(this);    QBrush bs(QColor(1,111,1));    pr.setBrush(bs);
    QRect r(0,55,22,55);
    pr.drawRect(r);
    QTransform t;    t.translate(50,0);    t.rotate(-60);
    QPolygon g1=t.mapToPolygon(r);    pr.drawPolygon(g1);
qDebug()<<t;    qDebug()<<g1;}

在这里插入图片描述

本文作者:黄邦勇帅(原名:黄勇)

在这里插入图片描述

  • 27
    点赞
  • 103
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值