PDA

View Full Version : turn off collision detection?



Deacon
31st October 2008, 22:12
Hello,

I'm working with PyQt4.4, and I'm looking for any means to turn off collision detection in the QGraphicsView infrastructure.

I'm loading hundreds of thousands of objects that I've reimplemented collision detection for. Its really fast except for tons and tons of .boundingRect() calls to my QGraphicsItem objects. I'm setting the sceneRect myself too, so I don't think these boundingRect() calls are necessary for any reason. Is there some way to turn them off?

Thanks much,

Deacon Sweeney

wysota
1st November 2008, 09:52
boundingRect() is necessary for the architecture to know which items to repaint when a particular area needs refreshing. It also defines a local coordinate system for each item, so unless you want to strip away everything the graphics view gives you (I mean all the benefits), it will be hard to get rid of boundingRect() and collision detection. On the other hand if you want to get rid of them, maybe you shouldn't use graphics view at all?

Deacon
2nd November 2008, 17:19
Hi wysota, thanks for your response.

> boundingRect() is necessary for the architecture to know which items to repaint when a
> particular area needs refreshing.

I already know which QGItems I need to repaint, and I've tried to force to update just the boundingRect of these items, through QGraphicsItem.update(QRect) and QGraphicsScene.update(QRect) calls. But I still encounter an onslaught of unnecessary boundingRect() calls, that kill my performance.

> It also defines a local coordinate system for each item,
> so unless you want to strip away everything the graphics view gives you (I mean all
> benefits), it will be hard to get rid of boundingRect() and collision detection.

So each QGraphicsItem.paint() call requires a boundingRect() call. I can dig that because I can tell the QGraphicsView framework which areas to repaint. Going back to my .update() use above, I'm still not clear why the .update(QRect) function can not just redefine the local coordinate system starting at the .x() .y() of the QRect I pass to .update(). Can I just repaint that QRect another way? is there some other intended functionality of applying this parameter to the update function?

> On the other
> hand if you want to get rid of them, maybe you shouldn't use graphics view at all?

I disagree completely. There's lots of great stuff under the hood, that Indexing seems to kill the performance of when more than a few tens of thousands of QGraphicsItems are present in the scene. So an option is offered to turn indexing off, but no option to reimplement where to repaint? It just seems like not a very big step to uncover some real performance flexibility.

Thanks again for your time.

Deacon

Methedrine
2nd November 2008, 22:28
According to the docs it is possible to specify the following in order to prevent QGraphicsView from doing collision detection:



QGraphicsView myView;
myView.setViewportUpdateMode(QGraphicsView::NoView portUpdate);


Or am I misunderstanding something here? :-)

Deacon
3rd November 2008, 18:35
Thanks Methedrine, so that gets rid of my boundingRect() calls, but I had discounted this approach because it also kills the repaint function for QGraphicItem objects that I've called .update() on.

I thought I might be able to apply the scene.invalidate() functions, but I still have to call QGraphicsScene.update() after each to get graphics updates, which ends up calling .boundingRect the same absurd number of times as when ViewportUpdate is on.

Is there another way to update just a single QRectF when indexing and viewportUpdate are both turned off?

Thanks,

Deacon

wysota
3rd November 2008, 19:23
Hi wysota, thanks for your response.

> boundingRect() is necessary for the architecture to know which items to repaint when a
> particular area needs refreshing.

I already know which QGItems I need to repaint, and I've tried to force to update just the boundingRect of these items, through QGraphicsItem.update(QRect) and QGraphicsScene.update(QRect) calls. But I still encounter an onslaught of unnecessary boundingRect() calls, that kill my performance.

The fact that you update some part of the view doesn't mean all items present there get repainted.That's where the bounding rect comes in. The view tracks regions that have been changed and repaints only those items that intersect the region. If you disable automatic updates, you have to do all the updating stuff yourself (including calling the painting routine of each item you want painted).

If you move items often, it might be good for you to disable indexing, maybe that is what is degrading your performance.



> It also defines a local coordinate system for each item,
> so unless you want to strip away everything the graphics view gives you (I mean all
> benefits), it will be hard to get rid of boundingRect() and collision detection.

So each QGraphicsItem.paint() call requires a boundingRect() call.
No. But anyway it's good to cache the bounding rect instead of calculating it during every call to this method.


I can dig that because I can tell the QGraphicsView framework which areas to repaint. Going back to my .update() use above, I'm still not clear why the .update(QRect) function can not just redefine the local coordinate system starting at the .x() .y() of the QRect I pass to .update().
The local coordinate system has nothing to do with the area you repaint.


Can I just repaint that QRect another way?
Yes, you can call the paint routine of each item occupying that area yourself. Before doing that you'll have to provide necessary transformations for the painter to reflect the proper coordinate system.


> On the other
> hand if you want to get rid of them, maybe you shouldn't use graphics view at all?

I disagree completely. There's lots of great stuff under the hood, that Indexing seems to kill the performance of when more than a few tens of thousands of QGraphicsItems are present in the scene. So an option is offered to turn indexing off, but no option to reimplement where to repaint? It just seems like not a very big step to uncover some real performance flexibility.

What great stuff are we talking about? Most "great stuff" in graphics view concerns determining what to repaint :)

What exactly is your usecase? How come do you think you know better what to repaint than the GV architecture? Could you explain this?

Methedrine
3rd November 2008, 21:02
Thanks Methedrine, so that gets rid of my boundingRect() calls, but I had discounted this approach because it also kills the repaint function for QGraphicItem objects that I've called .update() on.

I thought I might be able to apply the scene.invalidate() functions, but I still have to call QGraphicsScene.update() after each to get graphics updates, which ends up calling .boundingRect the same absurd number of times as when ViewportUpdate is on.

Is there another way to update just a single QRectF when indexing and viewportUpdate are both turned off?

Thanks,

Deacon

Why are you calling update on the QGraphicItems by yourself, if I may ask? What are you trying to achieve? You could certainly create a smaller scene from your already pre-processed QGraphicItems, but to me it currently sounds like you are actually re-inventing QGraphicsView then.

Deacon
4th November 2008, 00:50
The fact that you update some part of the view doesn't mean all items present there get repainted.That's where the bounding rect comes in. The view tracks regions that have been changed and repaints only those items that intersect the region. If you disable automatic updates, you have to do all the updating stuff yourself (including calling the painting routine of each item you want painted).

If you move items often, it might be good for you to disable indexing, maybe that is what is degrading your performance.


So I have to actually call the paint() function, and not rely on .update() or .invalidate() because all that stuff is turned off. Ok.


Yes, you can call the paint routine of each item occupying that area yourself. Before doing that you'll have to provide necessary transformations for the painter to reflect the proper coordinate system.

What exactly is your usecase? How come do you think you know better what to repaint than the GV architecture? Could you explain this?

Sure, its a panel of tiles that wrap the window with window resizes. I could have gotten away with the QTableView but I was worried that it's not quite as flexible as the GV system.

Deacon
4th November 2008, 00:53
Why are you calling update on the QGraphicItems by yourself, if I may ask? What are you trying to achieve? You could certainly create a smaller scene from your already pre-processed QGraphicItems, but to me it currently sounds like you are actually re-inventing QGraphicsView then.

I'm just trying to improve performance by limiting graphical updates to the items, which know when they need updated. When I allow scene.update() to do the job it goes through thousands of .boundingRect() calls, making any dynamic interaction with the screen take at least half of a second. Yes it is definitely reinventing much of QGV but its done already so I guess Ijust have to force paint() calls to make this work.

Deacon
23rd December 2008, 00:31
[Weeks Later...]



[QUOTE=Deacon;84597] So I have to actually call the paint() function, and not rely on .update() or .invalidate() because all that stuff is turned off. Ok.



Qt 4 issues warnings when the paint function is called outside of a paintEvent, so this approach did not work for me and I've found a better way.


I've recently discovered two rendering commands that DO work even when setViewportUpdateMode .( QtGui.QGraphicsView. NoViewportUpdate ) has been called; qgrapics_view_object.viewport().update() and .viewport().repaint(x, y, w, h)... I've so far found these to offer a very efficient alternative to the build-in paint event handling for some must-be-immediate events. This applies mostly because of my somewhat unusual situation where I can (and must) be able to recalculate those numbers pretty quickly.

Just thought I'd share back a little.

wysota
23rd December 2008, 00:43
Correct me if I'm wrong, but calling update() or repaint() on the graphics view's viewport is intercepted by the graphics view using an event filter and redirected to the usual graphics view update mechanism...

Deacon
23rd December 2008, 18:05
Correct me if I'm wrong, but calling update() or repaint() on the graphics view's viewport is intercepted by the graphics view using an event filter and redirected to the usual graphics view update mechanism...

seems like GV.viewport().update() reroutes back to the usual update system. I just was not previously aware of anything that renders when NoViewportUpdates is on. Only under the NoViewportUpdate setting does my CPU to not grind away at 50% the whole time my app is running.


.repaint() I'm pretty sure does not go through .update().

in __init__():

self.setViewportUpdateMode(QtGui.QGraphicsView.NoV iewportUpdate)


then in my QGraphicsItem:

def updateNow(self):
b = self.bRect
self.parent.viewport().repaint(b.x(), b.y(), b.width(), b.height())

works. So I guess its not going through the normal update() mechanism.

Is this not the way its supposed to be?

Deacon

wysota
30th December 2008, 11:06
The only difference between update() and repaint() should be the former uses QCoreApplication::postEvent() to post a paint event and the latter uses QCoreApplication::sendEvent() to execute the same event without going through the event queue. So the result in both cases should be identical with the only difference that update() makes a deferred call and repaint() forces an immediate redraw.

Deacon
30th December 2008, 18:37
and that is why .repaint works while viewport updates are turned off. That makes sense. Thanks for clarifying.

Deacon
30th December 2008, 18:37
this thread preceeds:

http://www.qtcentre.org/forum/f-qt-programming-2/t-cpu-churning-with-update-also-scrolling-with-noviewportupdate-17787-post88700.html#post88700