PDA

View Full Version : QGraphicsItem coordinate systems



d_stranz
15th June 2011, 17:26
I am having a miserable time trying to understand how coordinate systems work in the Graphics / View architecture. I've read everything I can find, but none of the examples seem to apply to my situation.

For discussion purposes, assume I have objects that I want to represent as QGraphicsItem instances. These items have world-based coordinates in centimeters. I want to draw them (in the QGraphicsItem :: paint method) using their centimeter dimensions.

I want to put them in a scene that has dimensions in meters (or feet, or miles, or anything else except cm). For argument's sake, say the scene has a scene rect 3 m square.

So if I have an object that is a square 100 cm x 100 cm, in its paint() method I call


painter->drawRect( QRectF( 0, 0, 100, 100 ) );

In my view, I get a rectangle 100 *pixels* square, no matter what I try to do with transforms, scaling, or anything else in the scene to map from item to scene coordinates.

Every example I have seen appears to use pixel coordinates everywhere (view, scene, items), with no examples on how to properly use transformations.

Can anyone point me to source code for a non-trivial Graphics / View application that uses world coordinates for items, with proper mapping to scene and view? I am thinking that something like a CAD or scientific plotting application would show me what I need to do.

Thanks in advance for any help.

wysota
15th June 2011, 17:44
The default scene-view scale is 1:1 thus one logical unit in scene coordinates corresponds to one pixel in the view coordinates. If you want to change that, you need to "zoom" the view on the scene using QGraphicsView::scale() or similar. It's similar between the scene and the item. If you want an item 100cm wide and the scene is scaled in metres then you need to scale down the item 100 times so that 1 logical unit of item coordinates becomes 1/100 logical units of scene coordinates. If I'm not clear enough then feel free to ask for further explanations.

d_stranz
15th June 2011, 18:28
The default scene-view scale is 1:1 thus one logical unit in scene coordinates corresponds to one pixel in the view coordinates.

Yes, got that. I actually just figured out what I was doing wrong.



QGraphicsScene * scene = new QGraphicsScene();
scene->setRect( 0, 0, 200, 200 );

// MyGraphicsItem constructor sets initial bounding rect to (0, 0, 1000, 100)
MyGraphicsItem * item = new MyGraphicsItem();

item->setPos( 10, 10 );

// Scale x coordinate only (y coordinate *is* pixels)
QGraphicsScale scale;
scale.setXScale( scene->width() / item->boundingRect().width() );

QList< QGraphicsTransform * > transforms;
transforms.push_back( &scale );
item->setTransformations( transforms );

// ...


I determined that my mistake was that the QGraphicsScale instance can't be created on the stack (or if it is, its lifetime must be at least the same as the QGraphicsItem that uses it). Changing the QGraphicsScale instance to a heap-allocated pointer fixes the problem, and I now get a properly scaled line.

So, I think I'm on my way after 3 days of trying to understand and getting a bloody forehead from pounding it on the desk.

One additional question: Can QGraphicsTransform instances be shared among several items, or are they "owned" by the item after calling setTransformations()?

wysota
15th June 2011, 19:27
I'd have to look into Qt's code. But it is certainly safer to have a 1:1 mapping between the transform and the item.