QT 利用QPainter繪圖的座標系轉換

 

2017年01月25日 09:15:17 老樊Lu碼 閱讀數:8757 標籤: Qt 更多

個人分類: Qt

版權聲明:本文爲博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/fanyun_01/article/details/53129781

       Qt繪製圖形時,少不了座標計算,那麼如何更好更快地計算出座標呢?現在來分析一下。

       如下圖所示,原來座標系是(0,0)X axis右Y axis下

現在想把它變成,座標在窗口中間,X右,Y上,標準的數學中的座標系。

Painter.setWindow(x,y,width().height());

用setWindow這個函數,表示什麼意思。前兩個參數左上角位置,後兩個參數寬高。

 

這個是原本的座標系,要把他變成下面這個

 


怎麼算呢,可以把變換好的座標系在紙上畫出來,左上角座標傳給前兩個參數,後兩個參數寬高可以算出來。

 


 
  1. Width= 50-(-50) = 100;

  2. 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的相應成員直接修改世界變換

 


 
  1. Void Qpainter::scale(qreal sx,qreal sy)

  2. {

  3. ......

  4. d->state->worldMatrix.scale(sx,sy);

  5. .......

  6. }

世界變換的兩個馬甲:Qpainter::setTransform  Qpainter::transform

 


 
  1. Void Qpainter::setTransform(const Qtransfrom &transform,bool combine)

  2. {

  3. setWorldTransform(transform,combine);

  4. }

廢棄的函數(從Qt4.3開始,Qtransform取代了Qmatrix的位置,下列函數已不建議使用):

Qpainter::setWorldMatrix   Qpainter::worldMatrix

窗口視口變換

直接相關:

Qpainter::setViewTransformEnabled

啓用,禁用視口變換

Qpainter::viewTransformEnabled

 

Qpainter::setViewport

設置 視口(物理座標)

Qpainter::setWindow

設置 窗口(與視口是同一矩形,中間太座標)

該變換是簡單的線性變換。

複合變換

窗口視口變換和世界變換的複合:Qpainter::combinedTransform

 


 
  1. Qtransform Qpainter::combinedTransform() const

  2. {

  3. Q_D(const QPainter);

  4. Return d->state->worldMatrix* d->viewTransform();

  5. }

典型應用:對鼠標事件的響應中,講座標從物理座標變換Qpainter需要的邏輯座標

仿射變換、透射變換

Qt4.3(包括)之前的Qmatrix只支持仿射變換(Affine transformation)

平移(Translation)  縮放(Scale)  旋轉(Rotation)  剪切(Shear)

Qtransform支持透射變換(perspective transformation).

M11

M12

M13

M21

M22

M23

M31 dx

M32 dy

M33

變換關係:

 


 
  1. X’=m11*x + m21*y +dx

  2. Y’=m22*y + m12*x +dy

  3. if(is not affine){

  4. w’=m13*x + m23*y + m33

  5. x’/=w’

  6. y’/=w’

  7. }

相關(射影幾何學,仿射幾何學,歐式幾何學)

        Qt的座標系統常用的幾個函數:  

        translate()函數,進行平移變換;scale()函數,進行比例變換;rotate()函數,進行旋轉變換;shear()函數,進行扭曲變換。

translate()函數,進行平移變換;scale()函數,進行比例變換;rotate()函數,進行旋轉變換;shear()函數,進行扭曲變換。最後介紹兩個有用的函數save()和restore(),利用它們來保存和彈出座標系的狀態,從而實現快速利用幾個變換來繪圖。
一、座標系簡介:
        Qt中每一個窗口都有一個座標系,默認的,窗口左上角爲座標原點,然後水平向右依次增大,水平向左依次減小,垂直向下依次增大,垂直向上依次減小。原點即爲(0,0)點,然後以像素爲單位增減。
例如:


 
  1. void Dialog::paintEvent(QPaintEvent *)

  2. {

  3. QPainter painter(this);

  4. painter.setBrush(Qt::red);

  5. painter.drawRect(0,0,100,100);

  6. painter.setBrush(Qt::yellow);

  7. painter.drawRect(-50,-50,100,100);

  8. }

        我們先在原點(0,0)繪製了一個長寬都是100像素的紅色矩形,又在(-50,-50)點繪製了一個同樣大小的黃色矩形。可以看到,我們只能看到黃色矩形的一部分。效果如下圖。
二、座標系變換:
        座標系變換是利用變換矩陣來進行的,我們可以利用QTransform類來設置變換矩陣,因爲一般我們不需要進行更改,所以這裏不在涉及。下面我們只是對座標系的平移,縮放,旋轉,扭曲等應用進行介紹。
1.利用translate()函數進行平移變換


 
  1. void Dialog::paintEvent(QPaintEvent *)

  2. {

  3. QPainter painter(this);

  4. painter.setBrush(Qt::yellow);

  5. painter.drawRect(0,0,50,50);

  6. painter.translate(100,100); //將點(100,100)設爲原點

  7. painter.setBrush(Qt::red);

  8. painter.drawRect(0,0,50,50);

  9. painter.translate(-100,-100);

  10. painter.drawLine(0,0,20,20);

  11. }

效果如下:
            這裏將(100,100)點作爲了原點,所以此時(100,100)就是(0,0)點,以前的(0,0)點就是
(-100,-100)點。要想使原來的(0,0)點重新成爲原點,就是將(-100,-100)設爲原點。
2.利用scale()函數進行比例變換,實現縮放效果


 
  1. void Dialog::paintEvent(QPaintEvent *)

  2. {

  3. QPainter painter(this);

  4. painter.setBrush(Qt::yellow);

  5. painter.drawRect(0,0,100,100);

  6. painter.scale(2,2); //放大兩倍

  7. painter.setBrush(Qt::red);

  8. painter.drawRect(50,50,50,50);

  9. }

      效果如下:
可以看到,painter.scale(2,2),是將橫縱座標都擴大了兩倍,現在的(50,50)點就相當於以前的(100,100)點。
3.利用shear()函數就行扭曲變換


 
  1. void Dialog::paintEvent(QPaintEvent *)

  2. {

  3. QPainter painter(this);

  4. painter.setBrush(Qt::yellow);

  5. painter.drawRect(0,0,50,50);

  6. painter.shear(0,1); //縱向扭曲變形

  7. painter.setBrush(Qt::red);

  8. painter.drawRect(50,0,50,50);

  9. }

效果如下:
        這裏,painter.shear(0,1),是對縱向進行扭曲,0表示不扭曲,當將第一個0更改時就會對橫行進行扭曲,關於扭曲變換到底是什麼效果,你觀察一下是很容易發現的。
4.利用rotate()函數進行比例變換,實現縮放效果


 
  1. void Dialog::paintEvent(QPaintEvent *)

  2. {

  3. QPainter painter(this);

  4. painter.drawLine(0,0,100,0);

  5. painter.rotate(30); //以原點爲中心,順時針旋轉30度

  6. painter.drawLine(0,0,100,0);

  7. painter.translate(100,100);

  8. painter.rotate(30);

  9. painter.drawLine(0,0,100,0);

  10. }

效果如下:
        因爲默認的rotate()函數是以原點爲中心進行順時針旋轉的,所以我們要想使其以其他點爲中心進行旋轉,就要先進行原點的變換。這裏的painter.translate(100,100)將(100,100)設置爲新的原點,想讓直線以其爲中心進行旋轉,可是你已經發現效果並非如此。是什麼原因呢?我們添加一條語句,如下:


 
  1. void Dialog::paintEvent(QPaintEvent *)

  2. {

  3. QPainter painter(this);

  4. painter.drawLine(0,0,100,0);

  5. painter.rotate(30); //以原點爲中心,順時針旋轉30度

  6. painter.drawLine(0,0,100,0);

  7. painter.rotate(-30);

  8. painter.translate(100,100);

  9. painter.rotate(30);

  10. painter.drawLine(0,0,100,0);

  11. }

效果如下:
        這時就是我們想要的效果了。我們加的一句代碼爲painter.rotate(-30),這是因爲前面已經將座標旋轉了30度,我們需要將其再旋轉回去,才能是以前正常的座標系統。不光這個函數如此,這裏介紹的這幾個函數均如此,所以很容易出錯。下面我們將利用兩個函數來很好的解決這個問題。
三、座標系狀態的保護
       我們可以先利用save()函數來保存座標系現在的狀態,然後進行變換操作,操作完之後,再用restore()函數將以前的座標系狀態恢復,其實就是一個入棧和出棧的操作。
例如:


 
  1. void Dialog::paintEvent(QPaintEvent *)

  2. {

  3. QPainter painter(this);

  4. painter.save(); //保存座標系狀態

  5. painter.translate(100,100);

  6. painter.drawLine(0,0,50,50);

  7. painter.restore(); //恢復以前的座標系狀態

  8. painter.drawLine(0,0,50,50);

  9. }

效果如下:
             利用好這兩個函數,可以實現快速的座標系切換,繪製出不同的圖形。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章