# 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 }