找回密码
 立即注册
  • QQ空间
  • 回复
  • 收藏

第16篇 Qt5之2D绘图(六)Qt坐标系统

yafeilinux 2017-4-6 16:06 25836人围观 yafeilinux原创

版权声明

该文章原创于Qt开源社区(www.qter.org),作者yafeilinux,转载请注明出处!单击这里讨论该文章!

导语

       前一节我们讲解了图片的显示,其中很多地方都用到了坐标的变化。这一节我们将讲解Qt的坐标系统,分为两部分来讲解:第一部分主要讲解前面一节的那几个函数,它们分别是translate()平移变换、scale()比例变换、rotate()旋转变换、shear()扭曲变换。最后还会介绍两个有用的函数save()和restore(),利用它们来保存和弹出坐标系的状态,从而实现快速利用几个变换函数来绘图。
    第二部分会和大家一起来研究一下Qt的坐标系统,其中可能会涉及到多个坐标,大家一定要亲自动手操作感悟一下,不然很难理解的!

环境:Windows 7 + Qt 5.8.0(包含QtCreator 4.2.1


目录


第一部分 Qt坐标系统应用
一、坐标系统简介
二、坐标系统变换
三、坐标系统的保存


第二部分 坐标系统深入研究
一、获得坐标信息
二、研究变换后的坐标系统
三、研究绘图设备的坐标系统


正文


第一部分 Qt坐标系统应用


一、坐标系统简介

    Qt中每一个窗口都有一个坐标系统,默认的,窗口左上角为坐标原点,水平向右依次增大,水平向左依次减小,垂直向下依次增大,垂直向上依次减小。原点即为(0,0)点,以像素为单位增减。
下面仍然在上一节的程序中进行代码演示,更改paintEvent()的内容如下:


void Dialog::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setBrush(Qt::red);
    painter.drawRect(0, 0, 100, 100);
    painter.setBrush(Qt::yellow);
    painter.drawRect(-50, -50, 100, 100);
}

    我们先在原点(0,0)绘制了一个长宽都是100像素的红色矩形,又在(-50,-50)点绘制了一个同样大小的黄色矩形。可以看到,我们只能看到黄色矩形的四分之一部分。运行程序,效果如下图所示。
01.png


二、坐标系统变换


默认的,QPainter在指定设备的坐标系统上进行绘制,在进行绘图时,可以使用QPainter::scale()函数缩放坐标系统;使用QPainter::rotate()函数顺时针旋转坐标系统;使用QPainter::translate()函数平移坐标系统;还可以使用QPainter::shear()围绕原点来扭曲坐标系统。如下图所示。

02.png


       坐标系统的2D变换由QTransform类实现,我们可以使用前面提到的那些便捷函数进行坐标系统变换,当然也可以通过QTransform类实现。

1.平移变换。将paintEvent()函数内容更改如下:


void Dialog::paintEvent(QPaintEvent *)
{
    // 平移变换
    QPainter painter(this);
    painter.setBrush(Qt::yellow);
    painter.drawRect(0, 0, 50, 50);
    //将点(100,100)设为原点
    painter.translate(100, 100);  
    painter.setBrush(Qt::red);
    painter.drawRect(0, 0, 50, 50);
    painter.translate(-100, -100);
    painter.drawLine(0, 0, 20, 20);
}

       运行程序,效果如下图所示。

03.png

       这里先在原点(0, 0)绘制了一个宽、高均为50的正方形,然后使用translate()函数将坐标系统进行了平移,使(100, 100)点成为了新原点,所以我们再次进行绘制的时候,虽然drawRect()中的逻辑坐标还是(0, 0)点,但实际显示出来的却是在(100, 100)点的红色正方形。可以再次使用translate()函数进行反向平移,使原点重新回到窗口左上角。


2.缩放变换。将paintEvent()函数中的内容更改如下:


void Dialog::paintEvent(QPaintEvent *)
{
    // 缩放
    QPainter painter(this);
    painter.setBrush(Qt::yellow);
    painter.drawRect(0, 0, 100, 100);
    painter.scale(2, 2); //放大两倍
    painter.setBrush(Qt::red);
    painter.drawRect(50, 50, 50, 50);
}

       运行程序,效果如下图所示。

04.png

       可以看到,当我们使用scale()函数将坐标系统的横、纵坐标都放大两倍以后,逻辑上的(50 50)点变成了窗口上的(100, 100)点,而逻辑上的长度50,绘制到窗口上的长度却是100



3.扭曲变换。将paintEvent()函数更改如下:


void Dialog::paintEvent(QPaintEvent *)
{   
// 扭曲    QPainter painter(this);   
painter.setBrush(Qt::yellow);   
painter.drawRect(0, 0, 50, 50);   
painter.shear(0, 1); //纵向扭曲变形   
painter.setBrush(Qt::red);   
painter.drawRect(50, 0, 50, 50);
}

       运行程序,效果如下图所示。

05.png

       shear()有两个参数,第一个是对横向进行扭曲,第二个是对纵向进行扭曲,而取值就是扭曲的程度。比如程序中对纵向扭曲值为1,那么就是红色正方形左边的边下移一个单位,右边的边下移两个单位,值为1就表明右边的边比左边的边多下移一个单位。大家可以更改取值,测试效果。


4.旋转变换。将paintEvent()函数更改如下:

void Dialog::paintEvent(QPaintEvent *)
{
    // 旋转
    QPainter painter(this);
    painter.drawLine(0, 0, 100, 0);
    //以原点为中心,顺时针旋转30度
    painter.rotate(30);
    painter.drawLine(0, 0, 100, 0);
    painter.translate(100, 100);
    painter.rotate(30);
    painter.drawLine(0, 0, 100, 0);
}
       运行程序,效果如下图所示。
06.png

       这里先绘制了一条水平的直线,然后将坐标系统旋转了30度,又绘制了一条直线。可以看到,默认是以原点(0, 0)为中心旋转的。如果想改变旋转中心,可以使用translate()函数,比如这里将中心移动到了(100, 100)点,然后旋转了30度,又绘制了一条直线。我们的本意是想在新的原点从水平方向旋转30度进行绘制,可是实际效果却超过了30度。这是由于前面已经使用rotate()函数旋转过坐标系统了,后面的旋转会在前面的基础上进行。
       下面我们再次更改paintEvent()函数:

void Dialog::paintEvent(QPaintEvent *)
{   
// 旋转   
QPainter painter(this);   
painter.drawLine(0, 0, 100, 0);   
//以原点为中心,顺时针旋转30度   
painter.rotate(30);   
painter.drawLine(0, 0, 100, 0);   
// 反向旋转   
painter.rotate(-30);   
painter.translate(100, 100);   
painter.drawLine(0, 0, 100, 0);   
painter.rotate(30);   
painter.drawLine(0, 0, 100, 0);
}

       运行程序,效果如下图所示。
07.png

       这次我们在移动原点以前先将坐标系统反向旋转,可以看到,第二次旋转也是从水平方向开始的。
       其实,前面讲到的这几个变换函数都是如此,他们改变了坐标系统以后,如果不进行逆向操作,坐标系统是无法自动复原

66人点赞鲜花

2人点赞握手

雷人

路过

鸡蛋

刚表态过的朋友 (68 人)

原作者: yafeilinux

yafeilinux和他的朋友们微信公众号二维码

微信公众号

专注于Qt嵌入式Linux开发等。扫一扫立即关注。

Qt开源社区官方QQ群二维码

QQ交流群

欢迎加入QQ群大家庭,一起讨论学习!


公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了