PDA

View Full Version : Drawing grids efficiently in QGraphicsScene



Gopala Krishna
11th February 2007, 12:02
Hi,
I need to draw grids in my app. The problem now is performance. The components move jerkily after adding grids. I confirmed from the profiler that scene::drawBackground() was most cpu consuming method.
Can anyone please help me out ? Is there any techinique like caching or something ?
Here is my code

void SchematicScene::drawBackground(QPainter *p, const QRectF& crect)
{
const QRectF rect = crect.normalized();
p->save();
p->setPen(QPen(Qt::lightGray,1));
int l = int(rect.left());
l -= (l % 10);

int r = int(rect.right());
r -= (r % 10);
if(r < int(rect.right()))
r += 10;

int t = int(rect.top());
t -= (t % 10);

int b = int(rect.bottom());
b -= (b % 10);
if(b < int(rect.bottom()))
b += 10;

for( int x = l; x <= r; x+=10)
for( int y = t; y <= b; y+=10)
p->drawPoint(x,y);

p->restore();
}

wysota
11th February 2007, 13:26
You can always make the grid "lighter" by reducing a number of points drawn.

Gopala Krishna
11th February 2007, 15:40
You can always make the grid "lighter" by reducing a number of points drawn.
Hey thats a good tip and it did improve the performance when I made grid spacing 20 instead of 10 . But I guess 10px spacing grid is neccessary for my app.

I found the documentation for QGraphicsView::CacheBackground and that showed good improvement even for grid spacing of 10px. But that dirties the grid when I scroll the view What can I do about this ?

wysota
11th February 2007, 19:22
What if you implemented the grid by placing points as QGraphicsItems instead of using drawBackground() ? This should speed up the rendering provided that only a part of the scene is visible at once.

Gopala Krishna
11th February 2007, 20:02
What if you implemented the grid by placing points as QGraphicsItems instead of using drawBackground() ? This should speed up the rendering provided that only a part of the scene is visible at once.

This surely is good thinking in different direction. But will that be applicable to my case ?
This is because the view is resizable and the user can easily resize according to him and I resize scene if the view is larger than scene. In that case the scene rect can be more than 1024*800 which means more than 8000 point items. And this is not maximum!
Do you think its really worth a try in such cases ? Doesn't this lead to explosion in memory usage ??

Bitto
11th February 2007, 20:30
Using a cosmetic 0-width pen avoids unnecessary tesselation, calling QPainter::drawLines() is usually faster than QPainter::drawLine(), and using QGraphicsScene::drawBackground() is almost always faster than creating items. Here's an example that performs pretty well for me:



class GridScene : public QGraphicsScene
{
public:
GridScene(qreal x, qreal y, qreal w, qreal h)
: QGraphicsScene(x, y, w, h)
{ }

protected:
void drawBackground(QPainter *painter, const QRectF &rect)
{
const int gridSize = 25;

qreal left = int(rect.left()) - (int(rect.left()) % gridSize);
qreal top = int(rect.top()) - (int(rect.top()) % gridSize);

QVarLengthArray<QLineF, 100> lines;

for (qreal x = left; x < rect.right(); x += gridSize)
lines.append(QLineF(x, rect.top(), x, rect.bottom()));
for (qreal y = top; y < rect.bottom(); y += gridSize)
lines.append(QLineF(rect.left(), y, rect.right(), y));

qDebug() << lines.size();

painter->drawLines(lines.data(), lines.size());
}
};

int main(int argc, char **argv)
{
QApplication app(argc, argv);

GridScene scene(-1000, -1000, 2000, 2000);
QGraphicsView view(&scene);
view.rotate(33);
view.show();

return app.exec();
}


Notice the use of QVarLengthArray, that's a trick to avoid allocating memory. As long as no more than 100 grid lines are visible at the same time, it'll use the stack and nothing else. You can play with the size; a QLineF uses 32 bytes of memory so 100 of those means 3200 bytes of stack space; there's room for more. :)

Bitto
11th February 2007, 20:35
...or drawPoints() instead of drawPoint(). ;-)

Gopala Krishna
11th February 2007, 20:59
Thanks Bitto, I can see the performance difference. :)
But when I move some 10 items together , the performance really comes down a lot. And now the profile shows Node::boundingRect() as culprit. I'll try to find out more and post it later.

rajesh
14th February 2007, 11:10
Hi Gopala,
Finally which method you used to draw grid and increase the performance?

Gopala Krishna
16th February 2007, 06:39
Hi rajesh,
I couldn't improve the performance. I posted a new thread (http://www.qtcentre.org/forum/f-qt-programming-2/t-graphicsview-performance-problems-5684.html) with example.

rajesh
16th February 2007, 06:58
In your main function just add

view->setViewport(new QGLWidget);

I am sure, this will improve the performence.
please add QGLWidget include file & path in settings.

rajesh
16th February 2007, 07:49
Hi Gopala,

I copied your drawBackground(... (http://doc.trolltech.com/4.2/QPainter.html)) code,
it displaying grid in scene, but later if I increase scene Rect then grid not increase to whole area.
eg:
m_scene->setSceneRect(0, 0, width, height);

what to do? any idea?

Thanks & Regards
Rajesh

Gopala Krishna
16th February 2007, 12:07
Hi Gopala,

I copied your drawBackground(... (http://doc.trolltech.com/4.2/QPainter.html)) code,
it displaying grid in scene, but later if I increase scene Rect then grid not increase to whole area.
eg:
m_scene->setSceneRect(0, 0, width, height);

what to do? any idea?

Thanks & Regards
Rajesh

Its working fine for me. I just added a slot to the scene which randomly increases size of scene and connected it QTimer. Whenever the sceneRect changed the view was properly updated for me.

xgoan
16th February 2007, 13:05
I have this code in my app:


void KonstructorScene::createGrid(){
QPoint rowStart(0, 0);

for(int j=0;j<m_grid.count();j++) qDeleteAll(m_grid[j]);
m_grid.clear();

for(int i=0;i<m_size.height();i++){
QPoint position(rowStart);
QVector<SquareItem*> row;

for(int j=0;j<m_size.width();j++){
SquareItem *square=new SquareItem(m_matrixTemplate[i][j], i, j, position);

row<<square;
addItem(square);
position+=QPoint(SQUARE_WIDTH/2, SQUARE_HEIGHT/2);
}
rowStart+=QPoint(-SQUARE_WIDTH/2, SQUARE_HEIGHT/2);

m_grid<<row;
}
}


void SquareItem::createPolygon(QPoint &position){
QPolygon polygon;

updateColor();
setPen(QPen(SQUARE_PEN_COLOR, PenSize));
m_center=position;
m_left=QPoint(position.x()-SQUARE_WIDTH/2, position.y());
m_top=QPoint(position.x(), position.y()-SQUARE_HEIGHT/2);
polygon<<m_left<<m_top
<<QPoint(position.x()+SQUARE_WIDTH/2, position.y())
<<QPoint(position.x(), position.y()+SQUARE_HEIGHT/2);


setPolygon(polygon);
}

Gopala Krishna
16th February 2007, 13:37
I have this code in my app:
...
You mean use square items as grid right ? I'll try but if you don't mind can you show the declaration of variables used and prototype of constructor for SquareItem.

arjunasd
8th August 2007, 09:57
Hi

Did you find an efficient way to draw the grid?

I am running into the same issue too? My grid is very slow. Also when I zoomIn or zoomOut, I have many wide irregular gaps between grids.

Thanks
Arjun

edixonvargas
7th June 2012, 15:59
Hello, I know this thread is so old, but I think I can contribute. Recently I had to do something similar and I got the same problem, eficiency, I develop a simple solution with a simple technique that uses a bitmap to draw all, is so fast and efficient, the explanation is in my website Creación de grilla de forma eficiente en QGraphicsView/QGraphicsScene (http://varper-tech.com/wp/creacion-de-grilla-de-forma-eficiente-en-qgraphicsviewqgraphicsscene/) but is spanish, if you think that you can exploit this, then visit it.