Qt绘制图形时,少不了坐标计算,那么如何更好更快地计算出坐标呢?现在来分析一下。
如下图所示,原来坐标系是(0,0)X axis右Y axis下
现在想把它变成,坐标在窗口中间,X右,Y上,标准的数学中的坐标系。
Painter.setWindow(x,y,width().height());
用setWindow这个函数,表示什么意思。前两个参数左上角位置,后两个参数宽高。
这个是原本的坐标系,要把他变成下面这个
怎么算呢,可以把变换好的坐标系在纸上画出来,左上角坐标传给前两个参数,后两个参数宽高可以算出来。
Width= 50-(-50) = 100;
Height = -50-50 = -100;
那么就是painter.setWindow(-50,50,100,-100);
一般painter.setWindow(-width()/2,height()/2,width(),-height());就可以达到目的了
World Corrdinates |
===> |
Window Coordinates |
===> |
Device Coordinates |
(逻辑坐标) |
世界变换 |
中间态坐标 |
窗口视口变换 |
(物理坐标) |
在默认情况下,3个坐标系是一致的。
世界变换
世界变换直接相关的函数:
Qpainter::setWorldMatrixEnabled |
启用,禁用世界变换 |
Qpainter:;setWorldTransform |
设置世界变换 |
Qpainter::worldTransform |
获取当前 |
Qpainter::resetTransform |
重置Qtransform() |
4个常用的函数:Qpainter::scale Qpainter::shear Qpainter::rotate Qpainter::translate
注:它们通过直接调用的Qtransform的相应成员直接修改世界变换
Void Qpainter::scale(qreal sx,qreal sy)
{
......
d->state->worldMatrix.scale(sx,sy);
.......
}
世界变换的两个马甲:Qpainter::setTransform Qpainter::transform
Void Qpainter::setTransform(const Qtransfrom &transform,bool combine)
{
setWorldTransform(transform,combine);
}
废弃的函数
(从
Qt4.3开始,
Qtransform取代了
Qmatrix的位置,下列函数已不建议使用
):
Qpainter::setWorldMatrix Qpainter::worldMatrix
窗口视口变换
直接相关:
Qpainter::setViewTransformEnabled |
启用,禁用视口变换 |
Qpainter::viewTransformEnabled |
|
Qpainter::setViewport |
设置 视口(物理坐标) |
Qpainter::setWindow |
设置 窗口(与视口是同一矩形,中间太坐标) |
该变换是简单的线性变换。
复合变换
窗口视口变换和世界变换的复合:Qpainter::combinedTransform
Qtransform Qpainter::combinedTransform() const
{
Q_D(const QPainter);
Return d->state->worldMatrix* d->viewTransform();
}
典型应用:对鼠标事件的响应中,讲坐标从物理坐标变换Qpainter需要的逻辑坐标
仿射变换、透射变换
Qt4.3(包括)之前的Qmatrix只支持仿射变换(Affine transformation)
平移(Translation) 缩放(Scale) 旋转(Rotation) 剪切(Shear)
Qtransform支持透射变换(perspective transformation).
M11 |
M12 |
M13 |
M21 |
M22 |
M23 |
M31 dx |
M32 dy |
M33 |
变换关系:
X’=m11*x + m21*y +dx
Y’=m22*y + m12*x +dy
if(is not affine){
w’=m13*x + m23*y + m33
x’/=w’
y’/=w’
}
相关(射影几何学,仿射几何学,欧式几何学)
Qt的坐标系统常用的几个函数:
translate()函数,进行平移变换;scale()函数,进行比例变换;rotate()函数,进行旋转变换;shear()函数,进行扭曲变换。
translate()函数,进行平移变换;scale()函数,进行比例变换;rotate()函数,进行旋转变换;shear()函数,进行扭曲变换。最后介绍两个有用的函数save()和restore(),利用它们来保存和弹出坐标系的状态,从而实现快速利用几个变换来绘图。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)点绘制了一个同样大小的黄色矩形。可以看到,我们只能看到黄色矩形的一部分。效果如下图。
void Dialog::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setBrush(Qt::yellow);
painter.drawRect(0,0,50,50);
painter.translate(100,100); //将点(100,100)设为原点
painter.setBrush(Qt::red);
painter.drawRect(0,0,50,50);
painter.translate(-100,-100);
painter.drawLine(0,0,20,20);
}
效果如下:
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);
}
效果如下:
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);
}
效果如下:
void Dialog::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.drawLine(0,0,100,0);
painter.rotate(30); //以原点为中心,顺时针旋转30度
painter.drawLine(0,0,100,0);
painter.translate(100,100);
painter.rotate(30);
painter.drawLine(0,0,100,0);
}
效果如下:
void Dialog::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.drawLine(0,0,100,0);
painter.rotate(30); //以原点为中心,顺时针旋转30度
painter.drawLine(0,0,100,0);
painter.rotate(-30);
painter.translate(100,100);
painter.rotate(30);
painter.drawLine(0,0,100,0);
}
效果如下:
void Dialog::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.save(); //保存坐标系状态
painter.translate(100,100);
painter.drawLine(0,0,50,50);
painter.restore(); //恢复以前的坐标系状态
painter.drawLine(0,0,50,50);
}
效果如下: