68 2D绘图(坐标系统)

Qt的坐标系统是由QPainter类控制的,而QPainter是在绘图设备上绘制的。绘图设备类QPaintDevice是所有可以绘制的对象的基类,它的子类主要有QWidget、QPixmap、QPicture、QImage和QPrinter等。

一个绘图设备的默认坐标系统中原点(0, 0)在其左上角,x坐标向右增长,y坐标向下增长。在基于像素的设备上,默认的单位是一个像素,而在打印机上默认的单位是一个点(1/72英寸)。            

QPainter的逻辑坐标与绘图设备的物理坐标之间的映射由QPainter的变换矩阵、视口和窗口处理。逻辑坐标和物理坐标默认是一致的。 

抗锯齿渲染

参考:https://blog.csdn.net/qq_40732350/article/details/86994305

坐标系统基本转换

QPainter的逻辑坐标与绘图设备的物理坐标之间的映射由QPainter 的变换矩阵、视口和窗口处理。逻辑坐标和物理坐标默认是一致的。

默认情况下,QPainter在关联的设备自己的坐标系上运行,但它也完全支持坐标转换。您可以使用QPainter::scale()函数按给定的偏移量缩放坐标系,使用QPainter::rotate()函数顺时针旋转它,使用QPainter::translate()对坐标系进行平移。

还可以使用QPainter::shear()函数在原点周围扭转坐标系。所有转换操作都在QPainter的转换矩阵上运行,您可以使用QPainter::worldTransform()函数进行检索。矩阵将平面中的点转换为另一点。

如果你反复需要相同的转换,你也可以使用Qtransform类对象和QPainter::worldTransform和QPainter::setWorldTransform()函数。您可以随时通过调用QPainter::save()函数来保存QPainter的变换矩阵,该函数将矩阵保存在内部堆栈中。使用QPainter::restore()函数弹出回来。

坐标系统”窗口-视口”转换

在使用QPainter进行绘制时,会使用逻辑坐标进行绘制,然后再转换为绘图设备的物理坐标。逻辑坐标到物理坐标的映射由QPainter的worldTransform()函数和QPainter的viewport()以及window()函数进行处理。其中视口(viewport)表示物理坐标下指定的一个任意矩形,而窗口(window,与以前讲的窗口部件的概念不同)表示逻辑坐标下的相同的矩形。默认的,逻辑坐标和物理坐标是重合的,它们都相当于绘图设备上的矩形。

使用窗口—视口转换可以使逻辑坐标系统适合应用的要求,这个机制也可以用来让绘图代码独立于绘图设备。 

例如可以使用下面的代码来使逻辑坐标以(-50, -50)为原点,宽为100,高为100,(0, 0)点为中心:

QPainter painter(this);
painter.setWindow(QRect(-50, -50, 100, 100));

现在逻辑坐标的(-50, -50)对应绘图设备的物理坐标的(0, 0)点。这样就可以独立于绘图设备,使绘图代码在指定的逻辑坐标上进行操作了。当设置窗口或者视口矩形时,实际上是执行了坐标的一个线性变换,窗口的四个角会映射到视口对应的四个角,反之亦然。出于这个原因,一个很好的办法是让视口和窗口维持相同的宽高比来防止变形:

int side = qMin(width(), height());
int x = (width() - side / 2);
int y = (height() - side / 2);
painter.setViewport(x, y, side, side);

实例:

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    // 填充界面背景为白色
    painter.fillRect(rect(), Qt::white);
    painter.setPen(QPen(Qt::red, 11));
    // 绘制一条线段
    painter.drawLine(QPoint(5, 6), QPoint(100, 99));
    // 将坐标系统进行平移,使(200, 150)点作为原点
    painter.translate(200, 150);
    // 开启抗锯齿
    painter.setRenderHint(QPainter::Antialiasing);
    // 重新绘制相同的线段
    painter.drawLine(QPoint(5, 6), QPoint(100, 99));  
}

运行结果:

实例:

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setWindow(-50, -50, 100, 100);
    painter.setBrush(Qt::green);
    painter.drawRect(0, 0, 20, 20);
}

这里先使用setWindow()函数将逻辑坐标矩形设置为以(-50, -50)为起点,宽100,高100。这样逻辑坐标的(-50, -50)点就会对应物理坐标的(0, 0)点,因为这里是在this即Widget部件上进行绘图,所以Widget就是绘图设备,也就是说,现在逻辑坐标的(-50, -50)点对应界面上的左上角的(0, 0)点。而且,因为逻辑坐标矩形宽为100,高为100,所以界面的宽度和高度都会被100等分。

为什么绘制的矩形不是我们想要的效果呢?

更改逻辑坐标或者物理坐标的矩形,就是进行坐标的一个线性变换,逻辑坐标矩形的四个角会映射到对应物理坐标矩形的四个角。而现在Widget部件的大小为宽400,高300,所以物理坐标对应的矩形就是(0, 0, 400, 300)。这样按比例对应,就是在水平方向,逻辑坐标的1个单位对应物理坐标的4个单位;在垂直方向,逻辑坐标的1个单位,对应物理坐标的3个单位。所以逻辑坐标中的宽20高20的矩形在物理坐标中就是宽80高60的矩形。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值