PDA

View Full Version : Speeding up dense collection of QGraphicsItems



lynchkp
8th March 2011, 21:11
Hello,

I'm trying to display a dense vector field (at times >10,000 vectors) over an image. My primary problem is that when scrolling across the image, the performance is quite laggy and the drawing time is quite substantial. I've looked online for a number of qgraphicsscene optimizations, but I haven't noticed too big of a performance improvement. Perhaps I'm missing something quite minor, I'm pretty new at using these graphics objects. I've attached images of the display. The current drawing time is around 300 msec.

I've implemented each of these as a QGraphicsItem. The class is given below:


VectorItem::VectorItem(const qpiv_vector &vec,
const qpiv_settings &settings,
int idx_i)
{
idx = idx_i;
scale_max = settings.scale_max;
snr = vec.snr;
vec_color_type = settings.vec_color_type;
highlight_flag = settings.highlight_flag;
interp = vec.interp;

dmag = sqrt( pow(vec.dx-settings.subtract_x,2) + pow(vec.dy-settings.subtract_y,2) );

x2 = dmag*settings.vec_scale_factor;
y2 = 0;

upper_x = x2 - 0.15*x2;
lower_x = upper_x;
upper_y = y2 + 0.07*x2;
lower_y = y2 - 0.07*x2;

this->setPos(vec.x,vec.y);
this->setRotation(atan2(vec.dy-settings.subtract_y,vec.dx-settings.subtract_x)*180/M_PI);
this->setAcceptHoverEvents(true);

// Pen definition.
findColor();
textPen.setWidth(2);
textPen.setCapStyle(Qt::RoundCap);
textPen.setColor(color);

// BoundingRect definition.
points.resize(3);
points[0] = QLineF(0,0,x2,y2);
points[1] = QLineF(upper_x,upper_y,x2,y2);
points[2] = QLineF(lower_x,lower_y,x2,y2);

// Shape definition.
points2.resize(8);
points2[0] = QPointF(-1,-1);
points2[1] = QPointF(-1,1);
points2[2] = QPointF(upper_x -1, 1);
points2[3] = QPointF(upper_x -1, upper_y +1);
points2[4] = QPointF(x2 + 1 , 0);
points2[5] = QPointF(lower_x -1, lower_y -1);
points2[6] = QPointF(lower_x -1, -1);
points2[7] = QPointF(-1,-1);
QPolygonF polygon(points2);
path.addPolygon(polygon);

}

QRectF VectorItem::boundingRect() const {
return QRectF(-x2-2,-x2-2,2*x2+2,2*x2+2);
}

QPainterPath VectorItem::shape() const {
return path;
}

void VectorItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
painter->setPen(textPen);
painter->drawLines(points);
}

void VectorItem::hoverEnterEvent ( QGraphicsSceneHoverEvent * event ) {
textPen.setWidth(4);
this->update(this->boundingRect());
}

void VectorItem::hoverLeaveEvent ( QGraphicsSceneHoverEvent * event ) {
textPen.setWidth(2);
this->update(this->boundingRect());
}

void VectorItem::mousePressEvent ( QGraphicsSceneMouseEvent * event ) {
openInfoDialog(idx);
}

void VectorItem::findColor() {
int idx;
if (vec_color_type == COLOR_VMAG) {
idx = floor((dmag/scale_max)*COLORMAP_SIZE);
} else if (vec_color_type == COLOR_SNR) {
idx = floor(((snr-0.5)/2.5)*COLORMAP_SIZE);
}

if (idx > COLORMAP_SIZE) {
idx = COLORMAP_SIZE;
}

if ((highlight_flag == true) && (interp == false)) {
color = Qt::white;
} else {
color = qRgb(jet_colormap[idx][1],jet_colormap[idx][2],jet_colormap[idx][3]);
}
}


And the implementation of the class:


for (int idx = 0; idx < grid.n; idx++) {
VectorItem *newarrow =
new VectorItem(vec.at(idx),settings,idx);
connect(newarrow,SIGNAL(openInfoDialog(int)),this, SLOT(openInfoDialog(int)));
scene->addItem(newarrow);
}


Any help would be greatly appreciated!!!

SixDegrees
9th March 2011, 09:01
If you haven't done so already, try fiddling with the QGraphicsView optimization flags (http://doc.qt.nokia.com/4.5/qgraphicsview.html#OptimizationFlag-enum).

If that fails, one idea would be to replace your thousands of QGraphicsItems with a single one that handles the painting of all vectors. This eliminates the overhead each individual QGraphicsItem carries with it, both in terms of memory and execution, but you lose some of the convenience of individual objects. If items are spaced on a regular grid, though, this may be acceptable.