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

# qwt_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 "qwt_global.h"
    00012 #include "qwt_curve.h"
    00013 #include "qwt_data.h"
    00014 #include "qwt_dimap.h"
    00015 #include "qwt_double_rect.h"
    00016 #include "qwt_math.h"
    00017 #include "qwt_painter.h"
    00018
    00022 void QwtCurve::init(const QString &title)
    00023 {
    00024     d_pen = QPen(Qt::black, 1);
    00025     d_ref = 0.0;
    00026     d_splineSize = 250;
    00027     d_options = Auto;
    00028     d_title = title;
    00029     d_style = Lines;
    00030     d_data = new QwtDoublePointData(QwtArray<QwtDoublePoint>());
    00031 }
    00032
    00036 void QwtCurve::copy(const QwtCurve &c)
    00037 {
    00038     d_ref = c.d_ref;
    00039     d_sym = c.d_sym;
    00040     d_pen = c.d_pen;
    00041     d_title = c.d_title;
    00042     d_style = c.d_style;
    00043
    00044     d_splineSize = c.d_splineSize;
    00045     d_options = c.d_options;
    00046
    00047     delete d_data;
    00048     d_data = c.d_data->copy();
    00049 }
    00050
    00052 QwtCurve::~QwtCurve()
    00053 {
    00054     delete d_data;
    00055 }
    00056
    00060 QwtCurve::QwtCurve(const QwtCurve &c)
    00061 {
    00062     init(c.d_title);
    00063     copy(c);
    00064 }
    00065
    00069 const QwtCurve& QwtCurve::operator=(const QwtCurve &c)
    00070 {
    00071     if (this != &c)
    00072     {
    00073         copy(c);
    00074         curveChanged();
    00075     }
    00076
    00077     return *this;
    00078 }
    00079
    00110 void QwtCurve::setStyle(int style, int options)
    00111 {
    00112     d_options = options;
    00113     d_style = style;
    00114     curveChanged();
    00115 }
    00116
    00122 int QwtCurve::style() const
    00123 {
    00124     return d_style;
    00125 }
    00126
    00132 void QwtCurve::setSymbol(const QwtSymbol &s )
    00133 {
    00134     d_sym = s;
    00135     curveChanged();
    00136 }
    00137
    00142 const QwtSymbol &QwtCurve::symbol() const
    00143 {
    00144     return d_sym;
    00145 }
    00146
    00147
    00152 void QwtCurve::setPen(const QPen &p)
    00153 {
    00154     if ( p != d_pen )
    00155     {
    00156         d_pen = p;
    00157         curveChanged();
    00158     }
    00159 }
    00160
    00165 const QPen& QwtCurve::pen() const
    00166 {
    00167     return d_pen;
    00168 }
    00169
    00182 void QwtCurve::setBrush(const QBrush &brush)
    00183 {
    00184     if ( brush != d_brush )
    00185     {
    00186         d_brush = brush;
    00187         curveChanged();
    00188     }
    00189 }
    00190
    00196 const QBrush& QwtCurve::brush() const
    00197 {
    00198     return d_brush;
    00199 }
    00200
    00201
    00213 void QwtCurve::setData(const double *xData, const double *yData, int size)
    00214 {
    00215     delete d_data;
    00216     d_data = new QwtArrayData(xData, yData, size);
    00217     curveChanged();
    00218 }
    00219
    00228 void QwtCurve::setData(const QwtArray<double> &xData,
    00229     const QwtArray<double> &yData)
    00230 {
    00231     delete d_data;
    00232     d_data = new QwtArrayData(xData, yData);
    00233     curveChanged();
    00234 }
    00235
    00243 void QwtCurve::setData(const QwtArray<QwtDoublePoint> &data)
    00244 {
    00245     delete d_data;
    00246     d_data = new QwtDoublePointData(data);
    00247     curveChanged();
    00248 }
    00249
    00257 void QwtCurve::setData(const QwtData &data)
    00258 {
    00259     delete d_data;
    00260     d_data = data.copy();
    00261     curveChanged();
    00262 }
    00263
    00277 void QwtCurve::setRawData(const double *xData, const double *yData, int size)
    00278 {
    00279     delete d_data;
    00280     d_data = new QwtCPointerData(xData, yData, size);
    00281     curveChanged();
    00282 }
    00283
    00288 void QwtCurve::setTitle(const QString &title)
    00289 {
    00290     d_title = title;
    00291     curveChanged();
    00292 }
    00293
    00298 const QString &QwtCurve::title() const
    00299 {
    00300     return d_title;
    00301 }
    00302
    00309 QwtDoubleRect QwtCurve::boundingRect() const
    00310 {
    00311     if ( d_data == NULL )
    00312         return QwtDoubleRect(1.0, -1.0, 1.0, -1.0); // invalid
    00313
    00314     return d_data->boundingRect();
    00315 }
    00316
    00321 QwtCurve::QwtCurve(const QString &title)
    00322 {
    00323     init(title);
    00324 }
    00325
    00331 int QwtCurve::verifyRange(int &i1, int &i2)
    00332 {
    00333     int size = dataSize();
    00334
    00335     if (size < 1) return 0;
    00336
    00337     i1 = qwtLim(i1, 0, size-1);
    00338     i2 = qwtLim(i2, 0, size-1);
    00339     qwtSort(i1, i2, i1, i2);
    00340
    00341     return (i2 - i1 + 1);
    00342 }
    00343
    00357 void QwtCurve::draw(QPainter *painter,
    00358     const QwtDiMap &xMap, const QwtDiMap &yMap, int from, int to)
    00359 {
    00360     if ( !painter || dataSize() <= 0 )
    00361         return;
    00362
    00363     if (to < 0)
    00364         to = dataSize() - 1;
    00365
    00366     if ( verifyRange(from, to) > 0 )
    00367     {
    00368         painter->save();
    00369         painter->setPen(d_pen);
    00370
    00371         QBrush b = d_brush;
    00372         if ( b.style() != Qt::NoBrush && !b.color().isValid() )
    00373             b.setColor(d_pen.color());
    00374
    00375         painter->setBrush(b);
    00376
    00377         drawCurve(painter, d_style, xMap, yMap, from, to);
    00378         painter->restore();
    00379
    00380         if (d_sym.style() != QwtSymbol::None)
    00381         {
    00382             painter->save();
    00383             drawSymbols(painter, d_sym, xMap, yMap, from, to);
    00384             painter->restore();
    00385         }
    00386     }
    00387 }
    00388
    00401 void QwtCurve::drawCurve(QPainter *painter, int style,
    00402     const QwtDiMap &xMap, const QwtDiMap &yMap, int from, int to)
    00403 {
    00404     switch (style)
    00405     {
    00406         case NoCurve:
    00407             break;
    00408         case Lines:
    00409             drawLines(painter, xMap, yMap, from, to);
    00410             break;
    00411         case Sticks:
    00412             drawSticks(painter, xMap, yMap, from, to);
    00413             break;
    00414         case Steps:
    00415             drawSteps(painter, xMap, yMap, from, to);
    00416             break;
    00417         case Spline:
    00418             if ( from > 0 || to < dataSize() - 1 )
    00419                 drawLines(painter, xMap, yMap, from, to);
    00420             else
    00421                 drawSpline(painter, xMap, yMap);
    00422             break;
    00423         case Dots:
    00424             drawDots(painter, xMap, yMap, from, to);
    00425             break;
    00426         default:
    00427             break;
    00428     }
    00429 }
    00430
    00441 void QwtCurve::drawLines(QPainter *painter,
    00442     const QwtDiMap &xMap, const QwtDiMap &yMap, int from, int to)
    00443 {
    00444     QPointArray polyline(to - from + 1);
    00445     for (int i = from; i <= to; i++)
    00446     {
    00447         int xi = xMap.transform(x(i));
    00448         int yi = yMap.transform(y(i));
    00449
    00450         polyline.setPoint(i - from, xi, yi);
    00451     }
    00452
    00453     QwtPainter::drawPolyline(painter, polyline);
    00454
    00455     if ( painter->brush().style() != Qt::NoBrush )
    00456     {
    00457         closePolyline(xMap, yMap, polyline);
    00458         painter->setPen(QPen(Qt::NoPen));
    00459         QwtPainter::drawPolygon(painter, polyline);
    00460     }
    00461 }
    00462
    00473 void QwtCurve::drawSticks(QPainter *painter,
    00474     const QwtDiMap &xMap, const QwtDiMap &yMap, int from, int to)
    00475 {
    00476     int x0 = xMap.transform(d_ref);
    00477     int y0 = yMap.transform(d_ref);
    00478
    00479     for (int i = from; i <= to; i++)
    00480     {
    00481         int xi = xMap.transform(x(i));
    00482         int yi = yMap.transform(y(i));
    00483
    00484         if (d_options & Xfy)
    00485             QwtPainter::drawLine(painter, x0, yi, xi, yi);
    00486         else
    00487             QwtPainter::drawLine(painter, xi, y0, xi, yi);
    00488     }
    00489 }
    00490
    00502 void QwtCurve::drawDots(QPainter *painter,
    00503     const QwtDiMap &xMap, const QwtDiMap &yMap, int from, int to)
    00504 {
    00505     const bool doFill = painter->brush().style() != Qt::NoBrush;
    00506
    00507     QPointArray polyline;
    00508     if ( doFill )
    00509         polyline.resize(to - from + 1);
    00510
    00511     for (int i = from; i <= to; i++)
    00512     {
    00513         int xi = xMap.transform(x(i));
    00514         int yi = yMap.transform(y(i));
    00515         QwtPainter::drawPoint(painter, xi, yi);
    00516
    00517         if ( doFill )
    00518             polyline.setPoint(i - from, xi, yi);
    00519     }
    00520
    00521     if ( doFill )
    00522     {
    00523         closePolyline(xMap, yMap, polyline);
    00524         painter->setPen(QPen(Qt::NoPen));
    00525         QwtPainter::drawPolygon(painter, polyline);
    00526     }
    00527 }
    00528
    00539 void QwtCurve::drawSteps(QPainter *painter,
    00540     const QwtDiMap &xMap, const QwtDiMap &yMap, int from, int to)
    00541 {
    00542     QPointArray polyline(2 * (to - from) + 1);
    00543
    00544     bool inverted = d_options & Yfx;
    00545     if ( d_options & Inverted )
    00546         inverted = !inverted;
    00547
    00548     int i,ip;
    00549     for (i = from, ip = 0; i <= to; i++, ip += 2)
    00550     {
    00551         int xi = xMap.transform(x(i));
    00552         int yi = yMap.transform(y(i));
    00553
    00554         if ( ip > 0 )
    00555         {
    00556             if (inverted)
    00557                 polyline.setPoint(ip - 1, polyline[ip-2].x(), yi);
    00558             else
    00559                 polyline.setPoint(ip - 1, xi, polyline[ip-2].y());
    00560         }
    00561
    00562         polyline.setPoint(ip, xi, yi);
    00563     }
    00564
    00565     QwtPainter::drawPolyline(painter, polyline);
    00566
    00567     if ( painter->brush().style() != Qt::NoBrush )
    00568     {
    00569         closePolyline(xMap, yMap, polyline);
    00570         painter->setPen(QPen(Qt::NoPen));
    00571         QwtPainter::drawPolygon(painter, polyline);
    00572     }
    00573 }
    00574
    00583 void QwtCurve::drawSpline(QPainter *painter,
    00584     const QwtDiMap &xMap, const QwtDiMap &yMap)
    00585 {
    00586     register int i;
    00587
    00588     int size = dataSize();
    00589     double *txval = new double[size];
    00590     double *tyval = new double[size];
    00591
    00592
    00593     if ( !txval || !tyval )
    00594     {
    00595         if (txval) delete[] txval;
    00596         if (tyval) delete[] tyval;
    00597         return;
    00598     }
    00599
    00600     QPointArray polyline(d_splineSize);
    00601
    00602     //
    00603     // Transform x and y values to window coordinates
    00604     // to avoid a distinction between linear and
    00605     // logarithmic scales.
    00606     //
    00607     for (i=0;i<size;i++)
    00608     {
    00609         txval[i] = xMap.xTransform(x(i));
    00610         tyval[i] = yMap.xTransform(y(i));
    00611     }
    00612
    00613     int stype;
    00614     if (! (d_options & (Yfx|Xfy|Parametric)))
    00615     {
    00616         if (qwtChkMono(txval, size))
    00617         {
    00618             stype = Yfx;
    00619         }
    00620         else
    00621         {
    00622             if(qwtChkMono(tyval, size))
    00623             {
    00624                 stype = Xfy;
    00625             }
    00626             else
    00627             {
    00628                 stype = Parametric;
    00629                 if ( (d_options & Periodic) ||
    00630                     ( (x(0) == x(size-1))
    00631                     && (y(0) == y(size-1))))
    00632                 {
    00633                     stype |= Periodic;
    00634                 }
    00635             }
    00636         }
    00637     }
    00638     else
    00639     {
    00640         stype = d_options;
    00641     }
    00642
    00643     if (stype & Parametric)
    00644     {
    00645         double *param = new double[size];
    00646         if (param)
    00647         {
    00648             //
    00649             // setup parameter vector
    00650             //
    00651             param[0] = 0.0;
    00652             for (i=1; i<size; i++)
    00653             {
    00654                 double delta = sqrt( qwtSqr(txval[i] - txval[i-1])
    00655                               + qwtSqr( tyval[i] - tyval[i-1]));
    00656                 param[i] = param[i-1] + qwtMax(delta, 1.0);
    00657             }
    00658
    00659             //
    00660             // setup splines
    00661             int rc = d_spx.recalc(param, txval, size, stype & Periodic);
    00662             if (!rc)
    00663                 rc = d_spy.recalc(param, tyval, size, stype & Periodic);
    00664
    00665             if (rc)
    00666             {
    00667                 drawLines(painter, xMap, yMap, 0, size - 1);
    00668             }
    00669             else
    00670             {
    00671                 // fill point array
    00672                 double delta = param[size - 1] / double(d_splineSize-1);
    00673                 for (i=0;i<d_splineSize;i++)
    00674                 {
    00675                     double dtmp = delta * double(i);
    00676                     polyline.setPoint(i, int(floor (d_spx.value(dtmp) + 0.5)),
    00677                                   int(floor (d_spy.value(dtmp) + 0.5)));
    00678                 }
    00679             }
    00680
    00681             delete[] param;
    00682         }
    00683     }
    00684     else if (stype & Xfy)
    00685     {
    00686         if (tyval[size-1] < tyval[0])
    00687         {
    00688             qwtTwistArray(txval, size);
    00689             qwtTwistArray(tyval, size);
    00690         }
    00691
    00692         // 1. Calculate spline coefficients
    00693         int rc = d_spx.recalc(tyval, txval, size, stype & Periodic);
    00694         if (rc)                         // an error occurred
    00695         {
    00696             drawLines(painter, xMap, yMap, 0, size - 1);
    00697         }
    00698         else                            // Spline OK
    00699         {
    00700             double ymin = qwtGetMin(tyval, size);
    00701             double ymax = qwtGetMax(tyval, size);
    00702             double delta = (ymax - ymin) / double(d_splineSize - 1);
    00703
    00704             for (i=0;i<d_splineSize;i++)
    00705             {
    00706                 double dtmp = ymin + delta * double(i);
    00707                 polyline.setPoint(i, int(floor(d_spx.value(dtmp) + 0.5)),
    00708                               int(floor(dtmp + 0.5)));
    00709             }
    00710         }
    00711     }
    00712     else
    00713     {
    00714         if (txval[size-1] < txval[0])
    00715         {
    00716             qwtTwistArray(tyval, size);
    00717             qwtTwistArray(txval, size);
    00718         }
    00719
    00720
    00721         // 1. Calculate spline coefficients
    00722         int rc = d_spy.recalc(txval, tyval, size, stype & Periodic);
    00723         if (rc)                         // error
    00724         {
    00725             drawLines(painter, xMap, yMap, 0, size - 1);
    00726         }
    00727         else                            // Spline OK
    00728         {
    00729             double xmin = qwtGetMin(txval, size);
    00730             double xmax = qwtGetMax(txval, size);
    00731             double delta = (xmax - xmin) / double(d_splineSize - 1);
    00732
    00733             for (i=0;i<d_splineSize;i++)
    00734             {
    00735                 double dtmp = xmin + delta * double(i);
    00736                 polyline.setPoint(i, int(floor (dtmp + 0.5)),
    00737                               int(floor(d_spy.value(dtmp) + 0.5)));
    00738             }
    00739         }
    00740     }
    00741
    00742     delete[] txval;
    00743     delete[] tyval;
    00744
    00745     QwtPainter::drawPolyline(painter, polyline);
    00746
    00747     if ( painter->brush().style() != Qt::NoBrush )
    00748     {
    00749         closePolyline(xMap, yMap, polyline);
    00750         painter->setPen(QPen(Qt::NoPen));
    00751         QwtPainter::drawPolygon(painter, polyline);
    00752     }
    00753 }
    00754
    00785 void QwtCurve::setOptions(int opt)
    00786 {
    00787     d_options = opt;
    00788     curveChanged();
    00789 }
    00790
    00795 int QwtCurve::options() const
    00796 {
    00797     return d_options;
    00798 }
    00799
    00805 void QwtCurve::setSplineSize(int s)
    00806 {
    00807     d_splineSize = qwtMax(s, 10);
    00808     curveChanged();
    00809 }
    00810
    00817 int QwtCurve::splineSize() const
    00818 {
    00819     return d_splineSize;
    00820 }
    00821
    00831 void QwtCurve::closePolyline(const QwtDiMap &xMap, const QwtDiMap &yMap,
    00832     QPointArray &pa) const
    00833 {
    00834     const int sz = pa.size();
    00835     if ( sz < 2 )
    00836         return;
    00837
    00838     pa.resize(sz + 2);
    00839
    00840     if ( d_options & QwtCurve::Xfy )
    00841     {
    00842         pa.setPoint(sz,
    00843             xMap.transform(d_ref), pa.point(sz - 1).y());
    00844         pa.setPoint(sz + 1,
    00845             xMap.transform(d_ref), pa.point(0).y());
    00846     }
    00847     else
    00848     {
    00849         pa.setPoint(sz,
    00850             pa.point(sz - 1).x(), yMap.transform(d_ref));
    00851         pa.setPoint(pa.size() - 1,
    00852             pa.point(0).x(), yMap.transform(d_ref));
    00853     }
    00854 }
    00855
    00865 void QwtCurve::drawSymbols(QPainter *painter, QwtSymbol &symbol,
    00866     const QwtDiMap &xMap, const QwtDiMap &yMap, int from, int to)
    00867 {
    00868     painter->setBrush(symbol.brush());
    00869     painter->setPen(symbol.pen());
    00870
    00871     QRect rect;
    00872     rect.setSize(QwtPainter::metricsMap().screenToLayout(symbol.size()));
    00873
    00874     for (int i = from; i <= to; i++)
    00875     {
    00876         const int xi = xMap.transform(x(i));
    00877         const int yi = yMap.transform(y(i));
    00878
    00879         rect.moveCenter(QPoint(xi, yi));
    00880         symbol.draw(painter, rect);
    00881     }
    00882 }
    00883
    00897 void QwtCurve::setBaseline(double ref)
    00898 {
    00899     d_ref = ref;
    00900     curveChanged();
    00901 }
    00902
    00907 double QwtCurve::baseline() const
    00908 {
    00909     return d_ref;
    00910 }
    00911
    00915 int QwtCurve::dataSize() const
    00916 {
    00917     return d_data->size();
    00918 }
    00919
    00927 void QwtCurve::curveChanged()
    00928 {
    00929 }