[Solved] Flip a QGraphicsSvgItem on its center point
-
Hi. I am new to Qt and evaluating its capabilities in advance of initiating a project, so I am really sorry if I post a dumb question. Does anyone know how I can flip an QGraphicsSvcItem on its horizontal or vertical centre axis. In other words, I have an SVG item displayed on the GraphicsView, its a triangle pointing upwards inside a square box, I was to flip it vertically so the triangle tip is now pointing downwards and the overall square stays in the same position on the GraphicsView. Just incase anyone suggests it, rotate(180) is not the solution, it needs to be a transformation of vertical co-ordinates, so like looking at a reflection in a mirror from the top or bottom.
I have found a way of doing it by using the scale() function
item->scale(-1,1);
which works but flips it centred on the top edge so I need to do that and then re-position, its not great but it works. I have tried to use setTransformOriginPoint() as I have done elsewhere for rotating the same object which works, but the scale method above does not. I am pretty sure I should be using transformations but I don't really understand how/when/where to apply this. How I am doing it would appear very inelegant...
Does any one have any ideas or examples I could go look at?
Thanks,
Gerry
-
I managed to solve this one myself with some more detailed debugging and experimentation. Here is how I done it, someone might find this useful.
Gerry
@
void MyGraphicsItem::flipHorizontal()
{
// Get the current transform
QTransform transform(this->transform());qreal m11 = transform.m11(); // Horizontal scaling qreal m12 = transform.m12(); // Vertical shearing qreal m13 = transform.m13(); // Horizontal Projection qreal m21 = transform.m21(); // Horizontal shearing qreal m22 = transform.m22(); // vertical scaling qreal m23 = transform.m23(); // Vertical Projection qreal m31 = transform.m31(); // Horizontal Position (DX) qreal m32 = transform.m32(); // Vertical Position (DY) qreal m33 = transform.m33(); // Addtional Projection Factor // We need this in a minute qreal scale = m11; // Horizontal flip m11 = -m11; // Re-position back to origin if(m31 > 0) m31 = 0; else m31 = (boundingRect().width() * scale); // Write back to the matrix transform.setMatrix(m11, m12, m13, m21, m22, m23, m31, m32, m33); // Set the items transformation setTransform(transform);
}
void MyGraphicsItem::flipVertical()
{
// Get the current transform
QTransform transform(this->transform());qreal m11 = transform.m11(); // Horizontal scaling qreal m12 = transform.m12(); // Vertical shearing qreal m13 = transform.m13(); // Horizontal Projection qreal m21 = transform.m21(); // Horizontal shearing qreal m22 = transform.m22(); // vertical scaling qreal m23 = transform.m23(); // Vertical Projection qreal m31 = transform.m31(); // Horizontal Position (DX) qreal m32 = transform.m32(); // Vertical Position (DY) qreal m33 = transform.m33(); // Addtional Projection Factor // We need this in a minute qreal scale = m22; // Vertical flip m22 = -m22; // Re-position back to origin if(m32 > 0) m32 = 0; else m32 = (boundingRect().height() * scale); // Write back to the matrix transform.setMatrix(m11, m12, m13, m21, m22, m23, m31, m32, m33); // Set the items transformation setTransform(transform);
}
@ -
Weird how the transformOriginPoint is seemingly ignored for scaling.
Still, you can simplify your code. I have done a sample with a vertical flip, and used three methods to do it.
@{
m_pScene = new QGraphicsScene(0,0,800,480,this);m_pView = new QGraphicsView(m_pScene, this); m_pView->setFrameStyle(QFrame::NoFrame); m_pView->setGeometry(0,0,800,480); m_pView->setAutoFillBackground(false); m_pView->show(); QPolygonF polygon; polygon << QPointF(100.0,250.0); polygon << QPointF(170.0, 350.0); polygon << QPointF(30.0, 350.0); QGraphicsPolygonItem* testItem = new QGraphicsPolygonItem(polygon); m_pScene->addItem(testItem); QGraphicsPolygonItem* transformedItem = new QGraphicsPolygonItem(polygon); transformedItem->setPen(QColor(Qt::red)); m_pScene->addItem(transformedItem); // Here the fun starts: QPointF itemCenter = transformedItem->mapToParent(transformedItem->boundingRect().center());
// // Method 1
// QTransform transform = QTransform();
// transform.translate(itemCenter.x(),
// itemCenter.y());
// transform.scale(1.0, -1.0);
// transform.translate(-itemCenter.x(),
// -itemCenter.y());
// transformedItem->setTransform(transform);// // Method 2
// transformedItem->setTransform(QTransform::fromTranslate(itemCenter.x(),
// itemCenter.y()),true);
// transformedItem->setTransform(QTransform::fromScale(1.0, -1.0),true);
// transformedItem->setTransform(QTransform::fromTranslate(-itemCenter.x(),
// -itemCenter.y()), true);// // Method 3
// transformedItem->translate(itemCenter.x(),
// itemCenter.y());
// transformedItem->scale(1.0, -1.0);
// transformedItem->translate(-itemCenter.x(),
// -itemCenter.y());
}@EDIT: used mapToScene, corrected to mapToParent
-
HI Asperamanca,
Thanks for the response, I don't fully understand how your solutions work but I like how tidy they look, I will try them out and see how I get on. The one thing they do not seem to cope with is if the object being flipped is already scaled (as mine are), you will see me taking care of that on line 17 and 26 in my example above, I guess will just need to do the same thing and pass that to the scale function.
Its a real shame the QTransform class does not have options to set each value in the matrix, that would make things much easier still.
Gerry
-
I started typing an explanation, went back to my sample, and I must say, there's something here I don't understand either. I'll think about it.
-
Ah, the way I remember it, you have to read combined transform operations from the last operation to the first. That is, the item is first translated (last operation) so it's center is exactly where the parent's center is (in this case, the top/left of the scene). Then it is scaled. Because it's centered, it's scaled in all directions at the same rate. And finally (first operation), you have to move it back where it belongs.