I would like to be able to rotate a QGraphicsItem
based on its center, and scale it based on the top left corner.
When I try to combine rotation and scaling, the item also apparently moves...
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsTextItem>
void testTransformations(QGraphicsScene* s)
{
qreal angle = 30, scaleX = 2, scaleY = 1;
// Reference rotated not scaled
QGraphicsTextItem* ref = new QGraphicsTextItem("bye world");
ref->setFont(QFont("Arial", 20));
ref->setDefaultTextColor(Qt::green);
s->addItem(ref);
qreal center0X = ref->boundingRect().center().x();
qreal center0Y = ref->boundingRect().center().y();
QTransform t0;
t0.translate(center0X, center0Y);
t0.rotate(angle);
t0.translate(-center0X, -center0Y);
ref->setTransform(t0);
// Reference scaled not rotated
QGraphicsTextItem* ref1 = new QGraphicsTextItem("bye world");
ref1->setFont(QFont("Arial", 20));
ref1->setDefaultTextColor(Qt::yellow);
s->addItem(ref1);
QTransform t;
t.scale(scaleX, scaleY);
ref1->setTransform(t);
// Rotate around center of resized item
QGraphicsTextItem* yyy = new QGraphicsTextItem("bye world");
yyy->setDefaultTextColor(Qt::red);
yyy->setFont(QFont("Arial", 20));
s->addItem(yyy);
qreal center1X = yyy->boundingRect().center().x() * scaleX;
qreal center1Y = yyy->boundingRect().center().y() * scaleY;
// in my code I store the item size, either before or after the resize, and use it to determine the center - which is virtually the same thing as this for a single operation
QTransform t1;
t1.translate(center1X, center1Y);
t1.rotate(angle);
t1.translate(-center1X, -center1Y);
t1.scale(scaleX, scaleY);
yyy->setTransform(t1);
// rotated around center of bounding rectangle
QGraphicsTextItem* xxx = new QGraphicsTextItem("bye world");
xxx->setDefaultTextColor(Qt::blue);
xxx->setFont(QFont("Arial", 20));
s->addItem(xxx);
qreal center2X = xxx->boundingRect().center().x();
qreal center2Y = xxx->boundingRect().center().y();
QTransform t2;
t2.translate(center2X, center2Y);
t2.rotate(angle);
t2.translate(-center2X, -center2Y);
t2.scale(scaleX, scaleY);
xxx->setTransform(t2);
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QGraphicsScene s;
QGraphicsView view(&s);
s.setSceneRect(-20, -20, 500, 500);
view.show();
testTransformations(&s);
return app.exec();
}
Result:
- green is rotated, not scaled (or scaled a different amount)
- yellow is scaled, not rotated
- blue is scaled, and rotated by the center of bounding rectangle (which is not resized)
- red is scaled and rotated around center
It is evident now to me that the transformations operate correctly - if I resize and rotate an item, I get first the yellow then the red item.
Yet, what I need, is if an item is already rotated (green) then scaled, to behave like the blue - stretch in the same direction, without jumping, while if an item is first scaled, then rotated, to behave like the red... Even more complicated, the original item (green) may have had scaling applied, so my simple solution of using the bounding rectangle wouldn't work.
I have tried to calculate the change... Always with weird results.
Is it possible to scale a rotated item, based on top left, without also moving it, while also rotating it around its center ?
It may require incremental transformations, and would be odd to get different results based on the order they are applied.
Edit: I have been experimenting with position adjustments, since the transformations have failed, but I have not been able to get a formula for a transform function that will give me smooth visual transition of the type:
1) rotate item (pinned to center)
2) scale item (pinned to top left) without jumping
3) rotate item (pinned to center)
where step 2 would also include an offset in position. I just don't know how to do it.
The way I see it, in the fragment for the "red" transform, I would have o add a mapToScene(somePoint)
before and after the transform, and perform a correction (moveBy
) based on result.
This would not be a great fix, but still... If only I knew how to adjust the position of the item after resize so it doesn't jump, it would still be a fix...