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?

Qt Code:
  1. #ifndef WIDGET_H
  2. #define WIDGET_H
  3.  
  4. #include <QWidget>
  5. #include <QList>
  6.  
  7. struct circle {
  8. qreal r;
  9. circle(QPointF center, qreal radius): c(center), r(radius) {}
  10. };
  11.  
  12. class Widget : public QWidget
  13. {
  14. Q_OBJECT
  15.  
  16. public:
  17. Widget(QWidget *parent = 0);
  18.  
  19. protected:
  20. void paintEvent(QPaintEvent *event);
  21.  
  22. void mousePressEvent(QMouseEvent *event);
  23. void mouseReleaseEvent(QMouseEvent *event);
  24. void mouseMoveEvent(QMouseEvent *event);
  25.  
  26. void wheelEvent(QWheelEvent *event);
  27.  
  28. private:
  29. QList<circle> circles;
  30. QPointF shift;
  31. qreal scale;
  32. QPoint previous;
  33. bool isDragging;
  34. };
  35.  
  36. #endif // WIDGET_H
To copy to clipboard, switch view to plain text mode 

Qt Code:
  1. #include "widget.h"
  2.  
  3. #include <math.h>
  4. #include <QPainter>
  5. #include <QMouseEvent>
  6. #include <QWheelEvent>
  7.  
  8. circle tangent2(const circle &c1, const circle &c2, qreal r, const QPointF &p)
  9. {
  10. qreal r1 = c1.r + r;
  11. qreal r2 = c2.r + r;
  12. qreal d = c1.r + c2.r;
  13. qreal dx = (d*d - r2*r2 + r1*r1)/(2*d);
  14. qreal dy = sqrt(r1*r1 - dx*dx);
  15. QPointF v = (c2.c - c1.c)/d;
  16. QPointF n(-v.y(), v.x());
  17. QPointF pv = p - c1.c;
  18. if (pv.x()*n.x() + pv.y()*n.y() < 0)
  19. n = -n;
  20. QPointF c = c1.c + dx*v + dy*n;
  21. return circle(c, r);
  22. }
  23.  
  24. circle tangent3(const circle &c1, const circle &c2, const circle &c3)
  25. {
  26. qreal k1 = 1/c1.r;
  27. qreal k2 = 1/c2.r;
  28. qreal k3 = 1/c3.r;
  29. qreal a = k1 + k2 + k3;
  30. qreal b = 2*sqrt(k1*k2 + k2*k3 + k3*k1);
  31. qreal k = qMax(qAbs(a - b), a + b);
  32. return tangent2(c1, c2, 1/k, c3.c);
  33. }
  34.  
  35. Widget::Widget(QWidget *parent)
  36. : QWidget(parent), shift(300, 400), scale(30), isDragging(false)
  37. {
  38. setAutoFillBackground(false);
  39. circle c1(QPointF(0, 0), 5);
  40. circle c2(QPointF(8, 0), 3);
  41. circle c3 = tangent2(c1, c2, 4, QPointF(0, -1));
  42. circles << c1 << c2 << c3;
  43. for (int i = 0; i < 6; ++i) {
  44. circle c = tangent3(c1, c2, c3);
  45. circles << c;
  46. c1 = c2;
  47. c2 = c3;
  48. c3 = c;
  49. }
  50. }
  51.  
  52. void Widget::paintEvent(QPaintEvent *event)
  53. {
  54. QPainter painter(this);
  55. painter.fillRect(0, 0, width(), height(), Qt::darkGray);
  56. painter.setBrush(Qt::NoBrush);
  57. painter.setPen(QPen(QBrush(Qt::white), 1.5));
  58. painter.setRenderHint(QPainter::Antialiasing, true);
  59. foreach(const circle &c, circles)
  60. painter.drawEllipse(c.c * scale + shift, c.r * scale, c.r * scale);
  61. }
  62.  
  63. void Widget::mousePressEvent(QMouseEvent *event)
  64. {
  65. if (!isDragging && event->button() == Qt::RightButton) {
  66. isDragging = true;
  67. previous = event->pos();
  68. }
  69. }
  70.  
  71. void Widget::mouseReleaseEvent(QMouseEvent *event)
  72. {
  73. if (isDragging && event->button() == Qt::RightButton) {
  74. isDragging = false;
  75. }
  76. }
  77.  
  78. void Widget::mouseMoveEvent(QMouseEvent *event)
  79. {
  80. if (isDragging) {
  81. shift += event->pos() - previous;
  82. previous = event->pos();
  83. repaint();
  84. }
  85. }
  86.  
  87. void Widget::wheelEvent(QWheelEvent *event)
  88. {
  89. int numDegrees = event->delta() / 8;
  90. int numTicks = numDegrees / 15;
  91. qreal factor = pow(1.2, -numTicks);
  92. shift += (1 - factor) * (event->pos() - shift);
  93. scale *= factor;
  94. repaint();
  95. }
To copy to clipboard, switch view to plain text mode 

Qt Code:
  1. #include <QtGui/QApplication>
  2. #include "widget.h"
  3.  
  4. int main(int argc, char *argv[])
  5. {
  6. QApplication a(argc, argv);
  7. Widget w;
  8. w.resize(800, 600);
  9. w.show();
  10. return a.exec();
  11. }
To copy to clipboard, switch view to plain text mode