PDA

View Full Version : How to reflect QGraphicsItem?



Radagast
21st June 2008, 13:54
I have a task to reflect one or more QGraphicsItems relatively to a line. And this operation should be performed correctly again and again to the mirrored items.
I've read a lot about QTransform and affine transformations and realized that I need 1) rotate; 2) scale (1;-1) 3) translate..somewhere
that's what I have now:


QGraphicsLineItem* line = qgraphicsitem_cast<QGraphicsLineItem*>(curItem);
double x1 = line->line().x1();
double y1 = line->line().y1();
double x2 = line->line().x2();
double y2 = line->line().y2();
double angle = atan((y2 - y1)/(x2 - x1));
QMessageBox::warning(0, "Scribble", "angle "+QString::number(angle*180/acos(-1.0)));
group->rotate(angle*180/acos(-1.0));
group->scale(1,-1);
group->rotate(-angle*180/acos(-1.0));
foreach (QGraphicsItem* item,group->children())
item->setTransform (group->transform(),true);
destroyItemGroup(group);
removeItem(line);
delete line;
curItem = NULL;

This is steps 1-2 as I don't know how to translate items correctly regardless of their pos() and previous mirror operations. At least the resulting angle of mirrored item seems to be right, but not after the second reflection :confused:
"curItem" holds the line of the mirror (it's temporal and is erased after the operation), "group" of items to be reflected is created elsewhere.
Thanks in advance for all your help. I attached the whole project (Qt 4.3.2, Visual Studio 2005 .vcproj, but without a .pro, sorry)

aamer4yu
21st June 2008, 20:03
Will have to see into ur prob,,,, seems interesting.
Meanwhile you can have a look at this (http://www.qt-apps.org/content/show.php/PictureFlow?content=75348) :)

Radagast
21st June 2008, 21:43
The link has no deal with my question

wysota
21st June 2008, 22:08
As far as I understand mirroring without taking a piece of paper and experimenting with calculations, mirroring is equal to scaling with a scale of (1, -1) or (-1, 1) where the scale axis (x or y) matches the mirror line. Therefore all you need to do can be summarized by three points:
1. transform the coordinate space so that one of its axis matches the line of the mirror
2. scale relative to the chosen axis
3. transform the coordinate space back to its original state

Remember that you want to move the coordinate space and not the item, so you should probably invert all the matrices if you want to apply them to the item and not the world.

I suggest you start by creating a custom widget derived from QWidget that will consist of a shape (even hardcoded), a mirror line (hardcoded) and a paint event that will transform the painter and draw the mirrored shape. This will let you verify my assumptions and should allow you to do the reverse mapping you need with the graphics view architecture.

Radagast
22nd June 2008, 07:00
Thanks but I need reflecting not only relatively to an axis, but to ANY line, given by 2 points.

wysota
22nd June 2008, 08:33
See points 1. and 3. of my previous post.

Radagast
26th June 2008, 17:29
I still keep on failing with this task...
In the constructor of the scene I've placed 2 lines

QGraphicsLineItem* line = new QGraphicsLineItem(0,0,400,0);
QPen pen(Qt::SolidLine);
pen.setWidth(2);
pen.setColor(Qt::black);
line->setPen(pen);
addItem(line);
line = new QGraphicsLineItem(0,0,0,400);
addItem(line);
they'll be axises. Also i track mouse coordinates

QPoint p = mouseEvent->scenePos().toPoint();
QGraphicsView* view = views()[0];
QMainWindow* parent = qobject_cast<QMainWindow*>(view->parentWidget());
parent->statusBar()->showMessage(QString::number(p.x())+" ; "+QString::number(p.y()));
why when I just create simple line with dots (10,10) and (60,10) and then call
item->translate(0, 20);
it moves to the position (10,50) and (60,50) ?!

Well, that's not essential for me at this moment...
After hours of mind torturing I've written this:

QGraphicsLineItem* line = qgraphicsitem_cast<QGraphicsLineItem*>(curItem);
double x1 = line->line().x1();
double y1 = line->line().y1();
double x2 = line->line().x2();
double y2 = line->line().y2();
double angle = atan((y2 - y1)/(x2 - x1));
foreach (QGraphicsItem* item,group->children())
{
QTransform tozero;
tozero.translate(-x1/2, -y1/2);
tozero.rotateRadians(angle);
QTransform mirror;
mirror.scale(1, -1);
QTransform back;
back.rotateRadians(-angle);
back.translate(x1/2, y1/2);
item->setTransform(tozero*mirror*back,true);
}
It works perfectly relativly to any line that is paralle to 0x, but if it's not the item flies away =( help me plz!

wysota
26th June 2008, 19:49
So why not try my approach? :)

Radagast
26th June 2008, 20:26
wysota
as far as I understand, it IS your approach :)

wysota
26th June 2008, 21:47
Certainly not. I told you to transform the viewport and not the item. I really suggest leaving graphics view aside now and finding proper transformations using QPainter - it should be much simpler. Then you can adjust the code for the graphics view architecture. Currently you are just guessing.

Radagast
26th June 2008, 21:57
hmm but why should I transform the viewport? o_O I can have many items in the viewport and not all of them must be mirrored, but only the selected ones.
And how the "QPainter decision" can be simpler...then I'll have to convert it to the "GVF decision". I almost have this decision, it almost works, I'm sure the trouble is very tiny, but I can't see it ((
anyway thanks for your attention...

wysota
26th June 2008, 22:03
Yes, you are right - almost.

Radagast
26th June 2008, 22:34
So if you clearly see my error, why don't just tell it? :( and get one more "thanks"
u see I'm not of the ones who ask to do everything for them, I did my best!

wysota
26th June 2008, 22:37
I don't see your error. I suggest you experiment with a simpler world, but you know better, so stick to your approach.

Radagast
26th June 2008, 22:46
even if a man with such a long operational experience as you have (as I suggest) doesn't see the error...how wil I see it? it's my 1st program in Qt.

wysota
26th June 2008, 22:52
Maybe because I didn't look for it.