PDA

View Full Version : QGraphicsScene, QGraphicsPath, and a lot of shapes...



fred_from_france
4th July 2012, 15:37
Hi Everybody,

I try to draw multiple polygons inside a QGraphicsPath, itself inside a QGraphicsScene.
My problem is that i have more that millions of polygons to draw. I know that in openGL/MFC, FPS is more than 10 and that's enough for my application.
Now, in Qt.... it take several seconds...

I think it's because QGraphicsPath are "intelligent" objects with a lot of interesting properties, but that also take a long time to draw if they are a lot...

But i would like to keep QGraphicsScene properties, like setSceneRect ( to delimit draw ) and scale ( to change a zoom for example ).

Can we combine QGraphicsScene / Qpainter and Scaling properties ????

thanks for your help !
Fred

high_flyer
4th July 2012, 15:57
n Qt.... it take several seconds...

I think it's because QGraphicsPath are "intelligent" objects with a lot of interesting properties, but that also take a long time to draw if they are a lot...

Well, as you can read in the first paragraph of the QGraphics Framework docs:

Graphics View uses a BSP (Binary Space Partitioning) tree to provide very fast item discovery, and as a result of this, it can visualize large scenes in real-time, even with millions of items.
If you don't believe the trolls, you can test the examples that demonstrate this very thing.

Conclusion:
The performance issue *probably* has to be in your code.


Can we combine QGraphicsScene / Qpainter and Scaling properties ????
Its all here:
http://qt-project.org/doc/qt-4.8/graphicsview.html

d_stranz
4th July 2012, 20:22
Conclusion:
The performance issue *probably* has to be in your code.


As a test of the QGraphics framework, and in particular, the ability to use BSP for fast sub-item discovery, I implemented a data plotting widget that is a somewhat simplified version of Qwt. In particular, the plotting of the actual curves within the scene was implemented using a QPainterPath inside a QGraphicsPathItem. Some of my curves contain 100,000 or more points, and may displayed as connected line segments or as vertical, unconnected "sticks".

The algorithm was implemented so that when the curve data was set, the QPainterPath and QGraphicsPathItem were rebuilt from primitives (moveTo, lineTo,etc.) with pen changes as needed when different parts of the curve had different colors. Once the QGraphicsPathItem was updated in the scene, the curve's paint() method was essentially a no-op, because the path draws itself.

I ran out of memory long before I could construct a path with 100,000 line segments in it. That leads me to seriously doubt this statement:


Graphics View uses a BSP (Binary Space Partitioning) tree to provide very fast item discovery, and as a result of this, it can visualize large scenes in real-time, even with millions of items.

What could be simpler than constructing a path with a large number of line segments?

After trying several ways to work around this, I finally gave up, got rid of the QPainterPath and implemented a QGraphicsItem to draw the line segments manually in the paint() method. Turning on the DeviceCoordinateCache flag enabled good performance for zooming and other operations.

The 40000 chips demo is not a good example for this issue, because it does not use QPainterPath, but draws each chip at the appropriate LOD on each paint() call. At the most coarse LOD, it is simply drawing 6 lines for each chip, so certainly it is blindingly fast. And at the finest LOD, there is just a bit of text and only a chip or two is visible. Each chip has only about 100 bytes of internal storage in addition to that used by QGraphicsItem, so even 40K of them is only 4 MB of memory plus the base class overhead - tiny.

My conclusion is that the QGraphics framework has its best performance when the primitives it must draw are simple. So if you have a million little rectangles, and each of them is a QGraphicsItem-based item, you will get great performance. But if you try to add those same 1 million rectangles to a QGraphicsPathItem, the performance will be terrible, as the OP observed.

I may try re-implementing my curve plotting class as a set of QGraphicsLineItem instances to see if that changes the performance. This seemed to me to be very wasteful - to create a new class instance for every segment, but maybe it will allow the BSP and the framework's clipping algorithms to work more efficiently.

high_flyer
5th July 2012, 10:30
After trying several ways to work around this, I finally gave up, got rid of the QPainterPath and implemented a QGraphicsItem to draw the line segments manually in the paint() method. Turning on the DeviceCoordinateCache flag enabled good performance for zooming and other operations.
Had exactly the same problem (way, way back), solved it exactly the same way.
Since the solution was to get rid of QPainterPath, which is NOT part of the QGraphics Framework, and relay purely on the Grpahics FW side - which proves that Graphics FW actaully is much more perfomant, then using the regular painter.
I admit the QPainterPath bit escaped me when I read the OP post . (but I am reading the posts during work, so quite fast).


The 40000 chips demo is not a good example for this issue, because it does not use QPainterPath, but draws each chip at the appropriate LOD on each paint() call. At the most coarse LOD, it is simply drawing 6 lines for each chip, so certainly it is blindingly fast. And at the finest LOD, there is just a bit of text and only a chip or two is visible. Each chip has only about 100 bytes of internal storage in addition to that used by QGraphicsItem, so even 40K of them is only 4 MB of memory plus the base class overhead - tiny.

Well, when you go about dealing with millions of items, I would expect to have performance issues no matter what system I am working with, and would go for very simple items.
Have millions of complex items on one side, and expecting miracles on the other (have them shown in a millisecond) at the moment at least, is not really sensible.


One more tip to OP:
You can use OpenGL (hardware acceleration) if you set your viewport to a QGLWidget.

wysota
5th July 2012, 11:05
As Daniel said, QPainterPath is not part of Graphics View framework, it doesn't use BSP and can't benefit from what graphics view offers. If one runs out of memory (quite hard for me to believe it unless resources are limited by the system somehow) then we can't circumvent that. However to improve performance in GV, it is enough to split the painter path into separate items, as far as I rememeber, it makes a big difference. Caching is a must as well.

I just ran this small test program:


#include <QtGui>
#include <iostream>

int main(int argc, char **argv) {
QPainterPath path;
for(int i=0;i<100000;++i) {
std::cerr << "Iteration " << i << "...";
path.lineTo(qrand() % 1000, qrand() % 1000);
std::cerr << "Done" << std::endl;
}
std::cerr << "Path ready" << std::endl;
// let's sleep now
QSemaphore s(0);
s.acquire();
return 0;
}

The path was constructed fine, the system reports the following memory usage:

VmPeak: 89104 kB
VmSize: 89104 kB
VmLck: 0 kB
VmPin: 0 kB
VmHWM: 7240 kB
VmRSS: 7240 kB
VmData: 4468 kB
VmStk: 136 kB
VmExe: 8 kB
VmLib: 22452 kB
VmPTE: 192 kB
VmSwap: 0 kB

One can see the peak memory usage is 90MB, with 22MB taken by libraries and only 4.5MB taken by the heap. This gives 45 bytes per path segment (on a 64b system).

d_stranz
5th July 2012, 19:28
One can see the peak memory usage is 90MB, with 22MB taken by libraries and only 4.5MB taken by the heap. This gives 45 bytes per path segment (on a 64b system).

Hmm, this is interesting. As I think about this more, it is entirely possible that the memory problems I saw are completely unrelated to QPainterPath and the GV framework. The program in which these large plots are displayed is a scientific data analysis application, which is manipulating large data sets in memory (240 MB just for the raw data alone, not even considering all of the annotation for the results). I have recently started to experience memory issues, where the app is getting into the 1GB range for heap usage. It is a 32-bit Windows app which can't be ported to 64-bit yet because of dependence on third-party DLLs which are only available in 32-bit.

When I first implemented my plotting tool and was looking at smaller data sets, performance was just fine using QPainterPath. My (probably incorrect) assumption when I started having problems with large data sets was that it was a QPainterPath issue.

Needs further investigation on my part, I think. I had high hopes for using the object tracking features of the GV framework.