本文章重點表述QGraphicsItem中,對于旋轉後的坐标變化。
我在實作QGraphicsRectItem的縮放和旋轉時,遇到了這樣一個問題。原本實作的縮放,在旋轉後也是能用的。但是涉及到旋轉中心的問題,讓人有些難以了解,最終分析實踐得到下述結論。
執行個體文章:https://blog.csdn.net/xiaonuo911teamo/article/details/106075647
如果你對QGraphicsItem的坐标機制,不甚了解,請先看此文章。https://blog.csdn.net/qq_25800311/article/details/81300923。
進入正題
QGrahpicsItem 對于旋轉僅僅是儲存了旋轉的角度與旋轉中心,并不儲存旋轉之後的坐标。下面看一個例子。
你看到這個例子中隐藏的病症了嗎?
我給了他預設正方形中心為旋轉中心(Qt裡面不設定是預設為原點的)。原本是一個旋轉了30度的正方形,然後從一個正方形拉伸到了一個長方形。到此看似還沒有問題,但是如果考慮下一步,我們需要再次旋轉呢?原本我們是以中心為旋轉中心的,但是現在呢?仍然是那個點,但他不是中心了。至少在我使用時,這是一個需要解決的問題,我需要将中心再次設定為矩形中心。我簡單執行了setTransformOriginPoint(this->rect().center());,然後我并沒有如願。
我得到的是下圖左側黃色的矩形,而我想要的是右側綠色的矩形。
為什麼會是這個結果呢?
經過一番研究,才得到開頭說的結論,QGraphicsItem隻是儲存了旋轉角度和旋轉中心,當繪制的時候,再計算位置進行繪制。如此,當我們設定了新的中心點,如果已經有了旋轉角度的話,那麼則會出現平移的現象。是以為了解決這個問題,我們需要再拉伸之後,将以(P1為中心的矩形)平移到(以P2為中心的矩形)的位置。
分析條件:O(x0,y0)點是之前的旋轉中心,P1(x1,y1)是新的旋轉中心,線段OP1=線段OP2,∠P2OP1為alpha(例子中是30度)。
思路:先求出P2坐标,然後平移P1到P2即可。求P2坐标可簡化為,線OP1旋轉30度後,點P1’(P2)的坐标。
插播一個小公式
x’ = x1 + r * cos(a + b);
x’ = x1 + r * cos(a) * cos(b) - r * sin(a) * sin(b);
又因為:
r * cos(b) = x2 - x1;
r * sin(b) = (y2 - y1);
最終可以求出:
x’ = x1 + cos(a) * (x2 - x1) - sin(a) * (y2 - y1);
同理求出:
y’ = y1 + sin(a) * (x2 - x1) + cos(a) * (y2 - y1);
回到正題
套用上述公式,就可以得到P2的坐标了。下面是代碼示例。下面的代碼取自母親章節:https://blog.csdn.net/xiaonuo911teamo/article/details/106075647
auto rr = this->rect();
auto angle = qDegreesToRadians(this->rotation());
auto p1 = rr.center();
auto origin = this->transformOriginPoint();
QPointF p2 = QPointF(0, 0);
p2.setX(origin.x() + qCos(angle)*(p1.x() - origin.x()) - qSin(angle)*(p1.y() - origin.y()));
p2.setY(origin.y() + qSin(angle)*(p1.x() - origin.x()) + qCos(angle)*(p1.y() - origin.y()));
auto diff = p1 - p2;
this->setRect(rr.adjusted(-diff.x(), -diff.y(), -diff.x(), -diff.y()));
setTransformOriginPoint(this->rect().center());