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_scale_map.h"
00018 #include "qwt_double_rect.h"
00019 #include "qwt_math.h"
00020 #include "qwt_clipper.h"
00021 #include "qwt_painter.h"
00022 #include "qwt_plot.h"
00023 #include "qwt_plot_canvas.h"
00024 #include "qwt_curve_fitter.h"
00025 #include "qwt_symbol.h"
00026 #include "qwt_plot_curve.h"
00027 
00028 #define SCALE_PEN 0
00029 
00030 #if QT_VERSION < 0x040000
00031 #include <qguardedptr.h>
00032 #else
00033 #include <qpointer.h>
00034 #endif
00035 
00036 #if QT_VERSION >= 0x040000
00037 
00038 #include <qevent.h>
00039 #include <qpaintengine.h>
00040 
00041 class QwtPlotCurvePaintHelper: public QObject
00042 {
00043 public:
00044     QwtPlotCurvePaintHelper(const QwtPlotCurve *curve, int from, int to):
00045         _curve(curve),
00046         _from(from),
00047         _to(to)
00048     {
00049     }
00050 
00051     virtual bool eventFilter(QObject *, QEvent *event)
00052     {
00053         if ( event->type() == QEvent::Paint )
00054         {
00055             _curve->draw(_from, _to);
00056             return true;
00057         }
00058         return false;
00059     }
00060 private:
00061     const QwtPlotCurve *_curve;
00062     int _from;
00063     int _to;
00064 };
00065 
00066 #endif // QT_VERSION >= 0x040000
00067 
00068 // Creating and initializing a QPainter is an
00069 // expensive operation. So we keep an painter
00070 // open for situations, where we paint outside
00071 // of paint events. This improves the performance
00072 // of incremental painting like in the realtime
00073 // example a lot.
00074 // But it is not possible to have more than
00075 // one QPainter open at the same time. So we
00076 // need to close it before regular paint events
00077 // are processed.
00078 
00079 class QwtGuardedPainter: public QObject
00080 {
00081 public:
00082     ~QwtGuardedPainter()
00083     {
00084         end();
00085     }
00086 
00087     QPainter *begin(QwtPlotCanvas *canvas)
00088     {
00089         _canvas = canvas;
00090 
00091         QMap<QwtPlotCanvas *, QPainter *>::iterator it = _map.find(_canvas);
00092         if ( it == _map.end() )
00093         {
00094             QPainter *painter = new QPainter(_canvas);
00095             painter->setClipping(true);
00096             painter->setClipRect(_canvas->contentsRect());
00097 
00098             it = _map.insert(_canvas, painter);
00099             _canvas->installEventFilter(this);
00100         }
00101 #if QT_VERSION < 0x040000
00102         return it.data();
00103 #else
00104         return it.value();
00105 #endif
00106     }
00107 
00108     void end()
00109     {
00110         if ( _canvas )
00111         {
00112             QMap<QwtPlotCanvas *, QPainter *>::iterator it = _map.find(_canvas);
00113             if ( it != _map.end() )
00114             {
00115                 _canvas->removeEventFilter(this);
00116 
00117 #if QT_VERSION < 0x040000
00118                 delete it.data();
00119 #else
00120                 delete it.value();
00121 #endif
00122                 _map.erase(it);
00123             }
00124         }
00125     }
00126 
00127     virtual bool eventFilter(QObject *, QEvent *event)
00128     {
00129         if ( event->type() == QEvent::Paint )
00130             end();
00131 
00132         return false;
00133     }
00134 
00135 private:
00136 #if QT_VERSION < 0x040000 
00137     QGuardedPtr<QwtPlotCanvas> _canvas;
00138 #else
00139     QPointer<QwtPlotCanvas> _canvas;
00140 #endif
00141     static QMap<QwtPlotCanvas *, QPainter *> _map;
00142 };
00143 
00144 QMap<QwtPlotCanvas *, QPainter *> QwtGuardedPainter::_map;
00145 
00146 static QwtPolygon clipPolygon(QPainter *painter, int attributes, 
00147     const QwtPolygon &polygon)
00148 {
00149     bool doClipping = attributes & QwtPlotCurve::ClipPolygons;
00150     QRect clipRect = painter->window();
00151 
00152     if ( !doClipping )
00153     {
00154 #if QT_VERSION >= 0x040000
00155         const QPaintEngine *pe = painter->paintEngine();
00156         if ( pe && pe->type() == QPaintEngine::SVG )
00157 #else
00158         if ( painter->device()->devType() == QInternal::Picture )
00159 #endif
00160         {
00161             // The SVG paint engine ignores any clipping,
00162             // so we enable polygon clipping.
00163 
00164             doClipping = true;
00165             if ( painter->hasClipping() )
00166                 clipRect &= painter->clipRegion().boundingRect();
00167         }
00168     }
00169 
00170     if ( doClipping )
00171         return QwtClipper::clipPolygon(clipRect, polygon);
00172     
00173     return polygon;
00174 }
00175 
00176 static int verifyRange(int size, int &i1, int &i2)
00177 {
00178     if (size < 1) 
00179         return 0;
00180 
00181     i1 = qwtLim(i1, 0, size-1);
00182     i2 = qwtLim(i2, 0, size-1);
00183 
00184     if ( i1 > i2 )
00185         qSwap(i1, i2);
00186 
00187     return (i2 - i1 + 1);
00188 }
00189 
00190 class QwtPlotCurve::PrivateData
00191 {
00192 public:
00193     class PixelMatrix: private QBitArray
00194     {
00195     public:
00196         PixelMatrix(const QRect& rect):
00197             QBitArray(rect.width() * rect.height()),
00198             _rect(rect)
00199         {
00200             fill(false);
00201         }
00202 
00203         inline bool testPixel(const QPoint& pos)
00204         {
00205             if ( !_rect.contains(pos) )
00206                 return false;
00207 
00208             const int idx = _rect.width() * (pos.y() - _rect.y()) + 
00209                 (pos.x() - _rect.x());
00210 
00211             const bool marked = testBit(idx);
00212             if ( !marked )
00213                 setBit(idx, true);
00214 
00215             return !marked;
00216         }
00217 
00218     private:
00219         QRect _rect;
00220     };
00221 
00222     PrivateData():
00223         curveType(Yfx),
00224         style(QwtPlotCurve::Lines),
00225         reference(0.0),
00226         attributes(0),
00227         paintAttributes(0)
00228     {
00229         symbol = new QwtSymbol();
00230         pen = QPen(Qt::black);
00231         curveFitter = new QwtSplineCurveFitter;
00232     }
00233 
00234     ~PrivateData()
00235     {
00236         delete symbol;
00237         delete curveFitter;
00238     }
00239 
00240     QwtPlotCurve::CurveType curveType;
00241     QwtPlotCurve::CurveStyle style;
00242     double reference;
00243 
00244     QwtSymbol *symbol;
00245     QwtCurveFitter *curveFitter;
00246 
00247     QPen pen;
00248     QBrush brush;
00249 
00250     int attributes;
00251     int paintAttributes;
00252 
00253     QwtGuardedPainter guardedPainter;
00254 };
00255 
00257 QwtPlotCurve::QwtPlotCurve():
00258     QwtPlotItem(QwtText())
00259 {
00260     init();
00261 }
00262 
00267 QwtPlotCurve::QwtPlotCurve(const QwtText &title):
00268     QwtPlotItem(title)
00269 {
00270     init();
00271 }
00272 
00277 QwtPlotCurve::QwtPlotCurve(const QString &title):
00278     QwtPlotItem(QwtText(title))
00279 {
00280     init();
00281 }
00282 
00284 QwtPlotCurve::~QwtPlotCurve()
00285 {
00286     delete d_xy;
00287     delete d_data;
00288 }
00289 
00293 void QwtPlotCurve::init()
00294 {
00295     setItemAttribute(QwtPlotItem::Legend);
00296     setItemAttribute(QwtPlotItem::AutoScale);
00297 
00298     d_data = new PrivateData;
00299     d_xy = new QwtPolygonFData(QwtArray<QwtDoublePoint>());
00300 
00301     setZ(20.0);
00302 }
00303 
00305 int QwtPlotCurve::rtti() const
00306 {
00307     return QwtPlotItem::Rtti_PlotCurve;
00308 }
00309 
00333 void QwtPlotCurve::setPaintAttribute(PaintAttribute attribute, bool on)
00334 {
00335     if ( on )
00336         d_data->paintAttributes |= attribute;
00337     else
00338         d_data->paintAttributes &= ~attribute;
00339 }
00340 
00345 bool QwtPlotCurve::testPaintAttribute(PaintAttribute attribute) const
00346 {
00347     return (d_data->paintAttributes & attribute);
00348 }
00349 
00377 void QwtPlotCurve::setStyle(CurveStyle style)
00378 {
00379     if ( style != d_data->style )
00380     {
00381         d_data->style = style;
00382         itemChanged();
00383     }
00384 }
00385 
00390 QwtPlotCurve::CurveStyle QwtPlotCurve::style() const 
00391 { 
00392     return d_data->style; 
00393 }
00394 
00400 void QwtPlotCurve::setSymbol(const QwtSymbol &symbol )
00401 {
00402     delete d_data->symbol;
00403     d_data->symbol = symbol.clone();
00404     itemChanged();
00405 }
00406 
00411 const QwtSymbol &QwtPlotCurve::symbol() const 
00412 { 
00413     return *d_data->symbol; 
00414 }
00415 
00421 void QwtPlotCurve::setPen(const QPen &pen)
00422 {
00423     if ( pen != d_data->pen )
00424     {
00425         d_data->pen = pen;
00426         itemChanged();
00427     }
00428 }
00429 
00434 const QPen& QwtPlotCurve::pen() const 
00435 { 
00436     return d_data->pen; 
00437 }
00438 
00451 void QwtPlotCurve::setBrush(const QBrush &brush)
00452 {
00453     if ( brush != d_data->brush )
00454     {
00455         d_data->brush = brush;
00456         itemChanged();
00457     }
00458 }
00459 
00464 const QBrush& QwtPlotCurve::brush() const 
00465 {
00466     return d_data->brush;
00467 }
00468 
00469 
00481 void QwtPlotCurve::setData(const double *xData, const double *yData, int size)
00482 {
00483     delete d_xy;
00484     d_xy = new QwtArrayData(xData, yData, size);
00485     itemChanged();
00486 }
00487 
00496 void QwtPlotCurve::setData(const QwtArray<double> &xData, 
00497     const QwtArray<double> &yData)
00498 {
00499     delete d_xy;
00500     d_xy = new QwtArrayData(xData, yData);
00501     itemChanged();
00502 }
00503 
00510 #if QT_VERSION < 0x040000
00511 void QwtPlotCurve::setData(const QwtArray<QwtDoublePoint> &data)
00512 #else
00513 void QwtPlotCurve::setData(const QPolygonF &data)
00514 #endif
00515 {
00516     delete d_xy;
00517     d_xy = new QwtPolygonFData(data);
00518     itemChanged();
00519 }
00520 
00527 void QwtPlotCurve::setData(const QwtData &data)
00528 {
00529     delete d_xy;
00530     d_xy = data.copy();
00531     itemChanged();
00532 }
00533 
00547 void QwtPlotCurve::setRawData(const double *xData, const double *yData, int size)
00548 {
00549     delete d_xy;
00550     d_xy = new QwtCPointerData(xData, yData, size);
00551     itemChanged();
00552 }
00553 
00560 QwtDoubleRect QwtPlotCurve::boundingRect() const
00561 {
00562     if ( d_xy == NULL )
00563         return QwtDoubleRect(1.0, 1.0, -2.0, -2.0); // invalid
00564 
00565     return d_xy->boundingRect();
00566 }
00567 
00577 void QwtPlotCurve::draw(QPainter *painter,
00578     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00579     const QRect &) const
00580 {
00581     draw(painter, xMap, yMap, 0, -1);
00582 }
00583 
00601 void QwtPlotCurve::draw(int from, int to) const
00602 {
00603     if ( !plot() )
00604         return;
00605 
00606     QwtPlotCanvas *canvas = plot()->canvas();
00607 
00608 #if QT_VERSION >= 0x040000
00609 #if 0
00610     if ( canvas->paintEngine()->type() == QPaintEngine::OpenGL )
00611     {
00612         /*
00613             OpenGL alway repaint the complete widget.
00614             So for this operation OpenGL is one of the slowest
00615             environments.
00616          */
00617         canvas->repaint();
00618         return;
00619     }
00620 #endif
00621 
00622     if ( !canvas->testAttribute(Qt::WA_WState_InPaintEvent) &&
00623         !canvas->testAttribute(Qt::WA_PaintOutsidePaintEvent) )
00624     {
00625         /*
00626           We save curve and range in helper and call repaint.
00627           The helper filters the Paint event, to repeat
00628           the QwtPlotCurve::draw, but now from inside the paint
00629           event.
00630          */
00631 
00632         QwtPlotCurvePaintHelper helper(this, from, to);
00633         canvas->installEventFilter(&helper);
00634 
00635         const bool noSystemBackground =
00636             canvas->testAttribute(Qt::WA_NoSystemBackground);
00637         canvas->setAttribute(Qt::WA_NoSystemBackground, true);
00638         canvas->repaint();
00639         canvas->setAttribute(Qt::WA_NoSystemBackground, noSystemBackground);
00640 
00641         return;
00642     }
00643 #endif
00644 
00645     const QwtScaleMap xMap = plot()->canvasMap(xAxis());
00646     const QwtScaleMap yMap = plot()->canvasMap(yAxis());
00647 
00648     if ( canvas->testPaintAttribute(QwtPlotCanvas::PaintCached) &&
00649         canvas->paintCache() && !canvas->paintCache()->isNull() )
00650     {
00651         QPainter cachePainter((QPixmap *)canvas->paintCache());
00652         cachePainter.translate(-canvas->contentsRect().x(),
00653             -canvas->contentsRect().y());
00654 
00655         draw(&cachePainter, xMap, yMap, from, to);
00656     }
00657 
00658 #if QT_VERSION >= 0x040000
00659     if ( canvas->testAttribute(Qt::WA_WState_InPaintEvent) )
00660     {
00661         QPainter painter(canvas);
00662 
00663         painter.setClipping(true);
00664         painter.setClipRect(canvas->contentsRect());
00665 
00666         draw(&painter, xMap, yMap, from, to);
00667     }
00668     else
00669 #endif
00670     {
00671         QPainter *painter = d_data->guardedPainter.begin(canvas);
00672         draw(painter, xMap, yMap, from, to);
00673     }
00674 }
00675 
00687 void QwtPlotCurve::draw(QPainter *painter,
00688     const QwtScaleMap &xMap, const QwtScaleMap &yMap, 
00689     int from, int to) const
00690 {
00691     if ( !painter || dataSize() <= 0 )
00692         return;
00693 
00694     if (to < 0)
00695         to = dataSize() - 1;
00696 
00697     if ( verifyRange(dataSize(), from, to) > 0 )
00698     {
00699         painter->save();
00700         
00701         QPen pen = d_data->pen;
00702 
00703 #if SCALE_PEN
00704         if ( pen.width() > 0 )
00705         {
00706             const QwtMetricsMap &metricsMap = QwtPainter::metricsMap();
00707             pen.setWidth(metricsMap.screenToLayoutX(pen.width()));
00708         }
00709 #endif
00710             
00711         painter->setPen(pen);
00712 
00713         /*
00714           Qt 4.0.0 is slow when drawing lines, but it's even 
00715           slower when the painter has a brush. So we don't
00716           set the brush before we really need it.
00717          */
00718 
00719         drawCurve(painter, d_data->style, xMap, yMap, from, to);
00720         painter->restore();
00721 
00722         if (d_data->symbol->style() != QwtSymbol::NoSymbol)
00723         {
00724             painter->save();
00725             drawSymbols(painter, *d_data->symbol, xMap, yMap, from, to);
00726             painter->restore();
00727         }
00728     }
00729 }
00730 
00742 void QwtPlotCurve::drawCurve(QPainter *painter, int style,
00743     const QwtScaleMap &xMap, const QwtScaleMap &yMap, 
00744     int from, int to) const
00745 {
00746     switch (style)
00747     {
00748         case Lines:
00749             if ( testCurveAttribute(Fitted) )
00750             {
00751                 // we always need the complete 
00752                 // curve for fitting
00753                 from = 0;
00754                 to = dataSize() - 1;
00755             }
00756             drawLines(painter, xMap, yMap, from, to);
00757             break;
00758         case Sticks:
00759             drawSticks(painter, xMap, yMap, from, to);
00760             break;
00761         case Steps:
00762             drawSteps(painter, xMap, yMap, from, to);
00763             break;
00764         case Dots:
00765             drawDots(painter, xMap, yMap, from, to);
00766             break;
00767         case NoCurve:
00768         default:
00769             break;
00770     }
00771 }
00772 
00788 void QwtPlotCurve::drawLines(QPainter *painter,
00789     const QwtScaleMap &xMap, const QwtScaleMap &yMap, 
00790     int from, int to) const
00791 {
00792     int size = to - from + 1;
00793     if ( size <= 0 )
00794         return;
00795 
00796     QwtPolygon polyline;
00797     if ( ( d_data->attributes & Fitted ) && d_data->curveFitter )
00798     {
00799         // Transform x and y values to window coordinates
00800         // to avoid a distinction between linear and
00801         // logarithmic scales.
00802 
00803 #if QT_VERSION < 0x040000
00804         QwtArray<QwtDoublePoint> points(size);
00805 #else
00806         QPolygonF points(size);
00807 #endif
00808         for (int i = from; i <= to; i++)
00809         {
00810             QwtDoublePoint &p = points[i];
00811             p.setX( xMap.xTransform(x(i)) );
00812             p.setY( yMap.xTransform(y(i)) );
00813         }
00814 
00815         points = d_data->curveFitter->fitCurve(points);
00816         size = points.size();
00817 
00818         if ( size == 0 )
00819             return;
00820 
00821         // Round QwtDoublePoints to QPoints
00822         // When Qwt support for Qt3 has been dropped (Qwt 6.x)
00823         // we will use a doubles for painting and the following
00824         // step will be obsolete.
00825 
00826         polyline.resize(size);
00827 
00828         const QwtDoublePoint *p = points.data();
00829         QPoint *pl = polyline.data();
00830         if ( d_data->paintAttributes & PaintFiltered )
00831         {
00832 
00833             QPoint pp(qRound(p[0].x()), qRound(p[0].y()));
00834             pl[0] = pp;
00835 
00836             int count = 1;
00837             for (int i = 1; i < size; i++)
00838             {
00839                 const QPoint pi(qRound(p[i].x()), qRound(p[i].y()));
00840                 if ( pi != pp )
00841                 {
00842                     pl[count++] = pi;
00843                     pp = pi;
00844                 }
00845             }
00846             if ( count != size )
00847                 polyline.resize(count);
00848         }
00849         else
00850         {
00851             for ( int i = 0; i < size; i++ )
00852             {
00853                 pl[i].setX( qRound(p[i].x()) );
00854                 pl[i].setY( qRound(p[i].y()) );
00855             }
00856         }
00857     }
00858     else
00859     {
00860         polyline.resize(size);
00861 
00862         if ( d_data->paintAttributes & PaintFiltered )
00863         {
00864             QPoint pp( xMap.transform(x(from)), yMap.transform(y(from)) );
00865             polyline.setPoint(0, pp);
00866 
00867             int count = 1;
00868             for (int i = from + 1; i <= to; i++)
00869             {
00870                 const QPoint pi(xMap.transform(x(i)), yMap.transform(y(i)));
00871                 if ( pi != pp )
00872                 {
00873                     polyline.setPoint(count, pi);
00874                     count++;
00875 
00876                     pp = pi;
00877                 }
00878             }
00879             if ( count != size )
00880                 polyline.resize(count);
00881         }
00882         else
00883         {
00884             for (int i = from; i <= to; i++)
00885             {
00886                 int xi = xMap.transform(x(i));
00887                 int yi = yMap.transform(y(i));
00888 
00889                 polyline.setPoint(i - from, xi, yi);
00890             }
00891         }
00892     }
00893 
00894     polyline = ::clipPolygon(painter, d_data->paintAttributes, polyline);
00895 
00896     QwtPainter::drawPolyline(painter, polyline);
00897 
00898     if ( d_data->brush.style() != Qt::NoBrush )
00899         fillCurve(painter, xMap, yMap, polyline);
00900 }
00901 
00913 void QwtPlotCurve::drawSticks(QPainter *painter,
00914     const QwtScaleMap &xMap, const QwtScaleMap &yMap, 
00915     int from, int to) const
00916 {
00917     int x0 = xMap.transform(d_data->reference);
00918     int y0 = yMap.transform(d_data->reference);
00919 
00920     for (int i = from; i <= to; i++)
00921     {
00922         const int xi = xMap.transform(x(i));
00923         const int yi = yMap.transform(y(i));
00924 
00925         if (d_data->curveType == Xfy)
00926             QwtPainter::drawLine(painter, x0, yi, xi, yi);
00927         else
00928             QwtPainter::drawLine(painter, xi, y0, xi, yi);
00929     }
00930 }
00931 
00943 void QwtPlotCurve::drawDots(QPainter *painter,
00944     const QwtScaleMap &xMap, const QwtScaleMap &yMap, 
00945     int from, int to) const
00946 {
00947     const QRect window = painter->window();
00948     if ( window.isEmpty() )
00949         return;
00950 
00951     const bool doFill = d_data->brush.style() != Qt::NoBrush;
00952 
00953     QwtPolygon polyline;
00954     if ( doFill )
00955         polyline.resize(to - from + 1);
00956 
00957     if ( to > from && d_data->paintAttributes & PaintFiltered )
00958     {
00959         if ( doFill )   
00960         {
00961             QPoint pp( xMap.transform(x(from)), yMap.transform(y(from)) );
00962 
00963             QwtPainter::drawPoint(painter, pp.x(), pp.y());
00964             polyline.setPoint(0, pp);
00965 
00966             int count = 1;
00967             for (int i = from + 1; i <= to; i++)
00968             {
00969                 const QPoint pi(xMap.transform(x(i)), yMap.transform(y(i)));
00970                 if ( pi != pp )
00971                 {
00972                     QwtPainter::drawPoint(painter, pi.x(), pi.y());
00973 
00974                     polyline.setPoint(count, pi);
00975                     count++;
00976 
00977                     pp = pi;
00978                 }
00979             }
00980             if ( int(polyline.size()) != count )
00981                 polyline.resize(count);
00982         }
00983         else
00984         {
00985             // if we don't need to fill, we can sort out
00986             // duplicates independent from the order
00987 
00988             PrivateData::PixelMatrix pixelMatrix(window);
00989 
00990             for (int i = from; i <= to; i++)
00991             {
00992                 const QPoint p( xMap.transform(x(i)),
00993                     yMap.transform(y(i)) );
00994 
00995                 if ( pixelMatrix.testPixel(p) )
00996                     QwtPainter::drawPoint(painter, p.x(), p.y());
00997             }
00998         }
00999     }
01000     else
01001     {
01002         for (int i = from; i <= to; i++)
01003         {
01004             const int xi = xMap.transform(x(i));
01005             const int yi = yMap.transform(y(i));
01006             QwtPainter::drawPoint(painter, xi, yi);
01007 
01008             if ( doFill )
01009                 polyline.setPoint(i - from, xi, yi);
01010         }
01011     }
01012 
01013     if ( doFill )
01014     {
01015         polyline = ::clipPolygon(painter, d_data->paintAttributes, polyline);
01016         fillCurve(painter, xMap, yMap, polyline);
01017     }
01018 }
01019 
01034 void QwtPlotCurve::drawSteps(QPainter *painter,
01035     const QwtScaleMap &xMap, const QwtScaleMap &yMap, 
01036     int from, int to) const
01037 {
01038     QwtPolygon polyline(2 * (to - from) + 1);
01039 
01040     bool inverted = d_data->curveType == Yfx;
01041     if ( d_data->attributes & Inverted )
01042         inverted = !inverted;
01043 
01044     int i,ip;
01045     for (i = from, ip = 0; i <= to; i++, ip += 2)
01046     {
01047         const int xi = xMap.transform(x(i));
01048         const int yi = yMap.transform(y(i));
01049 
01050         if ( ip > 0 )
01051         {
01052             if (inverted)
01053                 polyline.setPoint(ip - 1, polyline[ip-2].x(), yi);
01054             else
01055                 polyline.setPoint(ip - 1, xi, polyline[ip-2].y());
01056         }
01057 
01058         polyline.setPoint(ip, xi, yi);
01059     }
01060 
01061     polyline = ::clipPolygon(painter, d_data->paintAttributes, polyline);
01062 
01063     QwtPainter::drawPolyline(painter, polyline);
01064 
01065     if ( d_data->brush.style() != Qt::NoBrush )
01066         fillCurve(painter, xMap, yMap, polyline);
01067 }
01068 
01069 
01092 void QwtPlotCurve::setCurveAttribute(CurveAttribute attribute, bool on)
01093 {
01094     if ( bool(d_data->attributes & attribute) == on )
01095         return;
01096 
01097     if ( on )
01098         d_data->attributes |= attribute;
01099     else
01100         d_data->attributes &= ~attribute;
01101 
01102     itemChanged();
01103 }
01104 
01109 bool QwtPlotCurve::testCurveAttribute(CurveAttribute attribute) const 
01110 { 
01111     return d_data->attributes & attribute;
01112 }
01113 
01130 void QwtPlotCurve::setCurveType(CurveType curveType)
01131 {
01132     if ( d_data->curveType != curveType )
01133     {
01134         d_data->curveType = curveType;
01135         itemChanged();
01136     }
01137 }
01138 
01143 QwtPlotCurve::CurveType QwtPlotCurve::curveType() const
01144 {
01145     return d_data->curveType;
01146 }
01147 
01148 void QwtPlotCurve::setCurveFitter(QwtCurveFitter *curveFitter)
01149 {
01150     delete d_data->curveFitter;
01151     d_data->curveFitter = curveFitter;
01152 
01153     itemChanged();
01154 }
01155 
01156 QwtCurveFitter *QwtPlotCurve::curveFitter() const
01157 {
01158     return d_data->curveFitter;
01159 }
01160 
01173 void QwtPlotCurve::fillCurve(QPainter *painter,
01174     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
01175     QwtPolygon &pa) const
01176 {
01177     if ( d_data->brush.style() == Qt::NoBrush )
01178         return;
01179 
01180     closePolyline(xMap, yMap, pa);
01181     if ( pa.count() <= 2 ) // a line can't be filled
01182         return;
01183 
01184     QBrush b = d_data->brush;
01185     if ( !b.color().isValid() )
01186         b.setColor(d_data->pen.color());
01187 
01188     painter->save();
01189 
01190     painter->setPen(QPen(Qt::NoPen));
01191     painter->setBrush(b);
01192 
01193     QwtPainter::drawPolygon(painter, pa);
01194 
01195     painter->restore();
01196 }
01197 
01207 void QwtPlotCurve::closePolyline(
01208     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
01209     QwtPolygon &pa) const
01210 {
01211     const int sz = pa.size();
01212     if ( sz < 2 )
01213         return;
01214 
01215     pa.resize(sz + 2);
01216 
01217     if ( d_data->curveType == QwtPlotCurve::Xfy )
01218     {
01219         pa.setPoint(sz,
01220             xMap.transform(d_data->reference), pa.point(sz - 1).y());
01221         pa.setPoint(sz + 1,
01222             xMap.transform(d_data->reference), pa.point(0).y());
01223     }
01224     else
01225     {
01226         pa.setPoint(sz,
01227             pa.point(sz - 1).x(), yMap.transform(d_data->reference));
01228         pa.setPoint(pa.size() - 1,
01229             pa.point(0).x(), yMap.transform(d_data->reference));
01230     }
01231 }
01232 
01244 void QwtPlotCurve::drawSymbols(QPainter *painter, const QwtSymbol &symbol,
01245     const QwtScaleMap &xMap, const QwtScaleMap &yMap, 
01246     int from, int to) const
01247 {
01248     painter->setBrush(symbol.brush());
01249 
01250     const QwtMetricsMap &metricsMap = QwtPainter::metricsMap();
01251 
01252     QPen pen = symbol.pen();
01253 
01254 #if SCALE_PEN
01255     if ( pen.width() > 0 )
01256         pen.setWidth(metricsMap.screenToLayoutX(pen.width()));
01257 #endif
01258 
01259     painter->setPen(pen);
01260 
01261     QRect rect;
01262     rect.setSize(metricsMap.screenToLayout(symbol.size()));
01263 
01264     if ( to > from && d_data->paintAttributes & PaintFiltered )
01265     {
01266         const QRect window = painter->window();
01267         if ( window.isEmpty() )
01268             return;
01269 
01270         PrivateData::PixelMatrix pixelMatrix(window);
01271 
01272         for (int i = from; i <= to; i++)
01273         {
01274             const QPoint pi( xMap.transform(x(i)),
01275                 yMap.transform(y(i)) );
01276 
01277             if ( pixelMatrix.testPixel(pi) )
01278             {
01279                 rect.moveCenter(pi);
01280                 symbol.draw(painter, rect);
01281             }
01282         }
01283     }
01284     else
01285     {
01286         for (int i = from; i <= to; i++)
01287         {
01288             const int xi = xMap.transform(x(i));
01289             const int yi = yMap.transform(y(i));
01290 
01291             rect.moveCenter(QPoint(xi, yi));
01292             symbol.draw(painter, rect);
01293         }
01294     }
01295 }
01296 
01310 void QwtPlotCurve::setBaseline(double reference)
01311 {
01312     if ( d_data->reference != reference )
01313     {
01314         d_data->reference = reference;
01315         itemChanged();
01316     }
01317 }
01318 
01323 double QwtPlotCurve::baseline() const 
01324 { 
01325     return d_data->reference; 
01326 }
01327 
01332 int QwtPlotCurve::dataSize() const
01333 {
01334     return d_xy->size();
01335 }
01336 
01337 int QwtPlotCurve::closestPoint(const QPoint &pos, double *dist) const
01338 {
01339     if ( plot() == NULL || dataSize() <= 0 )
01340         return -1;
01341 
01342     const QwtScaleMap xMap = plot()->canvasMap(xAxis());
01343     const QwtScaleMap yMap = plot()->canvasMap(yAxis());
01344 
01345     int index = -1;
01346     double dmin = 1.0e10;
01347 
01348     for (int i=0; i < dataSize(); i++)
01349     {
01350         const double cx = xMap.xTransform(x(i)) - pos.x();
01351         const double cy = yMap.xTransform(y(i)) - pos.y();
01352 
01353         const double f = qwtSqr(cx) + qwtSqr(cy);
01354         if (f < dmin)
01355         {
01356             index = i;
01357             dmin = f;
01358         }
01359     }
01360     if ( dist )
01361         *dist = sqrt(dmin);
01362 
01363     return index;
01364 }
01365 
01367 void QwtPlotCurve::updateLegend(QwtLegend *legend) const
01368 {
01369     if ( !legend )
01370         return;
01371 
01372     QwtPlotItem::updateLegend(legend);
01373 
01374     QWidget *widget = legend->find(this);
01375     if ( !widget || !widget->inherits("QwtLegendItem") )
01376         return;
01377 
01378     QwtLegendItem *legendItem = (QwtLegendItem *)widget;
01379 
01380 #if QT_VERSION < 0x040000
01381     const bool doUpdate = legendItem->isUpdatesEnabled();
01382 #else
01383     const bool doUpdate = legendItem->updatesEnabled();
01384 #endif
01385     legendItem->setUpdatesEnabled(false);
01386 
01387     const int policy = legend->displayPolicy();
01388 
01389     if (policy == QwtLegend::FixedIdentifier)
01390     {
01391         int mode = legend->identifierMode();
01392 
01393         if (mode & QwtLegendItem::ShowLine)
01394             legendItem->setCurvePen(pen());
01395 
01396         if (mode & QwtLegendItem::ShowSymbol)
01397             legendItem->setSymbol(symbol());
01398 
01399         if (mode & QwtLegendItem::ShowText)
01400             legendItem->setText(title());
01401         else
01402             legendItem->setText(QwtText());
01403 
01404         legendItem->setIdentifierMode(mode);
01405     }
01406     else if (policy == QwtLegend::AutoIdentifier)
01407     {
01408         int mode = 0;
01409 
01410         if (QwtPlotCurve::NoCurve != style())
01411         {
01412             legendItem->setCurvePen(pen());
01413             mode |= QwtLegendItem::ShowLine;
01414         }
01415         if (QwtSymbol::NoSymbol != symbol().style())
01416         {
01417             legendItem->setSymbol(symbol());
01418             mode |= QwtLegendItem::ShowSymbol;
01419         }
01420         if ( !title().isEmpty() )
01421         {
01422             legendItem->setText(title());
01423             mode |= QwtLegendItem::ShowText;
01424         }
01425         else
01426         {
01427             legendItem->setText(QwtText());
01428         }
01429         legendItem->setIdentifierMode(mode);
01430     }
01431 
01432     legendItem->setUpdatesEnabled(doUpdate);
01433     legendItem->update();
01434 }

Generated on Sun Mar 22 16:54:07 2009 for Qwt User's Guide by  doxygen 1.5.0