# 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 #if QT_VERSION >= 0x040000
    00029
    00030 #include <qevent.h>
    00031 #include <qpaintengine.h>
    00032
    00033 class QwtPlotCurvePaintHelper: public QObject
    00034 {
    00035 public:
    00036     QwtPlotCurvePaintHelper(const QwtPlotCurve *curve, int from, int to):
    00037         _curve(curve),
    00038         _from(from),
    00039         _to(to)
    00040     {
    00041     }
    00042
    00043     virtual bool eventFilter(QObject *, QEvent *event)
    00044     {
    00045         if ( event->type() == QEvent::Paint )
    00046         {
    00047             _curve->draw(_from, _to);
    00048             return true;
    00049         }
    00050         return false;
    00051     }
    00052 private:
    00053     const QwtPlotCurve *_curve;
    00054     int _from;
    00055     int _to;
    00056 };
    00057
    00058 #endif // QT_VERSION >= 0x040000
    00059
    00060 static int verifyRange(int size, int &i1, int &i2)
    00061 {
    00062     if (size < 1)
    00063         return 0;
    00064
    00065     i1 = qwtLim(i1, 0, size-1);
    00066     i2 = qwtLim(i2, 0, size-1);
    00067
    00068     if ( i1 > i2 )
    00069         qSwap(i1, i2);
    00070
    00071     return (i2 - i1 + 1);
    00072 }
    00073
    00074 class QwtPlotCurve::PrivateData
    00075 {
    00076 public:
    00077     class PixelMatrix: private QBitArray
    00078     {
    00079     public:
    00080         PixelMatrix(const QRect& rect):
    00081             QBitArray(rect.width() * rect.height()),
    00082             _rect(rect)
    00083         {
    00084             fill(false);
    00085         }
    00086
    00087         inline bool testPixel(const QPoint& pos)
    00088         {
    00089             if ( !_rect.contains(pos) )
    00090                 return false;
    00091
    00092             const int idx = _rect.width() * (pos.y() - _rect.y()) +
    00093                 (pos.x() - _rect.x());
    00094
    00095             const bool marked = testBit(idx);
    00096             if ( !marked )
    00097                 setBit(idx, true);
    00098
    00099             return !marked;
    00100         }
    00101
    00102     private:
    00103         QRect _rect;
    00104     };
    00105
    00106     PrivateData():
    00107         curveType(Yfx),
    00108         style(QwtPlotCurve::Lines),
    00109         reference(0.0),
    00110         attributes(0),
    00111         paintAttributes(0)
    00112     {
    00113         symbol = new QwtSymbol();
    00114         pen = QPen(Qt::black);
    00115         curveFitter = new QwtSplineCurveFitter;
    00116     }
    00117
    00118     ~PrivateData()
    00119     {
    00120         delete symbol;
    00121         delete curveFitter;
    00122     }
    00123
    00124     QwtPlotCurve::CurveType curveType;
    00125     QwtPlotCurve::CurveStyle style;
    00126     double reference;
    00127
    00128     QwtSymbol *symbol;
    00129     QwtCurveFitter *curveFitter;
    00130
    00131     QPen pen;
    00132     QBrush brush;
    00133
    00134     int attributes;
    00135     int paintAttributes;
    00136 };
    00137
    00139 QwtPlotCurve::QwtPlotCurve():
    00140     QwtPlotItem(QwtText())
    00141 {
    00142     init();
    00143 }
    00144
    00149 QwtPlotCurve::QwtPlotCurve(const QwtText &title):
    00150     QwtPlotItem(title)
    00151 {
    00152     init();
    00153 }
    00154
    00159 QwtPlotCurve::QwtPlotCurve(const QString &title):
    00160     QwtPlotItem(QwtText(title))
    00161 {
    00162     init();
    00163 }
    00164
    00166 QwtPlotCurve::~QwtPlotCurve()
    00167 {
    00168     delete d_xy;
    00169     delete d_data;
    00170 }
    00171
    00175 void QwtPlotCurve::init()
    00176 {
    00177     setItemAttribute(QwtPlotItem::Legend);
    00178     setItemAttribute(QwtPlotItem::AutoScale);
    00179
    00180     d_data = new PrivateData;
    00181     d_xy = new QwtPolygonFData(QwtArray<QwtDoublePoint>());
    00182
    00183     setZ(20.0);
    00184 }
    00185
    00187 int QwtPlotCurve::rtti() const
    00188 {
    00189     return QwtPlotItem::Rtti_PlotCurve;
    00190 }
    00191
    00215 void QwtPlotCurve::setPaintAttribute(PaintAttribute attribute, bool on)
    00216 {
    00217     if ( on )
    00218         d_data->paintAttributes |= attribute;
    00219     else
    00220         d_data->paintAttributes &= ~attribute;
    00221 }
    00222
    00227 bool QwtPlotCurve::testPaintAttribute(PaintAttribute attribute) const
    00228 {
    00229     return (d_data->paintAttributes & attribute);
    00230 }
    00231
    00259 void QwtPlotCurve::setStyle(CurveStyle style)
    00260 {
    00261     if ( style != d_data->style )
    00262     {
    00263         d_data->style = style;
    00264         itemChanged();
    00265     }
    00266 }
    00267
    00272 QwtPlotCurve::CurveStyle QwtPlotCurve::style() const
    00273 {
    00274     return d_data->style;
    00275 }
    00276
    00282 void QwtPlotCurve::setSymbol(const QwtSymbol &symbol )
    00283 {
    00284     delete d_data->symbol;
    00285     d_data->symbol = symbol.clone();
    00286     itemChanged();
    00287 }
    00288
    00293 const QwtSymbol &QwtPlotCurve::symbol() const
    00294 {
    00295     return *d_data->symbol;
    00296 }
    00297
    00303 void QwtPlotCurve::setPen(const QPen &pen)
    00304 {
    00305     if ( pen != d_data->pen )
    00306     {
    00307         d_data->pen = pen;
    00308         itemChanged();
    00309     }
    00310 }
    00311
    00316 const QPen& QwtPlotCurve::pen() const
    00317 {
    00318     return d_data->pen;
    00319 }
    00320
    00333 void QwtPlotCurve::setBrush(const QBrush &brush)
    00334 {
    00335     if ( brush != d_data->brush )
    00336     {
    00337         d_data->brush = brush;
    00338         itemChanged();
    00339     }
    00340 }
    00341
    00346 const QBrush& QwtPlotCurve::brush() const
    00347 {
    00348     return d_data->brush;
    00349 }
    00350
    00351
    00363 void QwtPlotCurve::setData(const double *xData, const double *yData, int size)
    00364 {
    00365     delete d_xy;
    00366     d_xy = new QwtArrayData(xData, yData, size);
    00367     itemChanged();
    00368 }
    00369
    00378 void QwtPlotCurve::setData(const QwtArray<double> &xData,
    00379     const QwtArray<double> &yData)
    00380 {
    00381     delete d_xy;
    00382     d_xy = new QwtArrayData(xData, yData);
    00383     itemChanged();
    00384 }
    00385
    00392 #if QT_VERSION < 0x040000
    00393 void QwtPlotCurve::setData(const QwtArray<QwtDoublePoint> &data)
    00394 #else
    00395 void QwtPlotCurve::setData(const QPolygonF &data)
    00396 #endif
    00397 {
    00398     delete d_xy;
    00399     d_xy = new QwtPolygonFData(data);
    00400     itemChanged();
    00401 }
    00402
    00409 void QwtPlotCurve::setData(const QwtData &data)
    00410 {
    00411     delete d_xy;
    00412     d_xy = data.copy();
    00413     itemChanged();
    00414 }
    00415
    00429 void QwtPlotCurve::setRawData(const double *xData, const double *yData, int size)
    00430 {
    00431     delete d_xy;
    00432     d_xy = new QwtCPointerData(xData, yData, size);
    00433     itemChanged();
    00434 }
    00435
    00442 QwtDoubleRect QwtPlotCurve::boundingRect() const
    00443 {
    00444     if ( d_xy == NULL )
    00445         return QwtDoubleRect(1.0, 1.0, -2.0, -2.0); // invalid
    00446
    00447     return d_xy->boundingRect();
    00448 }
    00449
    00459 void QwtPlotCurve::draw(QPainter *painter,
    00460     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    00461     const QRect &) const
    00462 {
    00463     draw(painter, xMap, yMap, 0, -1);
    00464 }
    00465
    00483 void QwtPlotCurve::draw(int from, int to) const
    00484 {
    00485     if ( !plot() )
    00486         return;
    00487
    00488     QwtPlotCanvas *canvas = plot()->canvas();
    00489
    00490 #if QT_VERSION >= 0x040000
    00491     if ( canvas->paintEngine()->type() == QPaintEngine::OpenGL )
    00492     {
    00493         /*
    00494             OpenGL alway repaint the complete widget.
    00495             So for this operation OpenGL is one of the slowest
    00496             environments.
    00497          */
    00498         canvas->repaint();
    00499         return;
    00500     }
    00501
    00502     if ( !canvas->testAttribute(Qt::WA_WState_InPaintEvent) &&
    00503         !canvas->testAttribute(Qt::WA_PaintOutsidePaintEvent) )
    00504     {
    00505         /*
    00506           We save curve and range in helper and call repaint.
    00507           The helper filters the Paint event, to repeat
    00508           the QwtPlotCurve::draw, but now from inside the paint
    00509           event.
    00510          */
    00511
    00512         QwtPlotCurvePaintHelper helper(this, from, to);
    00513         canvas->installEventFilter(&helper);
    00514
    00515         const bool noSystemBackground =
    00516             canvas->testAttribute(Qt::WA_NoSystemBackground);
    00517         canvas->setAttribute(Qt::WA_NoSystemBackground, true);
    00518         canvas->repaint();
    00519         canvas->setAttribute(Qt::WA_NoSystemBackground, noSystemBackground);
    00520
    00521         return;
    00522     }
    00523 #endif
    00524
    00525     const QwtScaleMap xMap = plot()->canvasMap(xAxis());
    00526     const QwtScaleMap yMap = plot()->canvasMap(yAxis());
    00527
    00528     if ( canvas->testPaintAttribute(QwtPlotCanvas::PaintCached) &&
    00529         canvas->paintCache() && !canvas->paintCache()->isNull() )
    00530     {
    00531         QPainter cachePainter((QPixmap *)canvas->paintCache());
    00532         cachePainter.translate(-canvas->contentsRect().x(),
    00533             -canvas->contentsRect().y());
    00534
    00535         draw(&cachePainter, xMap, yMap, from, to);
    00536     }
    00537
    00538     QPainter painter(canvas);
    00539
    00540     painter.setClipping(true);
    00541     painter.setClipRect(canvas->contentsRect());
    00542
    00543     draw(&painter, xMap, yMap, from, to);
    00544 }
    00545
    00557 void QwtPlotCurve::draw(QPainter *painter,
    00558     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    00559     int from, int to) const
    00560 {
    00561     if ( !painter || dataSize() <= 0 )
    00562         return;
    00563
    00564     if (to < 0)
    00565         to = dataSize() - 1;
    00566
    00567     if ( verifyRange(dataSize(), from, to) > 0 )
    00568     {
    00569         painter->save();
    00570         painter->setPen(d_data->pen);
    00571
    00572         /*
    00573           Qt 4.0.0 is slow when drawing lines, but it's even
    00574           slower when the painter has a brush. So we don't
    00575           set the brush before we really need it.
    00576          */
    00577
    00578         drawCurve(painter, d_data->style, xMap, yMap, from, to);
    00579         painter->restore();
    00580
    00581         if (d_data->symbol->style() != QwtSymbol::NoSymbol)
    00582         {
    00583             painter->save();
    00584             drawSymbols(painter, *d_data->symbol, xMap, yMap, from, to);
    00585             painter->restore();
    00586         }
    00587     }
    00588 }
    00589
    00601 void QwtPlotCurve::drawCurve(QPainter *painter, int style,
    00602     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    00603     int from, int to) const
    00604 {
    00605     switch (style)
    00606     {
    00607         case Lines:
    00608             if ( testCurveAttribute(Fitted) )
    00609             {
    00610                 // we always need the complete
    00611                 // curve for fitting
    00612                 from = 0;
    00613                 to = dataSize() - 1;
    00614             }
    00615             drawLines(painter, xMap, yMap, from, to);
    00616             break;
    00617         case Sticks:
    00618             drawSticks(painter, xMap, yMap, from, to);
    00619             break;
    00620         case Steps:
    00621             drawSteps(painter, xMap, yMap, from, to);
    00622             break;
    00623         case Dots:
    00624             drawDots(painter, xMap, yMap, from, to);
    00625             break;
    00626         case NoCurve:
    00627         default:
    00628             break;
    00629     }
    00630 }
    00631
    00647 void QwtPlotCurve::drawLines(QPainter *painter,
    00648     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    00649     int from, int to) const
    00650 {
    00651     int size = to - from + 1;
    00652     if ( size <= 0 )
    00653         return;
    00654
    00655     QwtPolygon polyline;
    00656     if ( ( d_data->attributes & Fitted ) && d_data->curveFitter )
    00657     {
    00658         // Transform x and y values to window coordinates
    00659         // to avoid a distinction between linear and
    00660         // logarithmic scales.
    00661
    00662 #if QT_VERSION < 0x040000
    00663         QwtArray<QwtDoublePoint> points(size);
    00664 #else
    00665         QPolygonF points(size);
    00666 #endif
    00667         for (int i = from; i <= to; i++)
    00668         {
    00669             QwtDoublePoint &p = points[i];
    00670             p.setX( xMap.xTransform(x(i)) );
    00671             p.setY( yMap.xTransform(y(i)) );
    00672         }
    00673
    00674         points = d_data->curveFitter->fitCurve(points);
    00675         size = points.size();
    00676
    00677         if ( size == 0 )
    00678             return;
    00679
    00680         // Round QwtDoublePoints to QPoints
    00681         // When Qwt support for Qt3 has been dropped (Qwt 6.x)
    00682         // we will use a doubles for painting and the following
    00683         // step will be obsolete.
    00684
    00685         polyline.resize(size);
    00686
    00687         const QwtDoublePoint *p = points.data();
    00688         QPoint *pl = polyline.data();
    00689         if ( d_data->paintAttributes & PaintFiltered )
    00690         {
    00691
    00692             QPoint pp(qRound(p[0].x()), qRound(p[0].y()));
    00693             pl[0] = pp;
    00694
    00695             int count = 1;
    00696             for (int i = 1; i < size; i++)
    00697             {
    00698                 const QPoint pi(qRound(p[i].x()), qRound(p[i].y()));
    00699                 if ( pi != pp )
    00700                 {
    00701                     pl[count++] = pi;
    00702                     pp = pi;
    00703                 }
    00704             }
    00705             if ( count != size )
    00706                 polyline.resize(count);
    00707         }
    00708         else
    00709         {
    00710             for ( int i = 0; i < size; i++ )
    00711             {
    00712                 pl[i].setX( qRound(p[i].x()) );
    00713                 pl[i].setY( qRound(p[i].y()) );
    00714             }
    00715         }
    00716     }
    00717     else
    00718     {
    00719         polyline.resize(size);
    00720
    00721         if ( d_data->paintAttributes & PaintFiltered )
    00722         {
    00723             QPoint pp( xMap.transform(x(from)), yMap.transform(y(from)) );
    00724             polyline.setPoint(0, pp);
    00725
    00726             int count = 1;
    00727             for (int i = from + 1; i <= to; i++)
    00728             {
    00729                 const QPoint pi(xMap.transform(x(i)), yMap.transform(y(i)));
    00730                 if ( pi != pp )
    00731                 {
    00732                     polyline.setPoint(count, pi);
    00733                     count++;
    00734
    00735                     pp = pi;
    00736                 }
    00737             }
    00738             if ( count != size )
    00739                 polyline.resize(count);
    00740         }
    00741         else
    00742         {
    00743             for (int i = from; i <= to; i++)
    00744             {
    00745                 int xi = xMap.transform(x(i));
    00746                 int yi = yMap.transform(y(i));
    00747
    00748                 polyline.setPoint(i - from, xi, yi);
    00749             }
    00750         }
    00751     }
    00752
    00753     if ( d_data->paintAttributes & ClipPolygons )
    00754         polyline = QwtClipper::clipPolygon(painter->window(), polyline);
    00755
    00756     QwtPainter::drawPolyline(painter, polyline);
    00757
    00758     if ( d_data->brush.style() != Qt::NoBrush )
    00759         fillCurve(painter, xMap, yMap, polyline);
    00760 }
    00761
    00773 void QwtPlotCurve::drawSticks(QPainter *painter,
    00774     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    00775     int from, int to) const
    00776 {
    00777     int x0 = xMap.transform(d_data->reference);
    00778     int y0 = yMap.transform(d_data->reference);
    00779
    00780     for (int i = from; i <= to; i++)
    00781     {
    00782         const int xi = xMap.transform(x(i));
    00783         const int yi = yMap.transform(y(i));
    00784
    00785         if (d_data->curveType == Xfy)
    00786             QwtPainter::drawLine(painter, x0, yi, xi, yi);
    00787         else
    00788             QwtPainter::drawLine(painter, xi, y0, xi, yi);
    00789     }
    00790 }
    00791
    00803 void QwtPlotCurve::drawDots(QPainter *painter,
    00804     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    00805     int from, int to) const
    00806 {
    00807     const QRect window = painter->window();
    00808     if ( window.isEmpty() )
    00809         return;
    00810
    00811     const bool doFill = d_data->brush.style() != Qt::NoBrush;
    00812
    00813     QwtPolygon polyline;
    00814     if ( doFill )
    00815         polyline.resize(to - from + 1);
    00816
    00817     if ( to > from && d_data->paintAttributes & PaintFiltered )
    00818     {
    00819         if ( doFill )
    00820         {
    00821             QPoint pp( xMap.transform(x(from)), yMap.transform(y(from)) );
    00822
    00823             QwtPainter::drawPoint(painter, pp.x(), pp.y());
    00824             polyline.setPoint(0, pp);
    00825
    00826             int count = 1;
    00827             for (int i = from + 1; i <= to; i++)
    00828             {
    00829                 const QPoint pi(xMap.transform(x(i)), yMap.transform(y(i)));
    00830                 if ( pi != pp )
    00831                 {
    00832                     QwtPainter::drawPoint(painter, pi.x(), pi.y());
    00833
    00834                     polyline.setPoint(count, pi);
    00835                     count++;
    00836
    00837                     pp = pi;
    00838                 }
    00839             }
    00840             if ( int(polyline.size()) != count )
    00841                 polyline.resize(count);
    00842         }
    00843         else
    00844         {
    00845             // if we don't need to fill, we can sort out
    00846             // duplicates independent from the order
    00847
    00848             PrivateData::PixelMatrix pixelMatrix(window);
    00849
    00850             for (int i = from; i <= to; i++)
    00851             {
    00852                 const QPoint p( xMap.transform(x(i)),
    00853                     yMap.transform(y(i)) );
    00854
    00855                 if ( pixelMatrix.testPixel(p) )
    00856                     QwtPainter::drawPoint(painter, p.x(), p.y());
    00857             }
    00858         }
    00859     }
    00860     else
    00861     {
    00862         for (int i = from; i <= to; i++)
    00863         {
    00864             const int xi = xMap.transform(x(i));
    00865             const int yi = yMap.transform(y(i));
    00866             QwtPainter::drawPoint(painter, xi, yi);
    00867
    00868             if ( doFill )
    00869                 polyline.setPoint(i - from, xi, yi);
    00870         }
    00871     }
    00872
    00873     if ( doFill )
    00874     {
    00875         if ( d_data->paintAttributes & ClipPolygons )
    00876             polyline = QwtClipper::clipPolygon(painter->window(), polyline);
    00877
    00878         fillCurve(painter, xMap, yMap, polyline);
    00879     }
    00880 }
    00881
    00896 void QwtPlotCurve::drawSteps(QPainter *painter,
    00897     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    00898     int from, int to) const
    00899 {
    00900     QwtPolygon polyline(2 * (to - from) + 1);
    00901
    00902     bool inverted = d_data->curveType == Yfx;
    00903     if ( d_data->attributes & Inverted )
    00904         inverted = !inverted;
    00905
    00906     int i,ip;
    00907     for (i = from, ip = 0; i <= to; i++, ip += 2)
    00908     {
    00909         const int xi = xMap.transform(x(i));
    00910         const int yi = yMap.transform(y(i));
    00911
    00912         if ( ip > 0 )
    00913         {
    00914             if (inverted)
    00915                 polyline.setPoint(ip - 1, polyline[ip-2].x(), yi);
    00916             else
    00917                 polyline.setPoint(ip - 1, xi, polyline[ip-2].y());
    00918         }
    00919
    00920         polyline.setPoint(ip, xi, yi);
    00921     }
    00922
    00923     if ( d_data->paintAttributes & ClipPolygons )
    00924         polyline = QwtClipper::clipPolygon(painter->window(), polyline);
    00925
    00926     QwtPainter::drawPolyline(painter, polyline);
    00927
    00928     if ( d_data->brush.style() != Qt::NoBrush )
    00929         fillCurve(painter, xMap, yMap, polyline);
    00930 }
    00931
    00932
    00955 void QwtPlotCurve::setCurveAttribute(CurveAttribute attribute, bool on)
    00956 {
    00957     if ( bool(d_data->attributes & attribute) == on )
    00958         return;
    00959
    00960     if ( on )
    00961         d_data->attributes |= attribute;
    00962     else
    00963         d_data->attributes &= ~attribute;
    00964
    00965     itemChanged();
    00966 }
    00967
    00972 bool QwtPlotCurve::testCurveAttribute(CurveAttribute attribute) const
    00973 {
    00974     return d_data->attributes & attribute;
    00975 }
    00976
    00993 void QwtPlotCurve::setCurveType(CurveType curveType)
    00994 {
    00995     if ( d_data->curveType != curveType )
    00996     {
    00997         d_data->curveType = curveType;
    00998         itemChanged();
    00999     }
    01000 }
    01001
    01006 QwtPlotCurve::CurveType QwtPlotCurve::curveType() const
    01007 {
    01008     return d_data->curveType;
    01009 }
    01010
    01011 void QwtPlotCurve::setCurveFitter(QwtCurveFitter *curveFitter)
    01012 {
    01013     delete d_data->curveFitter;
    01014     d_data->curveFitter = curveFitter;
    01015
    01016     itemChanged();
    01017 }
    01018
    01019 QwtCurveFitter *QwtPlotCurve::curveFitter() const
    01020 {
    01021     return d_data->curveFitter;
    01022 }
    01023
    01036 void QwtPlotCurve::fillCurve(QPainter *painter,
    01037     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    01038     QwtPolygon &pa) const
    01039 {
    01040     if ( d_data->brush.style() == Qt::NoBrush )
    01041         return;
    01042
    01043     closePolyline(xMap, yMap, pa);
    01044     if ( pa.count() <= 2 ) // a line can't be filled
    01045         return;
    01046
    01047     QBrush b = d_data->brush;
    01048     if ( !b.color().isValid() )
    01049         b.setColor(d_data->pen.color());
    01050
    01051     painter->save();
    01052
    01053     painter->setPen(QPen(Qt::NoPen));
    01054     painter->setBrush(b);
    01055
    01056     QwtPainter::drawPolygon(painter, pa);
    01057
    01058     painter->restore();
    01059 }
    01060
    01070 void QwtPlotCurve::closePolyline(
    01071     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    01072     QwtPolygon &pa) const
    01073 {
    01074     const int sz = pa.size();
    01075     if ( sz < 2 )
    01076         return;
    01077
    01078     pa.resize(sz + 2);
    01079
    01080     if ( d_data->curveType == QwtPlotCurve::Xfy )
    01081     {
    01082         pa.setPoint(sz,
    01083             xMap.transform(d_data->reference), pa.point(sz - 1).y());
    01084         pa.setPoint(sz + 1,
    01085             xMap.transform(d_data->reference), pa.point(0).y());
    01086     }
    01087     else
    01088     {
    01089         pa.setPoint(sz,
    01090             pa.point(sz - 1).x(), yMap.transform(d_data->reference));
    01091         pa.setPoint(pa.size() - 1,
    01092             pa.point(0).x(), yMap.transform(d_data->reference));
    01093     }
    01094 }
    01095
    01107 void QwtPlotCurve::drawSymbols(QPainter *painter, const QwtSymbol &symbol,
    01108     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    01109     int from, int to) const
    01110 {
    01111     painter->setBrush(symbol.brush());
    01112     painter->setPen(symbol.pen());
    01113
    01114     QRect rect;
    01115     rect.setSize(QwtPainter::metricsMap().screenToLayout(symbol.size()));
    01116
    01117     if ( to > from && d_data->paintAttributes & PaintFiltered )
    01118     {
    01119         const QRect window = painter->window();
    01120         if ( window.isEmpty() )
    01121             return;
    01122
    01123         PrivateData::PixelMatrix pixelMatrix(window);
    01124
    01125         for (int i = from; i <= to; i++)
    01126         {
    01127             const QPoint pi( xMap.transform(x(i)),
    01128                 yMap.transform(y(i)) );
    01129
    01130             if ( pixelMatrix.testPixel(pi) )
    01131             {
    01132                 rect.moveCenter(pi);
    01133                 symbol.draw(painter, rect);
    01134             }
    01135         }
    01136     }
    01137     else
    01138     {
    01139         for (int i = from; i <= to; i++)
    01140         {
    01141             const int xi = xMap.transform(x(i));
    01142             const int yi = yMap.transform(y(i));
    01143
    01144             rect.moveCenter(QPoint(xi, yi));
    01145             symbol.draw(painter, rect);
    01146         }
    01147     }
    01148 }
    01149
    01163 void QwtPlotCurve::setBaseline(double reference)
    01164 {
    01165     if ( d_data->reference != reference )
    01166     {
    01167         d_data->reference = reference;
    01168         itemChanged();
    01169     }
    01170 }
    01171
    01176 double QwtPlotCurve::baseline() const
    01177 {
    01178     return d_data->reference;
    01179 }
    01180
    01185 int QwtPlotCurve::dataSize() const
    01186 {
    01187     return d_xy->size();
    01188 }
    01189
    01190 int QwtPlotCurve::closestPoint(const QPoint &pos, double *dist) const
    01191 {
    01192     if ( plot() == NULL || dataSize() <= 0 )
    01193         return -1;
    01194
    01195     const QwtScaleMap xMap = plot()->canvasMap(xAxis());
    01196     const QwtScaleMap yMap = plot()->canvasMap(yAxis());
    01197
    01198     int index = -1;
    01199     double dmin = 1.0e10;
    01200
    01201     for (int i=0; i < dataSize(); i++)
    01202     {
    01203         const double cx = xMap.xTransform(x(i)) - pos.x();
    01204         const double cy = yMap.xTransform(y(i)) - pos.y();
    01205
    01206         const double f = qwtSqr(cx) + qwtSqr(cy);
    01207         if (f < dmin)
    01208         {
    01209             index = i;
    01210             dmin = f;
    01211         }
    01212     }
    01213     if ( dist )
    01214         *dist = sqrt(dmin);
    01215
    01216     return index;
    01217 }
    01218
    01220 void QwtPlotCurve::updateLegend(QwtLegend *legend) const
    01221 {
    01222     if ( !legend )
    01223         return;
    01224
    01225     QwtPlotItem::updateLegend(legend);
    01226
    01227     QWidget *widget = legend->find(this);
    01228     if ( !widget || !widget->inherits("QwtLegendItem") )
    01229         return;
    01230
    01231     QwtLegendItem *legendItem = (QwtLegendItem *)widget;
    01232
    01233 #if QT_VERSION < 0x040000
    01234     const bool doUpdate = legendItem->isUpdatesEnabled();
    01235 #else
    01236     const bool doUpdate = legendItem->updatesEnabled();
    01237 #endif
    01238     legendItem->setUpdatesEnabled(false);
    01239
    01240     const int policy = legend->displayPolicy();
    01241
    01242     if (policy == QwtLegend::FixedIdentifier)
    01243     {
    01244         int mode = legend->identifierMode();
    01245
    01246         if (mode & QwtLegendItem::ShowLine)
    01247             legendItem->setCurvePen(pen());
    01248
    01249         if (mode & QwtLegendItem::ShowSymbol)
    01250             legendItem->setSymbol(symbol());
    01251
    01252         if (mode & QwtLegendItem::ShowText)
    01253             legendItem->setText(title());
    01254         else
    01255             legendItem->setText(QwtText());
    01256
    01257         legendItem->setIdentifierMode(mode);
    01258     }
    01259     else if (policy == QwtLegend::AutoIdentifier)
    01260     {
    01261         int mode = 0;
    01262
    01263         if (QwtPlotCurve::NoCurve != style())
    01264         {
    01265             legendItem->setCurvePen(pen());
    01266             mode |= QwtLegendItem::ShowLine;
    01267         }
    01268         if (QwtSymbol::NoSymbol != symbol().style())
    01269         {
    01270             legendItem->setSymbol(symbol());
    01271             mode |= QwtLegendItem::ShowSymbol;
    01272         }
    01273         if ( !title().isEmpty() )
    01274         {
    01275             legendItem->setText(title());
    01276             mode |= QwtLegendItem::ShowText;
    01277         }
    01278         else
    01279         {
    01280             legendItem->setText(QwtText());
    01281         }
    01282         legendItem->setIdentifierMode(mode);
    01283     }
    01284
    01285     legendItem->setUpdatesEnabled(doUpdate);
    01286     legendItem->update();
    01287 }