[Kst] branches/work/kst/portto4/kst/src/libkstmath

Mike Fenton mike at staikos.net
Wed Aug 13 21:56:25 CEST 2008


SVN commit 846649 by fenton:

Add caching of curve calculations for drawing.


 M  +119 -45   curve.cpp  
 M  +25 -0     curve.h  


--- branches/work/kst/portto4/kst/src/libkstmath/curve.cpp #846648:846649
@@ -75,6 +75,8 @@
   setBarStyle(0);
   setPointDensity(0);
 
+  _redrawRequired = true;
+
   _shortName = "C"+QString::number(_cnum);
   if (_cnum>max_cnum) 
     max_cnum = _cnum;
@@ -165,6 +167,10 @@
 
   unlockInputsAndOutputs();
 
+  if (depUpdated) {
+    _redrawRequired = true;
+  }
+
   return (depUpdated ? UPDATE : NO_CHANGE);
 }
 
@@ -711,16 +717,91 @@
 }
 
 
+bool Curve::redrawRequired(const CurveRenderContext& context) {
+  if ((_contextDetails.Lx == context.Lx) &&
+      (_contextDetails.Hx == context.Hx) &&  
+      (_contextDetails.Ly == context.Ly) &&  
+      (_contextDetails.Hy == context.Hy) &&  
+      (_contextDetails.m_X == context.m_X) &&  
+      (_contextDetails.m_Y == context.m_Y) &&  
+      (_contextDetails.b_X == context.b_X) &&  
+      (_contextDetails.b_Y == context.b_Y) &&  
+      (_contextDetails.XMin == context.XMin) &&  
+      (_contextDetails.XMax == context.XMax) &&  
+      (_contextDetails.xLog == context.xLog) &&  
+      (_contextDetails.yLog == context.yLog) &&  
+      (_contextDetails.xLogBase == context.xLogBase) &&  
+      (_contextDetails.yLogBase == context.yLogBase) &&  
+      (_contextDetails.penWidth == context.penWidth) ) {
+    return false;
+  } else {
+    _contextDetails.Lx = context.Lx;
+    _contextDetails.Hx = context.Hx;
+    _contextDetails.Ly = context.Ly;
+    _contextDetails.Hy = context.Hy;
+    _contextDetails.m_X = context.m_X;
+    _contextDetails.m_Y = context.m_Y;
+    _contextDetails.b_X = context.b_X;
+    _contextDetails.b_Y = context.b_Y;
+    _contextDetails.XMin = context.XMin;
+    _contextDetails.XMax = context.XMax;
+    _contextDetails.xLog = context.xLog;
+    _contextDetails.yLog = context.yLog;
+    _contextDetails.xLogBase = context.xLogBase;
+    _contextDetails.yLogBase = context.yLogBase;
+    _contextDetails.penWidth = context.penWidth;
+    return true;
+  }
+}
+
+
 void Curve::paint(const CurveRenderContext& context) {
+  if (redrawRequired(context) || _redrawRequired) {
+    curveUpdate(context);
+  }
 
+  QPainter *p = context.painter;
+  Qt::PenStyle style = Kst::LineStyle[lineStyle()];
+
+  if (hasBars()) {
+    if (barStyle() == 1) { // filled
+      p->setPen(QPen(context.foregroundColor, _width, style));
+    } else {
+      p->setPen(QPen(color(), _width, style));
+    }
+
+    foreach(QRect rect, _rects) {
+        p->fillRect(rect, color());
+    }
+  }
+
+  p->setPen(QPen(color(), _width, style));
+
+  foreach(QPolygon poly, _polygons) {
+    p->drawPolyline(poly);
+  }
+  foreach(QLine line, _lines) {
+    p->drawLine(line);
+  }
+  foreach(QPoint point, _points) {
+    CurvePointSymbol::draw(PointType, p, point.x(), point.y(), _width);
+  }
+}
+
+
+void Curve::curveUpdate(const CurveRenderContext& context) {
+  _polygons.clear();
+  _lines.clear();
+  _points.clear();
+  _rects.clear();
+  _redrawRequired = false;
+
   VectorPtr xv = *_inputVectors.find(COLOR_XVECTOR);
   VectorPtr yv = *_inputVectors.find(COLOR_YVECTOR);
   if (!xv || !yv) {
     return;
   }
 
-  /*Kst*/QPainter *p = context.painter;
-  QColor foregroundColor = context.foregroundColor;
   double Lx = context.Lx, Hx = context.Hx, Ly = context.Ly, Hy = context.Hy;
   double m_X = context.m_X, m_Y = context.m_Y;
   double b_X = context.b_X, b_Y = context.b_Y;
@@ -728,7 +809,6 @@
   bool xLog = context.xLog, yLog = context.yLog;
   double xLogBase = context.xLogBase;
   double yLogBase = context.yLogBase;
-  int penWidth = context.penWidth;
   double maxY = 0.0, minY = 0.0;
   double rX = 0.0, rY, rEX, rEY;
   double X1 = 0.0, Y1 = 0.0;
@@ -744,22 +824,21 @@
   benchtmp.start();
   int numberOfLinesDrawn = 0;
   int numberOfPointsDrawn = 0;
+  int numberOfBarsDrawn = 0;
 #endif
 
+  if (lineWidth() == 0) {
+    _width = context.penWidth;
+  } else if (context.penWidth > 0) {
+    _width = lineWidth() * context.penWidth;
+  } else {
+    _width = lineWidth();
+  }
+
   int pointDim = CurvePointSymbol::dim(context.window);
   if (sampleCount() > 0) {
-    Qt::PenStyle style = Kst::LineStyle[lineStyle()];
     int i0, iN;
-    int width;
 
-    if (lineWidth() == 0) {
-      width = penWidth;
-    } else if (penWidth > 0) {
-      width = lineWidth() * penWidth;
-    } else {
-      width = lineWidth();
-    }
-
     if (xv->isRising()) {
       i0 = indexNearX(XMin, xv, NS);
       if (i0 > 0) {
@@ -784,8 +863,6 @@
       int index = 0;
       int i0Start = i0;
 
-      p->setPen(QPen(color(), width, style));
-
 // optimize - isnan seems expensive, at least in gcc debug mode
 //            cachegrind backs this up.
 #undef isnan
@@ -848,7 +925,7 @@
 #ifdef BENCHMARK
   ++numberOfLinesDrawn;
 #endif
-            p->drawPolyline(poly);
+            _polygons.append(poly);
           }
           index = 0;
           if (overlap) {
@@ -864,7 +941,7 @@
 #ifdef BENCHMARK
   ++numberOfLinesDrawn;
 #endif
-                p->drawLine(d2i(X2), d2i(minY), d2i(X2), d2i(maxY));
+                _lines.append(QLine(d2i(X2), d2i(minY), d2i(X2), d2i(maxY)));
               }
             }
             overlap = false;
@@ -920,7 +997,7 @@
 #ifdef BENCHMARK
   ++numberOfLinesDrawn;
 #endif
-                    p->drawPolyline(poly);
+                    _polygons.append(poly);
                     index = 0;
                   }
                   if (KDE_ISUNLIKELY(minYi == maxYi)) {
@@ -972,7 +1049,7 @@
 #ifdef BENCHMARK
   ++numberOfLinesDrawn;
 #endif
-                      p->drawPolyline(poly);
+                      _polygons.append(poly);
                       index = 0;
                     }
 #ifdef DEBUG_VECTOR_CURVE
@@ -981,7 +1058,7 @@
 #ifdef BENCHMARK
   ++numberOfLinesDrawn;
 #endif
-                    p->drawLine(X2i, d2i(minY), X2i, d2i(maxY));
+                    _lines.append(QLine(X2i, d2i(minY), X2i, d2i(maxY)));
                   }
                 }
               }
@@ -1114,7 +1191,7 @@
 #ifdef BENCHMARK
   ++numberOfLinesDrawn;
 #endif
-                    p->drawPolyline(poly);
+                    _polygons.append(poly);
                   }
                   index = 0;
 #ifdef DEBUG_VECTOR_CURVE
@@ -1141,7 +1218,7 @@
 #ifdef BENCHMARK
   ++numberOfLinesDrawn;
 #endif
-        p->drawPolyline(poly);
+        _polygons.append(poly);
         index = 0;
       }
 
@@ -1161,7 +1238,7 @@
 #ifdef BENCHMARK
   ++numberOfLinesDrawn;
 #endif
-            p->drawLine(d2i(X2), d2i(minY), d2i(X2), d2i(maxY));
+           _lines.append(QLine(d2i(X2), d2i(minY), d2i(X2), d2i(maxY)));
           }
         }
         overlap = false;
@@ -1187,12 +1264,6 @@
       double rX2 = 0.0;
       double drX = 0.0;
 
-      if (barStyle() == 1) { // filled
-        p->setPen(QPen(foregroundColor, width, style));
-      } else {
-        p->setPen(QPen(color(), width, style));
-      }
-
       if (!exv) {
         // determine the bar position width. NOTE: This is done
         //  only if xv->isRising() as in this case the calculation
@@ -1286,24 +1357,27 @@
           if (barStyle() == 1) { // filled
             int X1i = d2i(X1);
             int Y1i = d2i(Y1);
-            p->fillRect(X1i, Y1i, d2i(X2) - X1i, d2i(Y2) - Y1i, color());
+            _rects.append(QRect(X1i, Y1i, d2i(X2) - X1i, d2i(Y2) - Y1i));
           }
           if (has_top) {
             int Y1i = d2i(Y1);
-            p->drawLine(d2i(X1-(width/2)), Y1i, d2i(X2+(width/2)), Y1i);
+            _lines.append(QLine(d2i(X1-(_width/2)), Y1i, d2i(X2+(_width/2)), Y1i));
           }
           if (has_bot) {
             int Y2i = d2i(Y2);
-            p->drawLine(d2i(X1-(width/2)), Y2i, d2i(X2-(width/2)), Y2i);
+            _lines.append(QLine(d2i(X1-(_width/2)), Y2i, d2i(X2-(_width/2)), Y2i));
           }
           if (has_left) {
             int X1i = d2i(X1);
-            p->drawLine(X1i, d2i(Y1-(width/2)), X1i, d2i(Y2+(width/2)));
+            _lines.append(QLine(X1i, d2i(Y1-(_width/2)), X1i, d2i(Y2+(_width/2))));
           }
           if (has_right) {
             int X2i = d2i(X2);
-            p->drawLine(X2i, d2i(Y1-(width/2)), X2i, d2i(Y2+(width/2)));
+            _lines.append(QLine(X2i, d2i(Y1-(_width/2)), X2i, d2i(Y2+(_width/2))));
           }
+#ifdef BENCHMARK
+  ++numberOfBarsDrawn;
+#endif
         }
       }
     }
@@ -1312,8 +1386,6 @@
     b_2 = benchtmp.elapsed();
 #endif
 
-    p->setPen(QPen(color(), width));
-
     // draw the points, if any...
     if (hasPoints()) {
       const double w = Hx - Lx;
@@ -1343,7 +1415,7 @@
   ++numberOfPointsDrawn;
 #endif
             lastPt = pt;
-            CurvePointSymbol::draw(PointType, p, pt.x(), pt.y(), width);
+            _points.append(pt);
         }
       }
     }
@@ -1434,12 +1506,12 @@
           int X1i = d2i(X1);
           int X2i = d2i(X2);
           int Y1i = d2i(Y1);
-          p->drawLine(X1i, Y1i, X2i, Y1i);
+          _lines.append(QLine(X1i, Y1i, X2i, Y1i));
           if (do_low_flag) {
-            p->drawLine(X1i, Y1i + pointDim, X1i, Y1i - pointDim);
+            _lines.append(QLine(X1i, Y1i + pointDim, X1i, Y1i - pointDim));
           }
           if (do_high_flag) {
-            p->drawLine(X2i, Y1i + pointDim, X2i, Y1i - pointDim);
+            _lines.append(QLine(X2i, Y1i + pointDim, X2i, Y1i - pointDim));
           }
         }
       }
@@ -1527,12 +1599,12 @@
           int X1i = d2i(X1);
           int Y1i = d2i(Y1);
           int Y2i = d2i(Y2);
-          p->drawLine(X1i, Y1i, X1i, Y2i);
+          _lines.append(QLine(X1i, Y1i, X1i, Y2i));
           if (do_low_flag) {
-            p->drawLine(X1i + pointDim, Y1i, X1i - pointDim, Y1i);
+          _lines.append(QLine(X1i + pointDim, Y1i, X1i - pointDim, Y1i));
           }
           if (do_high_flag) {
-            p->drawLine(X1i + pointDim, Y2i, X1i - pointDim, Y2i);
+          _lines.append(QLine(X1i + pointDim, Y2i, X1i - pointDim, Y2i));
           }
         }
       }
@@ -1542,12 +1614,14 @@
 #ifdef BENCHMARK
   b_4 = benchtmp.elapsed();
 #endif
+
 #ifdef BENCHMARK
   int i = bench_time.elapsed();
   qDebug() << "Plotting curve " << (void *)this << ": " << i << "ms" << endl;
   qDebug() << "    Without locks: " << b_4 << "ms" << endl;
-  qDebug() << "    Nnumber of lines drawn:" << numberOfLinesDrawn << endl;
-  qDebug() << "    Nnumber of points drawn:" << numberOfPointsDrawn << endl;
+  qDebug() << "    Number of lines drawn:" << numberOfLinesDrawn << endl;
+  qDebug() << "    Number of points drawn:" << numberOfPointsDrawn << endl;
+  qDebug() << "    Number of bars drawn:" << numberOfBarsDrawn << endl;
   if (b_1 > 0)       qDebug() << "            Lines: " << b_1 << "ms" << endl;
   if (b_2 - b_1 > 0) qDebug() << "             Bars: " << (b_2 - b_1) << "ms" << endl;
   if (b_3 - b_2 > 0) qDebug() << "           Points: " << (b_3 - b_2) << "ms" << endl;
--- branches/work/kst/portto4/kst/src/libkstmath/curve.h #846648:846649
@@ -31,6 +31,16 @@
 
 namespace Kst {
 
+  struct CurveContextDetails {
+    double Lx, Hx, Ly, Hy;
+    double m_X, m_Y;
+    double b_X, b_Y;
+    double XMin, XMax;
+    bool xLog, yLog;
+    double xLogBase, yLogBase;
+    int penWidth;
+  };
+
 class KST_EXPORT Curve: public Relation {
   Q_OBJECT
 
@@ -136,6 +146,12 @@
     // render this vcurve
     virtual void paint(const CurveRenderContext& context);
 
+    // Update the curve details.
+    void curveUpdate(const CurveRenderContext& context);
+
+    // Compare the cached the context to the provided one.
+    bool redrawRequired(const CurveRenderContext& context); 
+
     // render the legend symbol for this curve
     virtual void paintLegendSymbol(QPainter *p, const QRect& bound);
 
@@ -180,6 +196,15 @@
     QStack<bool> _hasLinesStack;
     QStack<int> _pointDensityStack;
 
+    QVector<QPolygon> _polygons;
+    QVector<QLine> _lines;
+    QVector<QPoint> _points;
+    QVector<QRect> _rects;
+    int _width;
+
+    CurveContextDetails _contextDetails;
+    bool _redrawRequired;
+
 };
 
 typedef SharedPtr<Curve> CurvePtr;


More information about the Kst mailing list