PDA

View Full Version : Performance problem with drawing circles



kamre
10th September 2009, 19:23
It is possible to drag with pressed right mouse button and to zoom with mouse wheel. And initially everything works rather smooth. But when I zoom to the smallest circle the performance of drawing is significantly degraded. Why? And how can I fix it?



#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QList>

struct circle {
QPointF c;
qreal r;
circle(QPointF center, qreal radius): c(center), r(radius) {}
};

class Widget : public QWidget
{
Q_OBJECT

public:
Widget(QWidget *parent = 0);

protected:
void paintEvent(QPaintEvent *event);

void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);

void wheelEvent(QWheelEvent *event);

private:
QList<circle> circles;
QPointF shift;
qreal scale;
QPoint previous;
bool isDragging;
};

#endif // WIDGET_H




#include "widget.h"

#include <math.h>
#include <QPainter>
#include <QMouseEvent>
#include <QWheelEvent>

circle tangent2(const circle &c1, const circle &c2, qreal r, const QPointF &p)
{
qreal r1 = c1.r + r;
qreal r2 = c2.r + r;
qreal d = c1.r + c2.r;
qreal dx = (d*d - r2*r2 + r1*r1)/(2*d);
qreal dy = sqrt(r1*r1 - dx*dx);
QPointF v = (c2.c - c1.c)/d;
QPointF n(-v.y(), v.x());
QPointF pv = p - c1.c;
if (pv.x()*n.x() + pv.y()*n.y() < 0)
n = -n;
QPointF c = c1.c + dx*v + dy*n;
return circle(c, r);
}

circle tangent3(const circle &c1, const circle &c2, const circle &c3)
{
qreal k1 = 1/c1.r;
qreal k2 = 1/c2.r;
qreal k3 = 1/c3.r;
qreal a = k1 + k2 + k3;
qreal b = 2*sqrt(k1*k2 + k2*k3 + k3*k1);
qreal k = qMax(qAbs(a - b), a + b);
return tangent2(c1, c2, 1/k, c3.c);
}

Widget::Widget(QWidget *parent)
: QWidget(parent), shift(300, 400), scale(30), isDragging(false)
{
setAutoFillBackground(false);
circle c1(QPointF(0, 0), 5);
circle c2(QPointF(8, 0), 3);
circle c3 = tangent2(c1, c2, 4, QPointF(0, -1));
circles << c1 << c2 << c3;
for (int i = 0; i < 6; ++i) {
circle c = tangent3(c1, c2, c3);
circles << c;
c1 = c2;
c2 = c3;
c3 = c;
}
}

void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.fillRect(0, 0, width(), height(), Qt::darkGray);
painter.setBrush(Qt::NoBrush);
painter.setPen(QPen(QBrush(Qt::white), 1.5));
painter.setRenderHint(QPainter::Antialiasing, true);
foreach(const circle &c, circles)
painter.drawEllipse(c.c * scale + shift, c.r * scale, c.r * scale);
}

void Widget::mousePressEvent(QMouseEvent *event)
{
if (!isDragging && event->button() == Qt::RightButton) {
isDragging = true;
previous = event->pos();
}
}

void Widget::mouseReleaseEvent(QMouseEvent *event)
{
if (isDragging && event->button() == Qt::RightButton) {
isDragging = false;
}
}

void Widget::mouseMoveEvent(QMouseEvent *event)
{
if (isDragging) {
shift += event->pos() - previous;
previous = event->pos();
repaint();
}
}

void Widget::wheelEvent(QWheelEvent *event)
{
int numDegrees = event->delta() / 8;
int numTicks = numDegrees / 15;
qreal factor = pow(1.2, -numTicks);
shift += (1 - factor) * (event->pos() - shift);
scale *= factor;
repaint();
}




#include <QtGui/QApplication>
#include "widget.h"

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.resize(800, 600);
w.show();
return a.exec();
}

bunjee
10th September 2009, 20:25
If you want a fast an advanced canvas with zoom:

Use QGraphicsView.

kamre
11th September 2009, 09:48
If you want a fast an advanced canvas with zoom:

Use QGraphicsView.

This is not possible for me because there is a limitation:


QGraphicsItem does not support use of cosmetic pens with a non-zero width.
And I need to draw my shapes with pen width that is the same for all zoom levels. So painting bounds for shapes are different for different zoom levels and QGraphicsView can't handle such cases, am I right?

In any case I'll try to reproduce this behaviour with QGraphicsView, cause I think the problem is somewhere in QPainter.

kamre
12th September 2009, 11:07
By the way here is a Java2D implementation (just rename the attachment to jar) and there is no such problem with performance as in Qt. So what is wrong with my approach to zooming in Qt version?

kamre
15th September 2009, 05:35
I have run this simple example with callgring profiler and here are the results.

When zoom level is not big and everything is rather fast:
http://pic.ipicture.ru/uploads/090915/X5GC3Scz19.png

With big zoom level and degraded performance:
http://pic.ipicture.ru/uploads/090915/DiRvE5X2Q2.png

So the problem begins with the call of function QPainter::intersected.
What is wrong in my example? Is this a known Qt4 limitation/feature or bug?