I have been reviewing and assessing Qt for a small software project. Having only spent a small amount of time with the development environment I have managed to create a small program that allows me to draw 2D graphics. I have been using C++ for many years and for GUI related work I have mostly used MFC. I like C++ for UI’s because it makes programs that are fast and responsive, I plan to post an article comparing .NET, Java and C++ for building desktop applications in the near future.

Back to the library evaluation, one of the things I needed to be able to do was to flip a vector graphic item either horizontally or vertically around its center axis, meaning after the flip the object should be in the exact same place on the world view as it was before the transformation. There are built in functions for doing rotations around a center point but not this specific function. The 2D graphics system in QGraphicsView/QGraphicsItem uses matrix transforms which are at best very complicated – you need a good understanding of mathematics and a lot of patience to be able to comprehend this staff – I needed to understand this: –

WTF! – does this mean anything to you? No, me either, thank heavens for those bright folk that work this stuff out for us…. if you do need to know more about the maths behind this you check out this document: http://en.wikipedia.org/wiki/Transformation_matrix which from what I can tell gives you the explanations, but I have to confess I switched off very quickly.

Having read that document I wanted to give up – too hard – or I am too lazy, either way i got a beer from the fridge and got nowhere – but not being one to give up so easy I decided that instead of learning the maths I would go back to debugging and good old-fashioned trial and error! Actually the Qt library has done most of the hard work, the fact that I can achieve my goal with a little bit of debugging, trial and error is testimony to that.

I did search around for examples and while there were lots of questions about this, there would appear to be very little in the way of answers, perhaps I am just a maths luddite or maybe there are many more people that shy away from the maths involved and say nothing 🙂 In the end I came up with this which appears to work very well, and given there would not appear to be much information out there on this particular requirement, I thought I should make this example available. Having all the individual variables makes for easy debugging, you can see what’s going on. I also included a simple debug function for dumping the transform matrix data.

+1 for Qt – check it out http://qt.nokia.com/products/

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); } void dump_transform(QTransform& t, const char* name) { qreal _m11 = t.m11(); // Horizontal scaling qreal _m12 = t.m12(); // Vertical shearing qreal _m13 = t.m13(); // Horizontal Projection qreal _m21 = t.m21(); // Horizontal shearing qreal _m22 = t.m22(); // vertical scaling qreal _m23 = t.m23(); // Vertical Projection qreal _m31 = t.m31(); // Horizontal Position (DX) qreal _m32 = t.m32(); // Vertical Position (DY) qreal _m33 = t.m33(); // Addtional Projection Factor qDebug("================ %s ==================", name); qDebug("m11: %f, m12: %f, m13: %f", _m11, _m12, _m13); qDebug("m21: %f, m22: %f, m23: %f", _m21, _m22, _m23); qDebug("m31: %f, m32: %f, m33: %f", _m31, _m32, _m33); }