Qt Coordinate System

Posted unclerunning

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Qt Coordinate System相关的知识,希望对你有一定的参考价值。

Qt 坐标系统

数学基础

矩阵与线性变换

坐标系变换

Qt坐标系统



视口

和OpenGL一样,视口确定了画面在窗口(QWidget)中显示的区域,Qt的绘图坐标会完全映射到视口(View port)上,就像图示一样。

默认情况下,窗口和视口是重合的,视口的大小覆盖了整个窗口。

和OpenGL一样,Qt的QPainter也有设置视口的接口:painter.setViewport(startX, startY, width, hight);

例如,对于一个400x400(resize(400,400))的窗口:

    void paintEvent(QPaintEvent *)
    
        QPainter painter(this);
        //在400x400的默认视口下画一个矩形区域,代表视口
        painter.drawRect(100, 100, 200, 200);

        //视口:限制窗口的绘图区域
        painter.setViewport(100, 100, 200, 200);       

        painter.fillRect(100, 100, 200, 200, Qt::red);
    

上面的代码在400x400的逻辑画布中画了一个“正方形”,中心与画布中心重合,边界距离画布的边界为100。最后,Qt将画布线性地映射到视口中,结果如下:



平移变换

    void paintEvent(QPaintEvent *)
    
        QPainter painter(this);

        //平移
        painter.translate(150, 150);
        //在平移之后的坐标系中绘图
        painter.fillRect(0, 0, 100, 100, Qt::red);
    

上面的代码在400x400的逻辑画布中,先将坐标系移动到点(150,150),然后在移动之后的坐标系中画一个100x100的矩形。结果如下:



缩放变换

    void paintEvent(QPaintEvent *)
    
        QPainter painter(this);
        painter.drawRect(100, 100, 200, 200);

        //平移
        painter.translate(150, 150);
        //缩放
        painter.scale(2, 2);

        painter.fillRect(0, 0, 50, 50, Qt::red);
    

上面的代码在400x400的逻辑画布中,先将坐标系移动到点(150,150),接着对移动之后的坐标系的x轴和y轴的基向量放大,得到新的坐标系,然后在这个坐标系中画一个50x50的矩形。结果和上图一样:



setWindow

    void paintEvent(QPaintEvent *)
    
        QPainter painter(this);
        painter.drawRect(100, 100, 200, 200);

        painter.setWindow(-75, -75, 200, 200);

        painter.fillRect(0, 0, 50, 50, Qt::red);
    

上面的代码等价于上节中的变换:setWindow 平移+ 缩放。

也可以等价为先缩放,再在缩放之后的坐标系中平移:

    void paintEvent(QPaintEvent *)
    
        QPainter painter(this);
        painter.drawRect(100, 100, 200, 200);

        //缩放
        painter.scale(2, 2);
        //平移
        painter.translate(75, 75);

        painter.fillRect(0, 0, 50, 50, Qt::red);
    

setWindow 平移 + 缩放 缩放 + 平移

所以,其实setWindow就是一个平移和缩放的组合操作,得到一个新的坐标系。

旋转

    void paintEvent(QPaintEvent *)
    
        QPainter painter(this);

        painter.translate(200, 200);

        // 顺时针旋转 30 度
        painter.rotate(30); 

        painter.fillRect(0, 0, 100, 100, Qt::red);
    



总结

OpenGL 3D坐标系统图示:



2D坐标系统图示:



与3D相比,2D的z坐标为0。

图中转换 T4T3T2 是Qt做的,我们在乎的是转换 T1=M1M2M3...Mn

T4T3T2 其实就是将画布(QWidget)转换到1x1x1的空间。 T1=M1M2M3...Mn 就是我们做的一系列坐标系变换。

例如:

    void paintEvent(QPaintEvent *)
    
        QPainter painter(this); 
        //M1
        painter.translate(200, 200);    
        //M2
        painter.rotate(30); 
        painter.fillRect(0, 0, 100, 100, Qt::red);
    

上面的代码在画布(QWidget)坐标系M中,先将坐标系进行平移变换 M1 得到坐标系M1,接着,对平移后的坐标系M1进行旋转变换 M2 得到坐标系M2。所以,当前的绘图坐标系(painter coordinate)就是M2,接下来使用的点的坐标都是坐标系M2中的点。Qt将M2中的点 (xM2,yM2,0) 与矩阵 T1 相乘,将点转换到M坐标系(QWidget):

xMyM0 = T1 xM2yM20

然后,将M坐标系中的点与矩阵 T4T3T2 相乘,将点转换到1x1x1空间中,OpenGL再将点映射到Qt设置的视口上,注意,此视口非painter.setViewport设置的视口,此视口是为顶层窗口设置的视口,默认覆盖顶层窗口。

以上是关于Qt Coordinate System的主要内容,如果未能解决你的问题,请参考以下文章

初识OpenGL (-)坐标系统(Coordinate System)

初识OpenGL (-)坐标系统(Coordinate System)

Opengl - GLM :: Ortho + GLM_COORDINATE_SYSTEM =很奇怪?

DICOM-RT:放疗系统的坐标系统DICOM-RT Coordinate System

Silverlight & Blend动画设计系列十:Silverlight中的坐标系统(Coordinate System)与向量(Vector)运动

Silverlight & Blend动画设计系列十:Silverlight中的坐标系统(Coordinate System)与向量(Vector)运动