# 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_curve_fitter.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 static int verifyRange(int size, int &i1, int &i2)
    00060 {
    00061     if (size < 1)
    00062         return 0;
    00063
    00064     i1 = qwtLim(i1, 0, size-1);
    00065     i2 = qwtLim(i2, 0, size-1);
    00066
    00067     if ( i1 > i2 )
    00068         qSwap(i1, i2);
    00069
    00070     return (i2 - i1 + 1);
    00071 }
    00072
    00073 class QwtPlotCurve::PrivateData
    00074 {
    00075 public:
    00076     class PixelMatrix: private QBitArray
    00077     {
    00078     public:
    00079         PixelMatrix(const QRect& rect):
    00080             QBitArray(rect.width() * rect.height()),
    00081             _rect(rect)
    00082         {
    00083             fill(false);
    00084         }
    00085
    00086         inline bool testPixel(const QPoint& pos)
    00087         {
    00088             if ( !_rect.contains(pos) )
    00089                 return false;
    00090
    00091             const int idx = _rect.width() * (pos.y() - _rect.y()) +
    00092                 (pos.x() - _rect.x());
    00093
    00094             const bool marked = testBit(idx);
    00095             if ( !marked )
    00096                 setBit(idx, true);
    00097
    00098             return !marked;
    00099         }
    00100
    00101     private:
    00102         QRect _rect;
    00103     };
    00104
    00105     PrivateData():
    00106         curveType(Yfx),
    00107         style(QwtPlotCurve::Lines),
    00108         reference(0.0),
    00109         attributes(0),
    00110         paintAttributes(0)
    00111     {
    00112         pen = QPen(Qt::black, 0);
    00113         curveFitter = new QwtSplineCurveFitter;
    00114     }
    00115
    00116     ~PrivateData()
    00117     {
    00118         delete curveFitter;
    00119     }
    00120
    00121     QwtPlotCurve::CurveType curveType;
    00122     QwtPlotCurve::CurveStyle style;
    00123     double reference;
    00124
    00125     QwtSymbol sym;
    00126     QwtCurveFitter *curveFitter;
    00127
    00128     QPen pen;
    00129     QBrush brush;
    00130
    00131     int attributes;
    00132     int paintAttributes;
    00133 };
    00134
    00138 QwtPlotCurve::QwtPlotCurve():
    00139     QwtPlotItem(QwtText())
    00140 {
    00141     init();
    00142 }
    00143
    00148 QwtPlotCurve::QwtPlotCurve(const QwtText &title):
    00149     QwtPlotItem(title)
    00150 {
    00151     init();
    00152 }
    00153
    00158 QwtPlotCurve::QwtPlotCurve(const QString &title):
    00159     QwtPlotItem(QwtText(title))
    00160 {
    00161     init();
    00162 }
    00163
    00165 QwtPlotCurve::~QwtPlotCurve()
    00166 {
    00167     delete d_xy;
    00168     delete d_data;
    00169 }
    00170
    00174 void QwtPlotCurve::init()
    00175 {
    00176     setItemAttribute(QwtPlotItem::Legend);
    00177     setItemAttribute(QwtPlotItem::AutoScale);
    00178
    00179     d_data = new PrivateData;
    00180     d_xy = new QwtPolygonFData(QwtArray<QwtDoublePoint>());
    00181
    00182     setZ(20.0);
    00183 }
    00184
    00185 int QwtPlotCurve::rtti() const
    00186 {
    00187     return QwtPlotItem::Rtti_PlotCurve;
    00188 }
    00189
    00211 void QwtPlotCurve::setPaintAttribute(PaintAttribute attribute, bool on)
    00212 {
    00213     if ( on )
    00214         d_data->paintAttributes |= attribute;
    00215     else
    00216         d_data->paintAttributes &= ~attribute;
    00217 }
    00218
    00223 bool QwtPlotCurve::testPaintAttribute(PaintAttribute attribute) const
    00224 {
    00225     return (d_data->paintAttributes & attribute);
    00226 }
    00227
    00255 void QwtPlotCurve::setStyle(CurveStyle style)
    00256 {
    00257     if ( style != d_data->style )
    00258     {
    00259         d_data->style = style;
    00260         itemChanged();
    00261     }
    00262 }
    00263
    00268 QwtPlotCurve::CurveStyle QwtPlotCurve::style() const
    00269 {
    00270     return d_data->style;
    00271 }
    00272
    00278 void QwtPlotCurve::setSymbol(const QwtSymbol &s )
    00279 {
    00280     d_data->sym = s;
    00281     itemChanged();
    00282 }
    00283
    00288 const QwtSymbol &QwtPlotCurve::symbol() const
    00289 {
    00290     return d_data->sym;
    00291 }
    00292
    00298 void QwtPlotCurve::setPen(const QPen &p)
    00299 {
    00300     if ( p != d_data->pen )
    00301     {
    00302         d_data->pen = p;
    00303         itemChanged();
    00304     }
    00305 }
    00306
    00311 const QPen& QwtPlotCurve::pen() const
    00312 {
    00313     return d_data->pen;
    00314 }
    00315
    00328 void QwtPlotCurve::setBrush(const QBrush &brush)
    00329 {
    00330     if ( brush != d_data->brush )
    00331     {
    00332         d_data->brush = brush;
    00333         itemChanged();
    00334     }
    00335 }
    00336
    00341 const QBrush& QwtPlotCurve::brush() const
    00342 {
    00343     return d_data->brush;
    00344 }
    00345
    00346
    00358 void QwtPlotCurve::setData(const double *xData, const double *yData, int size)
    00359 {
    00360     delete d_xy;
    00361     d_xy = new QwtArrayData(xData, yData, size);
    00362     itemChanged();
    00363 }
    00364
    00373 void QwtPlotCurve::setData(const QwtArray<double> &xData,
    00374     const QwtArray<double> &yData)
    00375 {
    00376     delete d_xy;
    00377     d_xy = new QwtArrayData(xData, yData);
    00378     itemChanged();
    00379 }
    00380
    00387 #if QT_VERSION < 0x040000
    00388 void QwtPlotCurve::setData(const QwtArray<QwtDoublePoint> &data)
    00389 #else
    00390 void QwtPlotCurve::setData(const QPolygonF &data)
    00391 #endif
    00392 {
    00393     delete d_xy;
    00394     d_xy = new QwtPolygonFData(data);
    00395     itemChanged();
    00396 }
    00397
    00404 void QwtPlotCurve::setData(const QwtData &data)
    00405 {
    00406     delete d_xy;
    00407     d_xy = data.copy();
    00408     itemChanged();
    00409 }
    00410
    00424 void QwtPlotCurve::setRawData(const double *xData, const double *yData, int size)
    00425 {
    00426     delete d_xy;
    00427     d_xy = new QwtCPointerData(xData, yData, size);
    00428     itemChanged();
    00429 }
    00430
    00437 QwtDoubleRect QwtPlotCurve::boundingRect() const
    00438 {
    00439     if ( d_xy == NULL )
    00440         return QwtDoubleRect(1.0, 1.0, -2.0, -2.0); // invalid
    00441
    00442     return d_xy->boundingRect();
    00443 }
    00444
    00454 void QwtPlotCurve::draw(QPainter *painter,
    00455     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    00456     const QRect &) const
    00457 {
    00458     draw(painter, xMap, yMap, 0, -1);
    00459 }
    00460
    00478 void QwtPlotCurve::draw(int from, int to) const
    00479 {
    00480     if ( !plot() )
    00481         return;
    00482
    00483     QwtPlotCanvas *canvas = plot()->canvas();
    00484
    00485     bool directPaint = true;
    00486
    00487 #if QT_VERSION >= 0x040000
    00488     if ( !canvas->testAttribute(Qt::WA_WState_InPaintEvent) &&
    00489         !canvas->testAttribute(Qt::WA_PaintOutsidePaintEvent) )
    00490     {
    00491         /*
    00492           We save curve and range in helper and call repaint.
    00493           The helper filters the Paint event, to repeat
    00494           the QwtPlotCurve::draw, but now from inside the paint
    00495           event.
    00496          */
    00497
    00498         QwtPlotCurvePaintHelper helper(this, from, to);
    00499         canvas->installEventFilter(&helper);
    00500         canvas->repaint();
    00501
    00502         return;
    00503     }
    00504 #endif
    00505
    00506     const QwtScaleMap xMap = plot()->canvasMap(xAxis());
    00507     const QwtScaleMap yMap = plot()->canvasMap(yAxis());
    00508
    00509     if ( canvas->testPaintAttribute(QwtPlotCanvas::PaintCached) &&
    00510         canvas->paintCache() && !canvas->paintCache()->isNull() )
    00511     {
    00512         QPainter cachePainter((QPixmap *)canvas->paintCache());
    00513         cachePainter.translate(-canvas->contentsRect().x(),
    00514             -canvas->contentsRect().y());
    00515
    00516         draw(&cachePainter, xMap, yMap, from, to);
    00517     }
    00518
    00519     if ( directPaint )
    00520     {
    00521         QPainter painter(canvas);
    00522
    00523         painter.setClipping(true);
    00524         painter.setClipRect(canvas->contentsRect());
    00525
    00526         draw(&painter, xMap, yMap, from, to);
    00527
    00528         return;
    00529     }
    00530
    00531 #if QT_VERSION >= 0x040000
    00532     if ( canvas->testPaintAttribute(QwtPlotCanvas::PaintCached) &&
    00533         canvas->paintCache() )
    00534     {
    00535         /*
    00536           The cache is up to date. We flush it via repaint to the
    00537           canvas. This works flicker free but is much ( > 10x )
    00538           slower than direct painting.
    00539          */
    00540
    00541         const bool noBG = canvas->testAttribute(Qt::WA_NoBackground);
    00542         if ( !noBG )
    00543             canvas->setAttribute(Qt::WA_NoBackground, true);
    00544
    00545         canvas->repaint(canvas->contentsRect());
    00546
    00547         if ( !noBG )
    00548             canvas->setAttribute(Qt::WA_NoBackground, false);
    00549
    00550         return;
    00551     }
    00552 #endif
    00553
    00554     // Ok, we give up
    00555     canvas->repaint(canvas->contentsRect());
    00556 }
    00557
    00569 void QwtPlotCurve::draw(QPainter *painter,
    00570     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    00571     int from, int to) const
    00572 {
    00573     if ( !painter || dataSize() <= 0 )
    00574         return;
    00575
    00576     if (to < 0)
    00577         to = dataSize() - 1;
    00578
    00579     if ( verifyRange(dataSize(), from, to) > 0 )
    00580     {
    00581         painter->save();
    00582         painter->setPen(d_data->pen);
    00583
    00584         /*
    00585           Qt 4.0.0 is slow when drawing lines, but it´s even
    00586           slower when the painter has a brush. So we don't
    00587           set the brush before we really need it.
    00588          */
    00589
    00590         drawCurve(painter, d_data->style, xMap, yMap, from, to);
    00591         painter->restore();
    00592
    00593         if (d_data->sym.style() != QwtSymbol::NoSymbol)
    00594         {
    00595             painter->save();
    00596             drawSymbols(painter, d_data->sym, xMap, yMap, from, to);
    00597             painter->restore();
    00598         }
    00599     }
    00600 }
    00601
    00613 void QwtPlotCurve::drawCurve(QPainter *painter, int style,
    00614     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    00615     int from, int to) const
    00616 {
    00617     switch (style)
    00618     {
    00619         case Lines:
    00620             if ( testCurveAttribute(Fitted) )
    00621             {
    00622                 // we always need the complete
    00623                 // curve for fitting
    00624                 from = 0;
    00625                 to = dataSize() - 1;
    00626             }
    00627             drawLines(painter, xMap, yMap, from, to);
    00628             break;
    00629         case Sticks:
    00630             drawSticks(painter, xMap, yMap, from, to);
    00631             break;
    00632         case Steps:
    00633             drawSteps(painter, xMap, yMap, from, to);
    00634             break;
    00635         case Dots:
    00636             drawDots(painter, xMap, yMap, from, to);
    00637             break;
    00638         case NoCurve:
    00639         default:
    00640             break;
    00641     }
    00642 }
    00643
    00659 void QwtPlotCurve::drawLines(QPainter *painter,
    00660     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    00661     int from, int to) const
    00662 {
    00663     int size = to - from + 1;
    00664     if ( size <= 0 )
    00665         return;
    00666
    00667     QwtPolygon polyline;
    00668     if ( ( d_data->attributes & Fitted ) && d_data->curveFitter )
    00669     {
    00670         // Transform x and y values to window coordinates
    00671         // to avoid a distinction between linear and
    00672         // logarithmic scales.
    00673
    00674 #if QT_VERSION < 0x040000
    00675         QwtArray<QwtDoublePoint> points(size);
    00676 #else
    00677         QPolygonF points(size);
    00678 #endif
    00679         for (int i = from; i <= to; i++)
    00680         {
    00681             QwtDoublePoint &p = points[i];
    00682             p.setX( xMap.xTransform(x(i)) );
    00683             p.setY( yMap.xTransform(y(i)) );
    00684         }
    00685
    00686         points = d_data->curveFitter->fitCurve(points);
    00687         size = points.size();
    00688
    00689         if ( size == 0 )
    00690             return;
    00691
    00692         // Round QwtDoublePoints to QPoints
    00693         // When Qwt support for Qt3 has been dropped (Qwt 6.x)
    00694         // we will use a doubles for painting and the following
    00695         // step will be obsolete.
    00696
    00697         polyline.resize(size);
    00698
    00699         const QwtDoublePoint *p = points.data();
    00700         QPoint *pl = polyline.data();
    00701         if ( d_data->paintAttributes & PaintFiltered )
    00702         {
    00703
    00704             QPoint pp(qRound(p[0].x()), qRound(p[0].y()));
    00705             pl[0] = pp;
    00706
    00707             int count = 1;
    00708             for (int i = 1; i < size; i++)
    00709             {
    00710                 const QPoint pi(qRound(p[i].x()), qRound(p[i].y()));
    00711                 if ( pi != pp )
    00712                 {
    00713                     pl[count++] = pi;
    00714                     pp = pi;
    00715                 }
    00716             }
    00717             if ( count != size )
    00718                 polyline.resize(count);
    00719         }
    00720         else
    00721         {
    00722             for ( int i = 0; i < size; i++ )
    00723             {
    00724                 pl[i].setX( qRound(p[i].x()) );
    00725                 pl[i].setY( qRound(p[i].y()) );
    00726             }
    00727         }
    00728     }
    00729     else
    00730     {
    00731         polyline.resize(size);
    00732
    00733         if ( d_data->paintAttributes & PaintFiltered )
    00734         {
    00735             QPoint pp( xMap.transform(x(from)), yMap.transform(y(from)) );
    00736             polyline.setPoint(0, pp);
    00737
    00738             int count = 1;
    00739             for (int i = from + 1; i <= to; i++)
    00740             {
    00741                 const QPoint pi(xMap.transform(x(i)), yMap.transform(y(i)));
    00742                 if ( pi != pp )
    00743                 {
    00744                     polyline.setPoint(count, pi);
    00745                     count++;
    00746
    00747                     pp = pi;
    00748                 }
    00749             }
    00750             if ( count != size )
    00751                 polyline.resize(count);
    00752         }
    00753         else
    00754         {
    00755             for (int i = from; i <= to; i++)
    00756             {
    00757                 int xi = xMap.transform(x(i));
    00758                 int yi = yMap.transform(y(i));
    00759
    00760                 polyline.setPoint(i - from, xi, yi);
    00761             }
    00762         }
    00763     }
    00764
    00765     if ( d_data->paintAttributes & ClipPolygons )
    00766     {
    00767         QwtRect r = painter->window();
    00768         polyline = r.clip(polyline);
    00769     }
    00770
    00771     QwtPainter::drawPolyline(painter, polyline);
    00772
    00773     if ( d_data->brush.style() != Qt::NoBrush )
    00774         fillCurve(painter, xMap, yMap, polyline);
    00775 }
    00776
    00788 void QwtPlotCurve::drawSticks(QPainter *painter,
    00789     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    00790     int from, int to) const
    00791 {
    00792     int x0 = xMap.transform(d_data->reference);
    00793     int y0 = yMap.transform(d_data->reference);
    00794
    00795     for (int i = from; i <= to; i++)
    00796     {
    00797         const int xi = xMap.transform(x(i));
    00798         const int yi = yMap.transform(y(i));
    00799
    00800         if (d_data->curveType == Xfy)
    00801             QwtPainter::drawLine(painter, x0, yi, xi, yi);
    00802         else
    00803             QwtPainter::drawLine(painter, xi, y0, xi, yi);
    00804     }
    00805 }
    00806
    00818 void QwtPlotCurve::drawDots(QPainter *painter,
    00819     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    00820     int from, int to) const
    00821 {
    00822     const QRect window = painter->window();
    00823     if ( window.isEmpty() )
    00824         return;
    00825
    00826     const bool doFill = d_data->brush.style() != Qt::NoBrush;
    00827
    00828     QwtPolygon polyline;
    00829     if ( doFill )
    00830         polyline.resize(to - from + 1);
    00831
    00832     if ( to > from && d_data->paintAttributes & PaintFiltered )
    00833     {
    00834         if ( doFill )
    00835         {
    00836             QPoint pp( xMap.transform(x(from)), yMap.transform(y(from)) );
    00837
    00838             QwtPainter::drawPoint(painter, pp.x(), pp.y());
    00839             polyline.setPoint(0, pp);
    00840
    00841             int count = 1;
    00842             for (int i = from + 1; i <= to; i++)
    00843             {
    00844                 const QPoint pi(xMap.transform(x(i)), yMap.transform(y(i)));
    00845                 if ( pi != pp )
    00846                 {
    00847                     QwtPainter::drawPoint(painter, pi.x(), pi.y());
    00848
    00849                     polyline.setPoint(count, pi);
    00850                     count++;
    00851
    00852                     pp = pi;
    00853                 }
    00854             }
    00855             if ( int(polyline.size()) != count )
    00856                 polyline.resize(count);
    00857         }
    00858         else
    00859         {
    00860             // if we don't need to fill, we can sort out
    00861             // duplicates independent from the order
    00862
    00863             PrivateData::PixelMatrix pixelMatrix(window);
    00864
    00865             for (int i = from; i <= to; i++)
    00866             {
    00867                 const QPoint p( xMap.transform(x(i)),
    00868                     yMap.transform(y(i)) );
    00869
    00870                 if ( pixelMatrix.testPixel(p) )
    00871                     QwtPainter::drawPoint(painter, p.x(), p.y());
    00872             }
    00873         }
    00874     }
    00875     else
    00876     {
    00877         for (int i = from; i <= to; i++)
    00878         {
    00879             const int xi = xMap.transform(x(i));
    00880             const int yi = yMap.transform(y(i));
    00881             QwtPainter::drawPoint(painter, xi, yi);
    00882
    00883             if ( doFill )
    00884                 polyline.setPoint(i - from, xi, yi);
    00885         }
    00886     }
    00887
    00888     if ( doFill )
    00889     {
    00890         if ( d_data->paintAttributes & ClipPolygons )
    00891         {
    00892             const QwtRect r = painter->window();
    00893             polyline = r.clip(polyline);
    00894         }
    00895
    00896         fillCurve(painter, xMap, yMap, polyline);
    00897     }
    00898 }
    00899
    00914 void QwtPlotCurve::drawSteps(QPainter *painter,
    00915     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    00916     int from, int to) const
    00917 {
    00918     QwtPolygon polyline(2 * (to - from) + 1);
    00919
    00920     bool inverted = d_data->curveType == Yfx;
    00921     if ( d_data->attributes & Inverted )
    00922         inverted = !inverted;
    00923
    00924     int i,ip;
    00925     for (i = from, ip = 0; i <= to; i++, ip += 2)
    00926     {
    00927         const int xi = xMap.transform(x(i));
    00928         const int yi = yMap.transform(y(i));
    00929
    00930         if ( ip > 0 )
    00931         {
    00932             if (inverted)
    00933                 polyline.setPoint(ip - 1, polyline[ip-2].x(), yi);
    00934             else
    00935                 polyline.setPoint(ip - 1, xi, polyline[ip-2].y());
    00936         }
    00937
    00938         polyline.setPoint(ip, xi, yi);
    00939     }
    00940
    00941     if ( d_data->paintAttributes & ClipPolygons )
    00942     {
    00943         const QwtRect r = painter->window();
    00944         polyline = r.clip(polyline);
    00945     }
    00946
    00947     QwtPainter::drawPolyline(painter, polyline);
    00948
    00949     if ( d_data->brush.style() != Qt::NoBrush )
    00950         fillCurve(painter, xMap, yMap, polyline);
    00951 }
    00952
    00953
    00976 void QwtPlotCurve::setCurveAttribute(CurveAttribute attribute, bool on)
    00977 {
    00978     if ( bool(d_data->attributes & attribute) == on )
    00979         return;
    00980
    00981     if ( on )
    00982         d_data->attributes |= attribute;
    00983     else
    00984         d_data->attributes &= ~attribute;
    00985
    00986     itemChanged();
    00987 }
    00988
    00993 bool QwtPlotCurve::testCurveAttribute(CurveAttribute attribute) const
    00994 {
    00995     return d_data->attributes & attribute;
    00996 }
    00997
    01014 void QwtPlotCurve::setCurveType(CurveType curveType)
    01015 {
    01016     if ( d_data->curveType != curveType )
    01017     {
    01018         d_data->curveType = curveType;
    01019         itemChanged();
    01020     }
    01021 }
    01022
    01027 QwtPlotCurve::CurveType QwtPlotCurve::curveType() const
    01028 {
    01029     return d_data->curveType;
    01030 }
    01031
    01032 void QwtPlotCurve::setCurveFitter(QwtCurveFitter *curveFitter)
    01033 {
    01034     delete d_data->curveFitter;
    01035     d_data->curveFitter = curveFitter;
    01036
    01037     itemChanged();
    01038 }
    01039
    01040 QwtCurveFitter *QwtPlotCurve::curveFitter() const
    01041 {
    01042     return d_data->curveFitter;
    01043 }
    01044
    01057 void QwtPlotCurve::fillCurve(QPainter *painter,
    01058     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    01059     QwtPolygon &pa) const
    01060 {
    01061     if ( d_data->brush.style() == Qt::NoBrush )
    01062         return;
    01063
    01064     closePolyline(xMap, yMap, pa);
    01065     if ( pa.count() <= 2 ) // a line can't be filled
    01066         return;
    01067
    01068     QBrush b = d_data->brush;
    01069     if ( !b.color().isValid() )
    01070         b.setColor(d_data->pen.color());
    01071
    01072     painter->save();
    01073
    01074     painter->setPen(QPen(Qt::NoPen));
    01075     painter->setBrush(b);
    01076
    01077     QwtPainter::drawPolygon(painter, pa);
    01078
    01079     painter->restore();
    01080 }
    01081
    01091 void QwtPlotCurve::closePolyline(
    01092     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    01093     QwtPolygon &pa) const
    01094 {
    01095     const int sz = pa.size();
    01096     if ( sz < 2 )
    01097         return;
    01098
    01099     pa.resize(sz + 2);
    01100
    01101     if ( d_data->curveType == QwtPlotCurve::Xfy )
    01102     {
    01103         pa.setPoint(sz,
    01104             xMap.transform(d_data->reference), pa.point(sz - 1).y());
    01105         pa.setPoint(sz + 1,
    01106             xMap.transform(d_data->reference), pa.point(0).y());
    01107     }
    01108     else
    01109     {
    01110         pa.setPoint(sz,
    01111             pa.point(sz - 1).x(), yMap.transform(d_data->reference));
    01112         pa.setPoint(pa.size() - 1,
    01113             pa.point(0).x(), yMap.transform(d_data->reference));
    01114     }
    01115 }
    01116
    01128 void QwtPlotCurve::drawSymbols(QPainter *painter, const QwtSymbol &symbol,
    01129     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    01130     int from, int to) const
    01131 {
    01132     painter->setBrush(symbol.brush());
    01133     painter->setPen(symbol.pen());
    01134
    01135     QRect rect;
    01136     rect.setSize(QwtPainter::metricsMap().screenToLayout(symbol.size()));
    01137
    01138     if ( to > from && d_data->paintAttributes & PaintFiltered )
    01139     {
    01140         const QRect window = painter->window();
    01141         if ( window.isEmpty() )
    01142             return;
    01143
    01144         PrivateData::PixelMatrix pixelMatrix(window);
    01145
    01146         for (int i = from; i <= to; i++)
    01147         {
    01148             const QPoint pi( xMap.transform(x(i)),
    01149                 yMap.transform(y(i)) );
    01150
    01151             if ( pixelMatrix.testPixel(pi) )
    01152             {
    01153                 rect.moveCenter(pi);
    01154                 symbol.draw(painter, rect);
    01155             }
    01156         }
    01157     }
    01158     else
    01159     {
    01160         for (int i = from; i <= to; i++)
    01161         {
    01162             const int xi = xMap.transform(x(i));
    01163             const int yi = yMap.transform(y(i));
    01164
    01165             rect.moveCenter(QPoint(xi, yi));
    01166             symbol.draw(painter, rect);
    01167         }
    01168     }
    01169 }
    01170
    01184 void QwtPlotCurve::setBaseline(double reference)
    01185 {
    01186     if ( d_data->reference != reference )
    01187     {
    01188         d_data->reference = reference;
    01189         itemChanged();
    01190     }
    01191 }
    01192
    01197 double QwtPlotCurve::baseline() const
    01198 {
    01199     return d_data->reference;
    01200 }
    01201
    01206 int QwtPlotCurve::dataSize() const
    01207 {
    01208     return d_xy->size();
    01209 }
    01210
    01211 int QwtPlotCurve::closestPoint(const QPoint &pos, double *dist) const
    01212 {
    01213     if ( plot() == NULL || dataSize() <= 0 )
    01214         return -1;
    01215
    01216     const QwtScaleMap xMap = plot()->canvasMap(xAxis());
    01217     const QwtScaleMap yMap = plot()->canvasMap(yAxis());
    01218
    01219     int index = -1;
    01220     double dmin = 1.0e10;
    01221
    01222     for (int i=0; i < dataSize(); i++)
    01223     {
    01224         const double cx = xMap.xTransform(x(i)) - pos.x();
    01225         const double cy = yMap.xTransform(y(i)) - pos.y();
    01226
    01227         const double f = qwtSqr(cx) + qwtSqr(cy);
    01228         if (f < dmin)
    01229         {
    01230             index = i;
    01231             dmin = f;
    01232         }
    01233     }
    01234     if ( dist )
    01235         *dist = sqrt(dmin);
    01236
    01237     return index;
    01238 }
    01239
    01240 void QwtPlotCurve::updateLegend(QwtLegend *legend) const
    01241 {
    01242     if ( !legend )
    01243         return;
    01244
    01245     QwtPlotItem::updateLegend(legend);
    01246
    01247     QWidget *widget = legend->find(this);
    01248     if ( !widget || !widget->inherits("QwtLegendItem") )
    01249         return;
    01250
    01251     QwtLegendItem *legendItem = (QwtLegendItem *)widget;
    01252
    01253 #if QT_VERSION < 0x040000
    01254     const bool doUpdate = legendItem->isUpdatesEnabled();
    01255 #else
    01256     const bool doUpdate = legendItem->updatesEnabled();
    01257 #endif
    01258     legendItem->setUpdatesEnabled(false);
    01259
    01260     const int policy = legend->displayPolicy();
    01261
    01262     if (policy == QwtLegend::FixedIdentifier)
    01263     {
    01264         int mode = legend->identifierMode();
    01265
    01266         if (mode & QwtLegendItem::ShowLine)
    01267             legendItem->setCurvePen(pen());
    01268
    01269         if (mode & QwtLegendItem::ShowSymbol)
    01270             legendItem->setSymbol(symbol());
    01271
    01272         if (mode & QwtLegendItem::ShowText)
    01273             legendItem->setText(title());
    01274         else
    01275             legendItem->setText(QwtText());
    01276
    01277         legendItem->setIdentifierMode(mode);
    01278     }
    01279     else if (policy == QwtLegend::AutoIdentifier)
    01280     {
    01281         int mode = 0;
    01282
    01283         if (QwtPlotCurve::NoCurve != style())
    01284         {
    01285             legendItem->setCurvePen(pen());
    01286             mode |= QwtLegendItem::ShowLine;
    01287         }
    01288         if (QwtSymbol::NoSymbol != symbol().style())
    01289         {
    01290             legendItem->setSymbol(symbol());
    01291             mode |= QwtLegendItem::ShowSymbol;
    01292         }
    01293         if ( !title().isEmpty() )
    01294         {
    01295             legendItem->setText(title());
    01296             mode |= QwtLegendItem::ShowText;
    01297         }
    01298         else
    01299         {
    01300             legendItem->setText(QwtText());
    01301         }
    01302         legendItem->setIdentifierMode(mode);
    01303     }
    01304
    01305     legendItem->setUpdatesEnabled(doUpdate);
    01306     legendItem->update();
    01307 }