【qt】坐标转换

文章介绍了计算机图形学中坐标变换的概念,如平移、旋转、缩放,以及如何在QPainter中使用QTransform类进行这些变换。通过齐次坐标表示二维和三维点,可以简化变换的数学表达。同时,文章展示了变换的复合性,如平移和旋转的顺序影响结果,并提供了使用QPainter进行坐标变换的代码示例。
摘要由CSDN通过智能技术生成

坐标变换(QTransform)

需要数学知识和计算机图形学方面的知识

基本数学知识

  1. 齐次坐标

    1. 二维空间中的点可使用(x,y)表示,但在计算机图形学中使用齐次坐标表示点更为方便,齐次坐标把点表示为三元组,即在(x,y)基础上增加一维表示(x,y,w),其中w是一个非零值
    2. 每个点有很多个不同的齐次坐标表示(只要其中一个时另一个倍数即可),比如(1,2,5),(2,4,10),(4.8.20)都是表示同一个点,通常会使用w去除齐次坐标,从而一个点被表示为(x/w,y/w,1),这样每一个二维坐标点都可以使用三维齐次坐标来表示
    3. 同理三维坐标(x,y,z),也可以使用四维齐次坐标表示为(x,y,z,1)
    4. 使用齐次坐标后,所有的坐标变换公式都可以使用如下矩阵相乘的形式来表示 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传在这里插入图片描述
  2. 坐标变换公式

    1. 以下各式中,dx和dy表示平移距离,Sx和Sy表示缩放系数,θ表示绕原点逆时针旋转的角度,P1(x1,y1)为坐标变换后的点,p(x,y)为坐标变换前的点
    2. 例如坐标 x1 = x + 0 +dx // a=1 b =0 c =dx [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传在这里插入图片描述
  3. 坐标的复合变换: 即多个坐标变换序列的组合

    1. 连续平移变换(其结果是平移相加)
      1. 把点p平移至点p1再平移至p2,其平移公式的推导步骤为 P 1 = P ∙ M 1 ; P 2 = P 1 ∙ M 2 = P ∙ M 1 ∙ M 2 P1 = P∙M1; P2 = P1∙M2 = P∙ M1∙M2 P1=PM1;P2=P1M2=PM1M2 由此推导过程可见,对复合的坐标变换系列,只需计算其变换矩阵即可,以上规则也适用于复杂的复合变换 P 2 = P ∙ T ( t 1 x , t 1 y ) ∙ T ( t 2 x , t 2 y ) = P ∙ T ( t 1 x + t 2 x , t 1 y + t 2 y ) P2 = P∙ T(t1x, t1y) ∙ T(t2x, t2y) = P∙ T(t1x+t2x , t1y+t2y) P2=PT(t1x,t1y)T(t2x,t2y)=PT(t1x+t2x,t1y+t2y)
    2. 连续缩放变换的结果就是缩放相乘 P 1 = P ∙ S ( s 1 x , s 1 y ) ∙ S ( s 2 x , s 2 y ) = P ∙ S ( s 1 x ∙ s 2 x , s 1 y ∙ s 2 y ) P1 = P∙ S(s1x, s1y) ∙ S(s2x, s2y) = P∙ S(s1x ∙ s2x, s1y ∙ s2y) P1=PS(s1x,s1y)S(s2x,s2y)=PS(s1xs2x,s1ys2y)
    3. 连续旋转的变换结果是旋转相加 P 1 = P ∙ R ( θ 1 ) ∙ R ( θ 2 ) = P ∙ R ( θ 1 + θ 2 ) P1 = P∙R(θ 1) ∙ R(θ 2) = P∙ R(θ 1 + θ 2) P1=PR(θ1)R(θ2)=PR(θ1+θ2)
  4. 矩阵计算的注意事项:平移再旋转与选旋转再平移是不同的 M 1 ∙ M 2 ∙ M 3 = ( M 1 ∙ M 2 ) ∙ M 3 = M 1 ∙ ( M 2 ∙ M 3 ) M1∙M2∙M3 = (M1∙ M2) ∙ M3 = M1∙ (M2 ∙ M3) M1M2M3=(M1M2)M3=M1(M2M3) 但是不等于 M 1 ∙ M 2 ≠ M 2 ∙ M 1 M1∙M2 ≠ M2∙M1 M1M2=M2M1

  5. 由此可见,只需给出变换矩阵,便可对其进行坐标变换,因此在计算机编程中,通常只需给出一个变换矩阵,然后给矩阵各元素赋予需要的值便可对其进行各种坐标变换

  6. 仿射(affine)变换:平移、旋转、缩放、对称、错切这些变换都是仿射变换的特例,任何仿射变换总可以表示为几种变换的组合。

  7. 投影变换:投影变换分为透视变换和平行变换

函数

  1. QPainter类中的基本变换函数进行坐标变换
    1. 默认情况下,QPainter是在自己所关联的绘制设备的坐标系(通常为像素)上运行的,绘制设备默认坐标系的原点位于左上角,X向右增长,Y向下增长
    2. QPainter的变换矩阵(QTransform 类)上进行的变换,可使用QPainter::worldTransform()函数获取该变换矩阵
      1. 平移坐标
        1. void translate(const QPointF &offset)
        2. void translate(const QPoint &offset)
        3. void translate(qreal dx,qreal dy)
      2. 缩放坐标系
        1. void scale(qreal sx,qreal sy)
      3. 按顺时针旋转坐标,单位为angle
        1. void rotate(qreal angle)
      4. 使用(sh,sv)错切坐标
        1. void shear(qreal sh,qreal sv)
      5. 保存当前绘制器状态(把状态压入堆栈),包括当前的坐标系
        1. void save()
      6. 恢复当前绘制器状态(从堆栈中弹出保存的状态)
        1. void restore()
      7. 重置所有坐标变换
        1. void resetTransform
      8. 返回从逻辑坐标转换为平台相关绘图设备的设备坐标矩阵,只有在平台相关句柄(Qt::HANDLE)上使用平台绘制命令才需要此函数
        1. const QTransform &QPainter::deviceTransform() const

函数

#ifndef WIDGET_H
#define WIDGET_H

#include <QtWidgets>
#include <QRectF>
class DrawCroodinates :public QWidget
{
    Q_OBJECT
private:
    void init(){

    }
protected:
    void paintEvent(QPaintEvent *event) override{
        Q_UNUSED(event)

        QPainter painter;
        painter.begin(this);

        QBrush brush(Qt::red);
        painter.setBrush(brush);

        QRectF  rect(0,11,22,55);
        painter.drawRect(rect); //画第一个矩形
        painter.translate(50,100);//变换1 向(dx,dy)(50,100)平移
        painter.drawRect(rect); //画第一个矩形


        painter.save();//保存当前绘制器状态
        painter.translate(50,50);
        painter.scale(1,2); //向Y缩放两倍
        painter.rotate(-60);//逆时针旋转60°
        painter.drawRect(rect);//变换2

        painter.restore();//恢复绘制器状态
        painter.translate(100,0);
        painter.drawRect(rect);//变换3

        painter.translate(50,0);
        painter.rotate(-60);
        painter.scale(1,3);
        painter.drawRect(rect);//变换4

        painter.resetTransform();
        painter.setBrush(QBrush(Qt::yellow));
        painter.drawRect(rect.translated(20,20));//变换5

        painter.end();
    }

public:
    DrawCroodinates(QWidget *p =nullptr) :QWidget(p){ init(); }
};

#endif // WIDGET_H
本资源为Qt绘图基础,世界坐标系转换为逻辑坐标系。世界坐标系原点在视图左上角,本例子通过世界坐标转换,将坐标原点定位在视图中央,Y轴向上,X轴向右,并绘制坐标轴,基于逻辑坐标系下的绘图,可将转换关系函数取消生效,对比世界坐标系下的绘图。 重写PainterEvent函数: void QtPixPainter::paintEvent(QPaintEvent* event) { QPainter painter(this); // 反走样 painter.setRenderHint(QPainter::Antialiasing, true); //物理坐标系与逻辑坐标系的转换,如果不转换,下面的绘图都是在世界坐标系下 setWorldTransform(painter); // 其他一些绘制矩形,多边形的例子,经过上面转换,都是在逻辑坐标系下 drawRectScale(painter); //draw_shearRect(painter); //利用rotate()函数进行比例变换,实现缩放效果 //draw_rotate_act(painter); //draw_by_save_restore(painter); //transform_draw_SinX(painter); transform_draw(painter); local_drawConvexPolygon(painter); } // 将世界坐标(原点左上角)转换为逻辑坐标(原点在屏幕中间) QPointF QtPixPainter::mapToScene(const QPointF& point) { QTransform transMatrix = _transform.inverted(); //翻转矩阵? return transMatrix.map(point); //将点piont映射到transMatrix定义的坐标系中来 } // 将鼠标的逻辑位置返回并以标签形式展示 void QtPixPainter::mouseMoveEvent(QMouseEvent* event) { QString msg; QPointF mouse_po = mapToScene(event->pos()); //总是返回屏幕物理坐标系 double x = mouse_po.x(); // 总是返回屏幕物理坐标系 double y = mouse_po.y(); QString str = "(" + QString::number(x) + "," + QString::number(y) + ")"; //qDebug()<<"world x = "<pos().x()<<",world y = "<pos().y(); m_mouse_lable->setText(str); }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值