Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

qwt_plot_curve.cpp

00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
00002  * Qwt Widget Library
00003  * Copyright (C) 1997   Josef Wilgen
00004  * Copyright (C) 2002   Uwe Rathmann
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the Qwt License, Version 1.0
00008  *****************************************************************************/
00009 
00010 #include <qpainter.h>
00011 #include <qpixmap.h>
00012 #include <qbitarray.h>
00013 #include "qwt_global.h"
00014 #include "qwt_legend.h"
00015 #include "qwt_legend_item.h"
00016 #include "qwt_data.h"
00017 #include "qwt_rect.h"
00018 #include "qwt_scale_map.h"
00019 #include "qwt_double_rect.h"
00020 #include "qwt_math.h"
00021 #include "qwt_painter.h"
00022 #include "qwt_plot.h"
00023 #include "qwt_plot_canvas.h"
00024 #include "qwt_spline.h"
00025 #include "qwt_symbol.h"
00026 #include "qwt_plot_curve.h"
00027 
00028 #if QT_VERSION >= 0x040000
00029 
00030 #include <qevent.h>
00031 
00032 class QwtPlotCurvePaintHelper: public QObject
00033 {
00034 public:
00035     QwtPlotCurvePaintHelper(const QwtPlotCurve *curve, int from, int to):
00036         _curve(curve),
00037         _from(from),
00038         _to(to)
00039     {
00040     }
00041 
00042     virtual bool eventFilter(QObject *, QEvent *event)
00043     {
00044         if ( event->type() == QEvent::Paint )
00045         {
00046             _curve->draw(_from, _to);
00047             return true;
00048         }
00049         return false;
00050     }
00051 private:
00052     const QwtPlotCurve *_curve;
00053     int _from;
00054     int _to;
00055 };
00056 
00057 #endif // QT_VERSION >= 0x040000
00058 
00059 #if QT_VERSION < 0x040000
00060 #define QwtPointArray QPointArray
00061 #else
00062 #define QwtPointArray QPolygon
00063 #endif
00064 
00065 class QwtPlotCurve::PrivateData
00066 {
00067 public:
00068     class PixelMatrix: private QBitArray
00069     {
00070     public:
00071         PixelMatrix(const QRect& rect):
00072             QBitArray(rect.width() * rect.height()),
00073             _rect(rect)
00074         {
00075             fill(false);
00076         }
00077 
00078         inline bool testPixel(const QPoint& pos)
00079         {
00080             if ( !_rect.contains(pos) )
00081                 return false;
00082 
00083             const int idx = _rect.width() * (pos.y() - _rect.y()) + 
00084                 (pos.x() - _rect.x());
00085 
00086             const bool marked = testBit(idx);
00087             if ( !marked )
00088                 setBit(idx, true);
00089 
00090             return !marked;
00091         }
00092 
00093     private:
00094         QRect _rect;
00095     };
00096 
00097     PrivateData()
00098     {
00099         pen = QPen(Qt::black, 0);
00100         reference = 0.0;
00101         splineSize = 250;
00102         attributes = Auto;
00103         paintAttributes = 0;
00104         style = QwtPlotCurve::Lines;
00105     }
00106 
00107     QwtPlotCurve::CurveStyle style;
00108     double reference;
00109 
00110     QwtSymbol sym;
00111 
00112     QPen pen;
00113     QBrush brush;
00114     QwtText title;
00115 
00116     int attributes;
00117     int splineSize;
00118     int paintAttributes;
00119 };
00120 
00121 static int qwtChkMono(const double *array, int size)
00122 {
00123     if (size < 2)
00124         return 0;
00125 
00126     int rv = qwtSign(array[1] - array[0]);
00127     for (int i = 1; i < size - 1; i++)
00128     {
00129         if ( qwtSign(array[i+1] - array[i]) != rv )
00130         {
00131             rv = 0;
00132             break;
00133         }
00134     }
00135     return rv;
00136 }
00137 
00138 static void qwtTwistArray(double *array, int size)
00139 {
00140     const int s2 = size / 2;
00141 
00142     for (int i=0; i < s2; i++)
00143     {
00144         const int itmp = size - 1 - i;
00145         const double dtmp = array[i];
00146         array[i] = array[itmp];
00147         array[itmp] = dtmp;
00148     }
00149 }
00150 
00154 QwtPlotCurve::QwtPlotCurve()
00155 {
00156     init(QwtText());
00157 }
00158 
00163 QwtPlotCurve::QwtPlotCurve(const QwtText &title)
00164 {
00165     init(title);
00166 }
00167 
00172 QwtPlotCurve::QwtPlotCurve(const QString &title)
00173 {
00174     init(title);
00175 }
00176 
00180 QwtPlotCurve::QwtPlotCurve(const QwtPlotCurve &c):
00181     QwtPlotItem(c)
00182 {
00183     init(c.d_data->title);
00184     copy(c);
00185 }
00186 
00188 QwtPlotCurve::~QwtPlotCurve()
00189 {
00190     delete d_xy;
00191     delete d_data;
00192 }
00193 
00197 void QwtPlotCurve::init(const QwtText &title)
00198 {
00199     setItemAttribute(QwtPlotItem::Legend);
00200     setItemAttribute(QwtPlotItem::AutoScale);
00201 
00202     d_data = new PrivateData;
00203     d_data->title = title;
00204 
00205     d_xy = new QwtDoublePointData(QwtArray<QwtDoublePoint>());
00206 
00207     setZ(20.0);
00208 }
00209 
00213 void QwtPlotCurve::copy(const QwtPlotCurve &c)
00214 {
00215     if (this != &c)
00216     {
00217         *d_data = *c.d_data;
00218 
00219         delete d_xy;
00220         d_xy = c.d_xy->copy();
00221 
00222         itemChanged();
00223     }
00224 }
00225 
00226 
00230 const QwtPlotCurve& QwtPlotCurve::operator=(const QwtPlotCurve &c)
00231 {
00232     copy(c);
00233     return *this;
00234 }
00235 
00236 int QwtPlotCurve::rtti() const
00237 {
00238     return QwtPlotItem::Rtti_PlotCurve;
00239 }
00240 
00262 void QwtPlotCurve::setPaintAttribute(PaintAttribute attribute, bool on)
00263 {
00264     if ( on )
00265         d_data->paintAttributes |= attribute;
00266     else
00267         d_data->paintAttributes &= ~attribute;
00268 }
00269 
00274 bool QwtPlotCurve::testPaintAttribute(PaintAttribute attribute) const
00275 {
00276     return (d_data->paintAttributes & attribute);
00277 }
00278 
00309 void QwtPlotCurve::setStyle(CurveStyle style)
00310 {
00311     if ( style != d_data->style )
00312     {
00313         d_data->style = style;
00314         itemChanged();
00315     }
00316 }
00317 
00323 QwtPlotCurve::CurveStyle QwtPlotCurve::style() const 
00324 { 
00325     return d_data->style; 
00326 }
00327 
00333 void QwtPlotCurve::setSymbol(const QwtSymbol &s )
00334 {
00335     d_data->sym = s;
00336     itemChanged();
00337 }
00338 
00343 const QwtSymbol &QwtPlotCurve::symbol() const 
00344 { 
00345     return d_data->sym; 
00346 }
00347 
00352 void QwtPlotCurve::setPen(const QPen &p)
00353 {
00354     if ( p != d_data->pen )
00355     {
00356         d_data->pen = p;
00357         itemChanged();
00358     }
00359 }
00360 
00365 const QPen& QwtPlotCurve::pen() const 
00366 { 
00367     return d_data->pen; 
00368 }
00369 
00382 void QwtPlotCurve::setBrush(const QBrush &brush)
00383 {
00384     if ( brush != d_data->brush )
00385     {
00386         d_data->brush = brush;
00387         itemChanged();
00388     }
00389 }
00390 
00396 const QBrush& QwtPlotCurve::brush() const 
00397 {
00398     return d_data->brush;
00399 }
00400 
00401 
00413 void QwtPlotCurve::setData(const double *xData, const double *yData, int size)
00414 {
00415     delete d_xy;
00416     d_xy = new QwtArrayData(xData, yData, size);
00417     itemChanged();
00418 }
00419 
00428 void QwtPlotCurve::setData(const QwtArray<double> &xData, 
00429     const QwtArray<double> &yData)
00430 {
00431     delete d_xy;
00432     d_xy = new QwtArrayData(xData, yData);
00433     itemChanged();
00434 }
00435 
00443 void QwtPlotCurve::setData(const QwtArray<QwtDoublePoint> &data)
00444 {
00445     delete d_xy;
00446     d_xy = new QwtDoublePointData(data);
00447     itemChanged();
00448 }
00449 
00457 void QwtPlotCurve::setData(const QwtData &data)
00458 {
00459     delete d_xy;
00460     d_xy = data.copy();
00461     itemChanged();
00462 }
00463 
00477 void QwtPlotCurve::setRawData(const double *xData, const double *yData, int size)
00478 {
00479     delete d_xy;
00480     d_xy = new QwtCPointerData(xData, yData, size);
00481     itemChanged();
00482 }
00483 
00488 void QwtPlotCurve::setTitle(const QString &title)
00489 {
00490     setTitle(QwtText(title));
00491 }
00492 
00497 void QwtPlotCurve::setTitle(const QwtText &title)
00498 {
00499     d_data->title = title;
00500     itemChanged();
00501 }
00502 
00507 const QwtText &QwtPlotCurve::title() const 
00508 { 
00509     return d_data->title; 
00510 }
00511 
00518 QwtDoubleRect QwtPlotCurve::boundingRect() const
00519 {
00520     if ( d_xy == NULL )
00521         return QwtDoubleRect(1.0, 1.0, -2.0, -2.0); // invalid
00522 
00523     return d_xy->boundingRect();
00524 }
00525 
00526 
00532 int QwtPlotCurve::verifyRange(int &i1, int &i2) const
00533 {
00534     int size = dataSize();
00535 
00536     if (size < 1) return 0;
00537 
00538     i1 = qwtLim(i1, 0, size-1);
00539     i2 = qwtLim(i2, 0, size-1);
00540 
00541     if ( i1 > i2 )
00542         qSwap(i1, i2);
00543 
00544     return (i2 - i1 + 1);
00545 }
00546 
00547 void QwtPlotCurve::draw(QPainter *painter,
00548     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00549     const QRect &) const
00550 {
00551     draw(painter, xMap, yMap, 0, -1);
00552 }
00553 
00571 void QwtPlotCurve::draw(int from, int to) const
00572 {
00573     if ( !plot() )
00574         return;
00575 
00576     QwtPlotCanvas *canvas = plot()->canvas();
00577 
00578     bool directPaint = true;
00579 
00580 #if QT_VERSION >= 0x040000
00581     if ( !canvas->testAttribute(Qt::WA_WState_InPaintEvent) &&
00582         !canvas->testAttribute(Qt::WA_PaintOutsidePaintEvent) )
00583     {
00584         /*
00585           We save curve and range in helper and call repaint.
00586           The helper filters the Paint event, to repeat
00587           the QwtPlotCurve::draw, but now from inside the paint
00588           event.
00589          */
00590 
00591         QwtPlotCurvePaintHelper helper(this, from, to);
00592         canvas->installEventFilter(&helper);
00593         canvas->repaint();
00594 
00595         return;
00596     }
00597 #endif
00598 
00599     const QwtScaleMap xMap = plot()->canvasMap(xAxis());
00600     const QwtScaleMap yMap = plot()->canvasMap(yAxis());
00601 
00602     if ( canvas->testPaintAttribute(QwtPlotCanvas::PaintCached) &&
00603         canvas->paintCache() && !canvas->paintCache()->isNull() )
00604     {
00605         QPainter cachePainter((QPixmap *)canvas->paintCache());
00606         cachePainter.translate(-canvas->contentsRect().x(),
00607             -canvas->contentsRect().y());
00608 
00609         draw(&cachePainter, xMap, yMap, from, to);
00610     }
00611 
00612     if ( directPaint )
00613     {
00614         QPainter painter(canvas);
00615 
00616         painter.setClipping(true);
00617         painter.setClipRect(canvas->contentsRect());
00618 
00619         draw(&painter, xMap, yMap, from, to);
00620 
00621         return;
00622     }
00623 
00624 #if QT_VERSION >= 0x040000
00625     if ( canvas->testPaintAttribute(QwtPlotCanvas::PaintCached) &&
00626         canvas->paintCache() )
00627     {
00628         /*
00629           The cache is up to date. We flush it via repaint to the
00630           canvas. This works flicker free but is much ( > 10x )
00631           slower than direct painting.
00632          */
00633 
00634         const bool noBG = canvas->testAttribute(Qt::WA_NoBackground);
00635         if ( !noBG )
00636             canvas->setAttribute(Qt::WA_NoBackground, true);
00637 
00638         canvas->repaint(canvas->contentsRect());
00639 
00640         if ( !noBG )
00641             canvas->setAttribute(Qt::WA_NoBackground, false);
00642 
00643         return;
00644     }
00645 #endif
00646 
00647     // Ok, we give up 
00648     canvas->repaint(canvas->contentsRect());
00649 }
00650 
00664 void QwtPlotCurve::draw(QPainter *painter,
00665     const QwtScaleMap &xMap, const QwtScaleMap &yMap, 
00666     int from, int to) const
00667 {
00668     if ( !painter || dataSize() <= 0 )
00669         return;
00670 
00671     if (to < 0)
00672         to = dataSize() - 1;
00673 
00674     if ( verifyRange(from, to) > 0 )
00675     {
00676         painter->save();
00677         painter->setPen(d_data->pen);
00678 
00679         /*
00680           Qt 4.0.0 is slow when drawing lines, but it´s even 
00681           slower when the painter has a brush. So we don't
00682           set the brush before we need it.
00683          */
00684 
00685         drawCurve(painter, d_data->style, xMap, yMap, from, to);
00686         painter->restore();
00687 
00688         if (d_data->sym.style() != QwtSymbol::None)
00689         {
00690             painter->save();
00691             drawSymbols(painter, d_data->sym, xMap, yMap, from, to);
00692             painter->restore();
00693         }
00694     }
00695 }
00696 
00709 void QwtPlotCurve::drawCurve(QPainter *painter, int style,
00710     const QwtScaleMap &xMap, const QwtScaleMap &yMap, 
00711     int from, int to) const
00712 {
00713     switch (style)
00714     {
00715         case Lines:
00716             drawLines(painter, xMap, yMap, from, to);
00717             break;
00718         case Sticks:
00719             drawSticks(painter, xMap, yMap, from, to);
00720             break;
00721         case Steps:
00722             drawSteps(painter, xMap, yMap, from, to);
00723             break;
00724         case Spline:
00725             if ( from > 0 || to < dataSize() - 1 )
00726                 drawLines(painter, xMap, yMap, from, to);
00727             else
00728                 drawSpline(painter, xMap, yMap);
00729             break;
00730         case Dots:
00731             drawDots(painter, xMap, yMap, from, to);
00732             break;
00733         case NoCurve:
00734         default:
00735             break;
00736     }
00737 }
00738 
00749 void QwtPlotCurve::drawLines(QPainter *painter,
00750     const QwtScaleMap &xMap, const QwtScaleMap &yMap, 
00751     int from, int to) const
00752 {
00753     const int size = to - from + 1;
00754     if ( size <= 0 )
00755         return;
00756 
00757     QwtPointArray polyline(size);
00758 
00759     if ( d_data->paintAttributes & PaintFiltered )
00760     {
00761         QPoint pp( xMap.transform(x(from)), yMap.transform(y(from)) );
00762         polyline.setPoint(0, pp);
00763 
00764         int count = 1;
00765         for (int i = from + 1; i <= to; i++)
00766         {
00767             const QPoint pi(xMap.transform(x(i)), yMap.transform(y(i)));
00768             if ( pi != pp )
00769             {
00770                 polyline.setPoint(count, pi);
00771                 count++;
00772 
00773                 pp = pi;
00774             }
00775         }
00776         if ( count != size )
00777             polyline.resize(count);
00778     }
00779     else
00780     {
00781         for (int i = from; i <= to; i++)
00782         {
00783             int xi = xMap.transform(x(i));
00784             int yi = yMap.transform(y(i));
00785 
00786             polyline.setPoint(i - from, xi, yi);
00787         }
00788     }
00789 
00790     if ( d_data->paintAttributes & ClipPolygons )
00791     {
00792         QwtRect r = painter->window();
00793         polyline = r.clip(polyline);
00794     }
00795 
00796     QwtPainter::drawPolyline(painter, polyline);
00797 
00798     if ( d_data->brush.style() != Qt::NoBrush )
00799         fillCurve(painter, xMap, yMap, polyline);
00800 }
00801 
00812 void QwtPlotCurve::drawSticks(QPainter *painter,
00813     const QwtScaleMap &xMap, const QwtScaleMap &yMap, 
00814     int from, int to) const
00815 {
00816     int x0 = xMap.transform(d_data->reference);
00817     int y0 = yMap.transform(d_data->reference);
00818 
00819     for (int i = from; i <= to; i++)
00820     {
00821         const int xi = xMap.transform(x(i));
00822         const int yi = yMap.transform(y(i));
00823 
00824         if (d_data->attributes & Xfy)
00825             QwtPainter::drawLine(painter, x0, yi, xi, yi);
00826         else
00827             QwtPainter::drawLine(painter, xi, y0, xi, yi);
00828     }
00829 }
00830 
00842 void QwtPlotCurve::drawDots(QPainter *painter,
00843     const QwtScaleMap &xMap, const QwtScaleMap &yMap, 
00844     int from, int to) const
00845 {
00846     const QRect window = painter->window();
00847     if ( window.isEmpty() )
00848         return;
00849 
00850     const bool doFill = d_data->brush.style() != Qt::NoBrush;
00851 
00852     QwtPointArray polyline;
00853     if ( doFill )
00854         polyline.resize(to - from + 1);
00855 
00856     if ( to > from && d_data->paintAttributes & PaintFiltered )
00857     {
00858         int count = 0;
00859 
00860         if ( doFill )   
00861         {
00862             QPoint pp( xMap.transform(x(from)), yMap.transform(y(from)) );
00863             polyline.setPoint(0, pp);
00864 
00865             int count = 1;
00866             for (int i = from + 1; i <= to; i++)
00867             {
00868                 const QPoint pi(xMap.transform(x(i)), yMap.transform(y(i)));
00869                 if ( pi != pp )
00870                 {
00871                     polyline.setPoint(count, pi);
00872                     count++;
00873 
00874                     pp = pi;
00875                 }
00876             }
00877         }
00878         else
00879         {
00880             // if we don't need to fill, we can sort out
00881             // duplicates independent from the order
00882 
00883             PrivateData::PixelMatrix pixelMatrix(window);
00884 
00885             for (int i = from; i <= to; i++)
00886             {
00887                 const QPoint p( xMap.transform(x(i)),
00888                     yMap.transform(y(i)) );
00889 
00890                 if ( pixelMatrix.testPixel(p) )
00891                 {
00892                     polyline[count] = p;
00893                     count++;
00894                 }
00895             }
00896         }
00897         if ( int(polyline.size()) != count )
00898             polyline.resize(count);
00899     }
00900     else
00901     {
00902         for (int i = from; i <= to; i++)
00903         {
00904             const int xi = xMap.transform(x(i));
00905             const int yi = yMap.transform(y(i));
00906             QwtPainter::drawPoint(painter, xi, yi);
00907 
00908             if ( doFill )
00909                 polyline.setPoint(i - from, xi, yi);
00910         }
00911     }
00912 
00913     if ( d_data->paintAttributes & ClipPolygons )
00914     {
00915         const QwtRect r = painter->window();
00916         polyline = r.clip(polyline);
00917     }
00918 
00919     if ( doFill )
00920         fillCurve(painter, xMap, yMap, polyline);
00921 }
00922 
00933 void QwtPlotCurve::drawSteps(QPainter *painter,
00934     const QwtScaleMap &xMap, const QwtScaleMap &yMap, 
00935     int from, int to) const
00936 {
00937     QwtPointArray polyline(2 * (to - from) + 1);
00938 
00939     bool inverted = d_data->attributes & Yfx;
00940     if ( d_data->attributes & Inverted )
00941         inverted = !inverted;
00942 
00943     int i,ip;
00944     for (i = from, ip = 0; i <= to; i++, ip += 2)
00945     {
00946         const int xi = xMap.transform(x(i));
00947         const int yi = yMap.transform(y(i));
00948 
00949         if ( ip > 0 )
00950         {
00951             if (inverted)
00952                 polyline.setPoint(ip - 1, polyline[ip-2].x(), yi);
00953             else
00954                 polyline.setPoint(ip - 1, xi, polyline[ip-2].y());
00955         }
00956 
00957         polyline.setPoint(ip, xi, yi);
00958     }
00959 
00960     if ( d_data->paintAttributes & ClipPolygons )
00961     {
00962         const QwtRect r = painter->window();
00963         polyline = r.clip(polyline);
00964     }
00965 
00966     QwtPainter::drawPolyline(painter, polyline);
00967 
00968     if ( d_data->brush.style() != Qt::NoBrush )
00969         fillCurve(painter, xMap, yMap, polyline);
00970 }
00971 
00980 void QwtPlotCurve::drawSpline(QPainter *painter,
00981     const QwtScaleMap &xMap, const QwtScaleMap &yMap) const
00982 {
00983     int i;
00984 
00985     const int size = dataSize();
00986     double *txval = new double[size];
00987     double *tyval = new double[size];
00988 
00989     //
00990     // Transform x and y values to window coordinates
00991     // to avoid a distinction between linear and
00992     // logarithmic scales.
00993     //
00994     for (i=0;i<size;i++)
00995     {
00996         txval[i] = xMap.xTransform(x(i));
00997         tyval[i] = yMap.xTransform(y(i));
00998     }
00999 
01000     int stype;
01001     if (! (d_data->attributes & (Yfx|Xfy|Parametric)))
01002     {
01003         if (qwtChkMono(txval, size))
01004         {
01005             stype = Yfx;
01006         }
01007         else if(qwtChkMono(tyval, size))
01008         {
01009             stype = Xfy;
01010         }
01011         else
01012         {
01013             stype = Parametric;
01014             if ( (d_data->attributes & Periodic) ||
01015                 ( (x(0) == x(size-1))
01016                 && (y(0) == y(size-1))))
01017             {
01018                 stype |= Periodic;
01019             }
01020         }
01021     }
01022     else
01023     {
01024         stype = d_data->attributes;
01025     }
01026 
01027     bool ok = false;
01028     QwtPointArray polyline(d_data->splineSize);
01029 
01030     if (stype & Parametric)
01031     {
01032         //
01033         // setup parameter vector
01034         //
01035         double *param = new double[size];
01036         param[0] = 0.0;
01037         for (i=1; i<size; i++)
01038         {
01039             const double delta = sqrt( qwtSqr(txval[i] - txval[i-1])
01040                           + qwtSqr( tyval[i] - tyval[i-1]));
01041             param[i] = param[i-1] + qwtMax(delta, 1.0);
01042         }
01043 
01044         //
01045         // setup splines
01046         QwtSpline spx, spy;
01047         ok = spx.recalc(param, txval, size, stype & Periodic);
01048         if (ok)
01049             ok = spy.recalc(param, tyval, size, stype & Periodic);
01050 
01051         if ( ok )
01052         {
01053             // fill point array
01054             const double delta = 
01055                 param[size - 1] / double(d_data->splineSize-1);
01056             for (i = 0; i < d_data->splineSize; i++)
01057             {
01058                 const double dtmp = delta * double(i);
01059                 polyline.setPoint(i, qRound(spx.value(dtmp)), 
01060                     qRound(spy.value(dtmp)) );
01061             }
01062         }
01063         delete[] param;
01064     }
01065     else if (stype & Xfy)
01066     {
01067         if (tyval[size-1] < tyval[0])
01068         {
01069             qwtTwistArray(txval, size);
01070             qwtTwistArray(tyval, size);
01071         }
01072 
01073         // 1. Calculate spline coefficients
01074         QwtSpline spx;
01075         ok = spx.recalc(tyval, txval, size, stype & Periodic);
01076         if ( ok )
01077         {
01078             const double ymin = qwtGetMin(tyval, size);
01079             const double ymax = qwtGetMax(tyval, size);
01080             const double delta = (ymax - ymin) / double(d_data->splineSize - 1);
01081 
01082             for (i = 0; i < d_data->splineSize; i++)
01083             {
01084                 const double dtmp = ymin + delta * double(i);
01085                 polyline.setPoint(i, 
01086                     qRound(spx.value(dtmp)), qRound(dtmp + 0.5));
01087             }
01088         }
01089     }
01090     else
01091     {
01092         if (txval[size-1] < txval[0])
01093         {
01094             qwtTwistArray(tyval, size);
01095             qwtTwistArray(txval, size);
01096         }
01097 
01098         // 1. Calculate spline coefficients
01099         QwtSpline spy;
01100         ok = spy.recalc(txval, tyval, size, stype & Periodic);
01101         if ( ok )
01102         {
01103             const double xmin = qwtGetMin(txval, size);
01104             const double xmax = qwtGetMax(txval, size);
01105             const double delta = (xmax - xmin) / double(d_data->splineSize - 1);
01106 
01107             for (i = 0; i < d_data->splineSize; i++)
01108             {
01109                 double dtmp = xmin + delta * double(i);
01110                 polyline.setPoint(i, 
01111                     qRound(dtmp), qRound(spy.value(dtmp)));
01112             }
01113         }
01114     }
01115 
01116     delete[] txval;
01117     delete[] tyval;
01118 
01119     if ( ok )
01120     {
01121         if ( d_data->paintAttributes & ClipPolygons )
01122         {
01123             const QwtRect r = painter->window();
01124             polyline = r.clip(polyline);
01125         }
01126 
01127         QwtPainter::drawPolyline(painter, polyline);
01128 
01129         if ( d_data->brush.style() != Qt::NoBrush )
01130             fillCurve(painter, xMap, yMap, polyline);
01131     }
01132     else
01133         drawLines(painter, xMap, yMap, 0, size - 1);
01134 }
01135 
01166 void QwtPlotCurve::setCurveAttribute(CurveAttribute attribute, bool on)
01167 {
01168     if ( bool(d_data->attributes & attribute) == on )
01169         return;
01170 
01171     if ( on )
01172         d_data->attributes |= attribute;
01173     else
01174         d_data->attributes &= ~attribute;
01175 
01176     itemChanged();
01177 }
01178 
01183 bool QwtPlotCurve::testCurveAttribute(CurveAttribute attribute) const 
01184 { 
01185     return d_data->attributes & attribute;
01186 }
01187 
01193 void QwtPlotCurve::setSplineSize(int s)
01194 {
01195     d_data->splineSize = qwtMax(s, 10);
01196     itemChanged();
01197 }
01198 
01205 int QwtPlotCurve::splineSize() const 
01206 { 
01207     return d_data->splineSize; 
01208 }
01209 
01222 void QwtPlotCurve::fillCurve(QPainter *painter,
01223     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
01224     QwtPointArray &pa) const
01225 {
01226     if ( d_data->brush.style() == Qt::NoBrush )
01227         return;
01228 
01229     closePolyline(xMap, yMap, pa);
01230     if ( pa.count() <= 2 ) // a line can't be filled
01231         return;
01232 
01233     QBrush b = d_data->brush;
01234     if ( !b.color().isValid() )
01235         b.setColor(d_data->pen.color());
01236 
01237     painter->save();
01238 
01239     painter->setPen(QPen(Qt::NoPen));
01240     painter->setBrush(b);
01241 
01242     QwtPainter::drawPolygon(painter, pa);
01243 
01244     painter->restore();
01245 }
01246 
01256 void QwtPlotCurve::closePolyline(
01257     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
01258     QwtPointArray &pa) const
01259 {
01260     const int sz = pa.size();
01261     if ( sz < 2 )
01262         return;
01263 
01264     pa.resize(sz + 2);
01265 
01266     if ( d_data->attributes & QwtPlotCurve::Xfy )
01267     {
01268         pa.setPoint(sz,
01269             xMap.transform(d_data->reference), pa.point(sz - 1).y());
01270         pa.setPoint(sz + 1,
01271             xMap.transform(d_data->reference), pa.point(0).y());
01272     }
01273     else
01274     {
01275         pa.setPoint(sz,
01276             pa.point(sz - 1).x(), yMap.transform(d_data->reference));
01277         pa.setPoint(pa.size() - 1,
01278             pa.point(0).x(), yMap.transform(d_data->reference));
01279     }
01280 }
01281 
01291 void QwtPlotCurve::drawSymbols(QPainter *painter, const QwtSymbol &symbol,
01292     const QwtScaleMap &xMap, const QwtScaleMap &yMap, 
01293     int from, int to) const
01294 {
01295     painter->setBrush(symbol.brush());
01296     painter->setPen(symbol.pen());
01297 
01298     QRect rect;
01299     rect.setSize(QwtPainter::metricsMap().screenToLayout(symbol.size()));
01300 
01301     if ( to > from && d_data->paintAttributes & PaintFiltered )
01302     {
01303         const QRect window = painter->window();
01304         if ( window.isEmpty() )
01305             return;
01306 
01307         PrivateData::PixelMatrix pixelMatrix(window);
01308 
01309         for (int i = from; i <= to; i++)
01310         {
01311             const QPoint pi( xMap.transform(x(i)),
01312                 yMap.transform(y(i)) );
01313 
01314             if ( pixelMatrix.testPixel(pi) )
01315             {
01316                 rect.moveCenter(pi);
01317                 symbol.draw(painter, rect);
01318             }
01319         }
01320     }
01321     else
01322     {
01323         for (int i = from; i <= to; i++)
01324         {
01325             const int xi = xMap.transform(x(i));
01326             const int yi = yMap.transform(y(i));
01327 
01328             rect.moveCenter(QPoint(xi, yi));
01329             symbol.draw(painter, rect);
01330         }
01331     }
01332 }
01333 
01347 void QwtPlotCurve::setBaseline(double reference)
01348 {
01349     if ( d_data->reference != reference )
01350     {
01351         d_data->reference = reference;
01352         itemChanged();
01353     }
01354 }
01355 
01360 double QwtPlotCurve::baseline() const 
01361 { 
01362     return d_data->reference; 
01363 }
01364 
01368 int QwtPlotCurve::dataSize() const
01369 {
01370     return d_xy->size();
01371 }
01372 
01373 int QwtPlotCurve::closestPoint(const QPoint &pos, double *dist) const
01374 {
01375     if ( plot() == NULL || dataSize() <= 0 )
01376         return -1;
01377 
01378     const QwtScaleMap xMap = plot()->canvasMap(xAxis());
01379     const QwtScaleMap yMap = plot()->canvasMap(yAxis());
01380 
01381     int index = -1;
01382     double dmin = 1.0e10;
01383 
01384     for (int i=0; i < dataSize(); i++)
01385     {
01386         const double cx = xMap.xTransform(x(i)) - pos.x();
01387         const double cy = yMap.xTransform(y(i)) - pos.y();
01388 
01389         const double f = qwtSqr(cx) + qwtSqr(cy);
01390         if (f < dmin)
01391         {
01392             index = i;
01393             dmin = f;
01394         }
01395     }
01396     if ( dist )
01397         *dist = sqrt(dmin);
01398 
01399     return index;
01400 }
01401 
01402 void QwtPlotCurve::updateLegend(QwtLegend *legend) const
01403 {
01404     if ( !legend )
01405         return;
01406 
01407     QwtPlotItem::updateLegend(legend);
01408 
01409     QWidget *widget = legend->find(this);
01410     if ( !widget || !widget->inherits("QwtLegendItem") )
01411         return;
01412 
01413     QwtLegendItem *legendItem = (QwtLegendItem *)widget;
01414 
01415 #if QT_VERSION < 0x040000
01416     const bool doUpdate = legendItem->isUpdatesEnabled();
01417 #else
01418     const bool doUpdate = legendItem->updatesEnabled();
01419 #endif
01420     legendItem->setUpdatesEnabled(false);
01421 
01422     const int policy = legend->displayPolicy();
01423 
01424     if (policy == QwtLegend::Fixed)
01425     {
01426         int mode = legend->identifierMode();
01427 
01428         if (mode & QwtLegendItem::ShowLine)
01429             legendItem->setCurvePen(pen());
01430 
01431         if (mode & QwtLegendItem::ShowSymbol)
01432             legendItem->setSymbol(symbol());
01433 
01434         if (mode & QwtLegendItem::ShowText)
01435             legendItem->setText(title());
01436         else
01437             legendItem->setText(QwtText());
01438 
01439         legendItem->setIdentifierMode(mode);
01440     }
01441     else if (policy == QwtLegend::Auto)
01442     {
01443         int mode = 0;
01444 
01445         if (QwtPlotCurve::NoCurve != style())
01446         {
01447             legendItem->setCurvePen(pen());
01448             mode |= QwtLegendItem::ShowLine;
01449         }
01450         if (QwtSymbol::None != symbol().style())
01451         {
01452             legendItem->setSymbol(symbol());
01453             mode |= QwtLegendItem::ShowSymbol;
01454         }
01455         if ( !title().isEmpty() )
01456         {
01457             legendItem->setText(title());
01458             mode |= QwtLegendItem::ShowText;
01459         }
01460         else
01461         {
01462             legendItem->setText(QwtText());
01463         }
01464         legendItem->setIdentifierMode(mode);
01465     }
01466 
01467     legendItem->setUpdatesEnabled(doUpdate);
01468     legendItem->update();
01469 }

Generated on Mon Jan 30 22:16:25 2006 for Qwt User's Guide by  doxygen 1.4.4