PDA

View Full Version : Rotating canvas item on its own center



cbeall1
5th March 2006, 17:05
Hi,
I'm trying to rotate several canvas items around their own center. I read on this forum and in other places that I need to translate the painter, rotate it, paint on it, and then restore it to its former state. I've tried this (or so I think), but I must be missing something. The rotation doesn't work properly, and with the painter translation/rotation code added, even boxes with a rotation of 0 show up in the wrong place.
I've attached two screenshots: The first of the boxes without any translation/rotation code used. And the second code shows what happens when I add the translate/rotate funtions. Notice that even the unrotated boxes are translated, but they should be in exactly the same place as in the first screenshot. (The images are the same scale). The rotated boxes are placed at the same coordinates as the unrotated ones, so they should overlap if the code worked properly. Rotation is 55 and 19 degrees.

http://www.ece.utk.edu/~beall/original.png
http://www.ece.utk.edu/~beall/rotation.png

Here is my code from drawShape


void MSPBox::drawShape(QPainter &painter)
{
painter.translate(x(), y());
painter.rotate(rotate);

QCanvasRectangle::drawShape(painter);
painter.drawText(rect(), AlignCenter, text());

painter.rotate(-rotate);
painter.translate(-x(), -y());

cout << rotate << " is the angle" << endl;
}

Thanks for any suggestions!

wysota
5th March 2006, 17:23
You should rotate the painter to be exactly in the centre of your item.


painter.save();
painter.translate(x()+width()/2, y()+height()/2);
painter.rotate(rotate);
painter.drawRect(-width()/2, -height()/2, width(), height());
painter.drawText(-width()/2, -height()/2, width(), height(), AlignCenter, text());
painter.restore();

BTW. You can get some artifacts if you don't provide a correct (rotated) bounding box for your item.

jacek
5th March 2006, 17:24
The problem is that QRect holds, apart from dimension, also the position. So either you have to use only width and height, or add another two translations.

Try this:
void MSPBox::drawShape( QPainter&painter )
{
QWMatrix old( painter.worldMatrix() );

const int dx = x() + width() / 2;
const int dy = y() + height() / 2;

painter.translate( dx, dy );
painter.rotate( rotate );
painter.translate( -dx, -dy );

QCanvasRectangle::drawShape( painter );
painter.drawText( rect(), AlignCenter, text() );

painter.setWorldMatrix( old );

cout << rotate << " is the angle" << endl;
}

cbeall1
5th March 2006, 23:48
Thanks for both replies. Jacek, your method worked :D

Now I have another question about using the canvas from multiple threads. I have a multithreaded server that will be receiving coordinates from multiple clients and I want to visualize this in real-time (I will move the boxes, and change the rotation). What do I need to do to make this threadsafe? I know that the canvas itself is just a data structure, so is it ok to add things to it/move things from any thread (using a mutex lock, of course), and only the update has to be called from the main GUI thread? I can't find any detailed info on this issue in the documentation.
Thanks!

wysota
6th March 2006, 00:41
What do I need to do to make this threadsafe?
Use custom events to send data to the main thread which will modify canvas structures. Don't attempt to modify them from another thread! No matter if you use mutexes or not. You'd have to lock all operations on the canvas, including all its events, so it's better to use custom events.