How to rotate QGraphicsItem right after mouse?
-
Hello!
My application have QGraphicsScene and custom QGraphicsItem on it.
I wrote the following code for my custom graphics item rotation:// FigureScene is inherited from QGraphicsScene void FigureScene::mousePressEvent(QGraphicsSceneMouseEvent* mouseEvent) { // Remember last press coordinate if (mouseEvent->button() == Qt::RightButton) { lastRightMousePressed = mouseEvent->screenPos(); } } void FigureScene::mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) { if (mouseEvent->button() == Qt::RightButton) { const auto sceneCoord = mouseEvent->scenePos(); foreach (QGraphicsItem* item, m_parentScene->selectedItems()) { QTransform transform; QPointF center = item->sceneBoundingRect().center(); transform.translate(center.x(), center.y()); qreal angle = qAtan2(lastRightMousePressed.y() - sceneCoord.y(), lastRightMousePressed.x() - sceneCoord.x()); transform.rotate(angle); transform.translate(-center.x(), -center.y()); item->setPos(transform.map(item->pos())); item->setRotation(item->rotation() + angle); } } }
And my figure rotating something like this:
The problem is that when I rotate the mouse clockwise or counterclockwise, the figure rotates only counterclockwise.I would like my figure to rotate right after the mouse.
How can I achieve that? -
Instead of doing additive rotation each move I would modify item's origin and remember its rotation on press in a map and then just set rotation on move. This would make the item follow cursor with pixel accuracy.
In press:
itemRotations.clear(); // this is a QMap<QGraphicsItem*, qreal> const QPointF mousePos = mouseEvent->scenePos(); foreach (QGraphicsItem* item, selectedItems()) { const QPointF itemOrigin = item->sceneBoundingRect().center(); const qreal angle = qAtan2(mousePos.y() - itemOrigin.y(), mousePos.x() - itemOrigin.x()); item->setTransformOriginPoint(itemOrigin); itemRotations[item] = item->rotation() - qRadiansToDegrees(angle); }
and in move:
const QPointF mousePos = mouseEvent->scenePos(); foreach (QGraphicsItem* item, selectedItems()) { const QPointF itemOrigin = item->transformOriginPoint(); const qreal angle = qAtan2(mousePos.y() - itemOrigin.y(), mousePos.x() - itemOrigin.x()); item->setRotation(itemRotations[item] + qRadiansToDegrees(angle)); }
-
@Chris-Kawa, Hello and thank you so much for your answer!
But I don't get it. Here is code that you propose:void FigureScene::onRightMousePressEvent(QGraphicsSceneMouseEvent* mouseEvent) { itemRotations.clear(); const QPointF mousePos = mouseEvent->scenePos(); foreach (QGraphicsItem* item, selectedItems()) { const QPointF itemOrigin = item->sceneBoundingRect().center(); const qreal angle = qAtan2(mousePos.y() - itemOrigin.y(), mousePos.x() - itemOrigin.x()); item->setTransformOriginPoint(itemOrigin); itemRotations[item] = item->rotation() - qRadiansToDegrees(angle); } } void FigureScene::onRightMouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) { const QPointF mousePos = mouseEvent->scenePos(); foreach (QGraphicsItem* item, selectedItems()) { const QPointF itemOrigin = item->transformOriginPoint(); const qreal angle = qAtan2(mousePos.y() - itemOrigin.y(), mousePos.x() - itemOrigin.x()); item->setRotation(itemRotations[item] + qRadiansToDegrees(angle)); } }
Here is what happens:
Figure just running away right after movement.
Is it something wrong with setting position? -
I did something like that in a project of mine, but with a difference that the rectangle does not rotate in his center but rotates relative to a center defined in a first click position called commandInitialPos, then you do a second click to start rotating, then you move the mouse to rotate.
I am posting the relevant code I used may it can be helpfull for you to adaptthe relevant pseudo code and link to the project:
https://bitbucket.org/joaodeusmorgado/techdrawstudio/src/142960ab5c809ddcbd20fb40f294e01d85c850d5/qml/qmlEntities/EntityTemplate.qml#lines-117//first click - define the center of rotation onCommandCprStart: function(pos) { commandInitialPos = pos //assume that pos is the mouse click position }
//second click - start rotation position onCommandCprUpdate: function(pos, ....){ rotateStartPoint = pos //save the start rotation position //calculates and saves the start angle rotateStartAngle = mathLib.angleFromPoints(commandInitialPos, rotateStartPoint) rectP0aux = re.p0 // here I just saving the rectangle initiall position vertexs rectP1aux = re.p1 rectP2aux = re.p2 rectP3aux = re.p3 }
onCommandMtm: function(pos, ....){//this is equivalent to mouse move rotateUpdateAngle = mathLib.angleFromPoints(commandInitialPos, pos) var angle = rotateUpdateAngle - rotateStartAngle // lets do it baby, lets rotate it, yeahhhh, updates the rectangles vertices, which is the rotation re.p0 = mathLib.rotate2DFromPoint(commandInitialPos, angle, rectP0aux) re.p1 = mathLib.rotate2DFromPoint(commandInitialPos, angle, rectP1aux) re.p2 = mathLib.rotate2DFromPoint(commandInitialPos, angle, rectP2aux) re.p3 = mathLib.rotate2DFromPoint(commandInitialPos, angle, rectP3aux) }
QVector3D MathLib::rotate2DFromPoint(const QVector3D ¢er, const float &angle, const QVector3D &p) const { float cosAngle = qCos(angle); float sinAngle = qSin(angle); float x = cosAngle*p.x() - sinAngle*p.y() + center.x() - cosAngle*center.x() + sinAngle*center.y(); float y = sinAngle*p.x() + cosAngle*p.y() + center.y() - sinAngle*center.x() - cosAngle*center.y(); return QVector3D(x, y, p.z()); }
This is the rectangle rotating:
-