[Qt-interest] Unable to get sensible coordinate mappings

Andrew Hodgkinson ahodgkinson at endurancetech.co.uk
Mon May 18 17:14:34 CEST 2009


Earlier, Sean Harmer wrote:

> Can you post a small compilable example [...]

OK, I'll look into that if I have time; I've a very limited number of
hours allocated for this particular project unfortunately.

Meanwhile, David Boddie wrote:

> Out of interest, why don't you call showFullScreen() on the view?

It's just the usual problem of 'discovery' when it comes to APIs :-)

I'm new to Qt - only spent about 3 days programming to its API so far -
and I didn't know the call existed. None of the "examples/graphicsview"
Qt examples use it and the method is not described in:

   http://doc.trolltech.com/4.5/qgraphicsview.html

Of course, it turns out it's inherited from QWidget. For me personally
that wasn't an obvious place to look, because I'm still not used to
thinking in the Qt way of "Widget" = "Window". Even the "portedasteroids"
example, which really does look like it should be a full screen
application, does resize itself to full screen - so there was no reason
to believe that Qt even offered such a method. It may help others like me
in future if one or two examples ran in something other than a WIMP-like,
windowed, resizable state - at least those in the embedded version of the
library, anyway.

Good to know it's there, thanks; I can now replace a few lines of
slightly obscure code with a single simple call!

>> The QGraphicsView derivative [...] instantiates a derivative of
>> QGraphicsItem and adds it to the scene with "scene->addItem" [...]
>> to display a banner across the screen's width at about 1/3 of its
>> height. A nominal resolution of 1280x720 is chosen; if the device
>> is actually operating in a higher (e.g. 1920x1080) or lower (e.g.
>> 640x480) resolution, the UI will scale.
>
> It sounds like you expect it to scale, but does it actually scale?

Yes. The QGraphicsItem's paint() method calls "painter->setWindow" to
specify its coordinate range and "painter->setViewport" (specifying scene
coordinates) to map this range of item coordinates onto the scene. This
works fine.

>> [...] My scene coordinates are not scaled by the view and the
>> QGraphicsItem derivative merely sets its own local coordinate scope
>>  and a viewport. The viewport, of course, *is* set in scene
>> coordinates and debug output shows that these are the expected
>> values depending on the device size. So, scene()->sceneRect() is the
>> 'right size', but mapping any item rectangle to scene coordinates
>> with e.g. mapRectToScene() returns nonsensical results.
>
> I'm not convinced that setting the sceneRect property does what you
> expect, and some simple checks also led me to the conclusion that it
> didn't do what I expected, either. :-/

I wasn't being too clear, sorry.

The size of the rectangle returned by scene()->sceneRect(), in terms of
its x(), y(), width() and height() methods' return values, matches my
expectations - the pixel size of the virtual framebuffer is returned,
which given the full-screen nature of the scene, is the "right" answer.
I'm asking for the size via the scene rectangle object, so I expect it to
given an answer in its own coordinate space.

The painter routines are working; I paint over a coordinate range of
(0,0) to (1279,719) in item coordinates and the viewport settings mean
that the results of this are scaled as expected and painted onto the
scene in the 'right' places by Qt without any extra effort by me.

Trouble starts in the QGraphicsItem's "boundingRect" implementation.
Documentation says that the object should return a value in item
coordinates. Doing this leads to unexpected behaviour - only part of the
item gets drawn onto the scene. Upon investigation it became apparent
that the value seems to be (but this may be just an illusion /
side-effect) interpreted as scene coordinates, not item coordinates. If I
return simply the value of "scene()->sceneRect()" - i.e. make my
QGraphicsItem claim that its 'drawn-on area' spans the whole of the
scene, specified in scene coordinates - then I see the banner redrawn
correctly regardless of scene resolution.

If I try to map a rectangle to scene coordinates, the results are also
strange. For example, consider 'QGraphicsItem::mapRectToScene()'.

   "Maps the rectangle rect, which is in this item's coordinate system,
    to the scene coordinate system, and returns the mapped rectangle as
    a new rectangle (i.e., the bounding rectangle of the resulting
    polygon).

   "This function was introduced in Qt 4.5."

So given this:

   setPos( 0, 0 );
   QRectF mapped = mapRectToScene( 0, 0, 1280, 720 );

...we might expect the same rectangle as the scene coordinates viewport
back again, since the item's window is (0,0,1280,720) and the viewport
maps this to scene coordinates. But I don't get this - "mapped" values of
"x,y,width,height" are "0,0,1280,720" - the mapped scene coordinates
rectangle is equal in size and location to the item coordinates
rectangle. This is when I realised that the result arises because Qt
can't actually possibly know what viewport or window I'm going to use in
my 'paint()' method elsewhere in the QGraphicsItem code.

Since the ability to specify window and viewport is done through the
*painter* and NOT the QGraphicsItem then Qt can't actually do the mapping
it claims. The ability to specify window and viewport through the painter
and not the item seems at odds with the API from Qt 4.5 which says it
provides mappings between item and scene coordinates. No wonder the
return value of 'boundingRect' appears to be interpreted as if it were in
scene (or parent) coordinates. It couldn't be treated any other way.

> If you're happy with the idea of scaling up from a scene containing
> items placed within a 1280x720 rectangle then one thing you might want
> to try is to set a transform on the view, mapping scene coordinates to
> the screen geometry.

Painting/scaling etc. is working nicely and matches my expectations
based on the documentation. However, to get it to work perfectly the
return value I must provide from the QGraphicsItem's "boundingRect"
method is strange and all of the item-to-scene coordinate mapping methods
return strange values. And in fact, I don't see how they could ever work.
This is the part I don't understand.

>> [1] You will note that the example implementation of 'boundingRect'
>> given in the method documentation is correct, while the example
>> given in the 'details' introduction section is incorrect [...]
>
> Agreed. I'll fix that.

Ta.

-- 
Andrew Hodgkinson, Endurance Technology
Land line: 01223 369 408, mobile: 07855 866 780
Registered Office: 5 Marine Drive West, Bognor Regis, W. Sussex, PO21 2QA



More information about the Qt-interest-old mailing list