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

qwt_curve.cpp

Go to the documentation of this file.
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_math.h"
00012 #include "qwt_dimap.h"
00013 #include "qwt_painter.h"
00014 #include "qwt_curve.h"
00015 
00019 void QwtCurve::init(const QString &title)
00020 {
00021     d_pen = QPen(Qt::black, 1);
00022     d_ref = 0.0;
00023     d_splineSize = 250;
00024     d_options = Auto;
00025     d_raw = FALSE;
00026     d_title = title;
00027     d_style = Lines;
00028   d_rangeCache.isDirty = TRUE;
00029 }
00030 
00034 void QwtCurve::copy(const QwtCurve &c)
00035 {
00036     d_ref = c.d_ref;
00037     d_sym = c.d_sym;
00038     d_pen = c.d_pen;
00039     d_title = c.d_title;
00040     d_raw = FALSE;
00041     d_style = c.d_style;
00042 
00043     d_splineSize = c.d_splineSize;
00044     d_options = c.d_options;
00045 
00046     if (c.d_raw)
00047     {
00048        d_x.duplicate(c.d_x);
00049        d_y.duplicate(c.d_y);
00050     }
00051     else
00052     {
00053        d_x = c.d_x;
00054        d_y = c.d_y;
00055     }
00056   d_rangeCache = c.d_rangeCache;
00057 }
00058 
00060 QwtCurve::~QwtCurve()
00061 {
00062     if (d_raw)
00063     {
00064         d_x.resetRawData(d_x.data(), d_x.size());
00065         d_y.resetRawData(d_y.data(), d_y.size());
00066     }
00067 }
00068 
00076 QwtCurve::QwtCurve(const QwtCurve &c)
00077 {
00078     init(c.d_title);
00079     copy(c);
00080 }
00081 
00089 const QwtCurve& QwtCurve::operator=(const QwtCurve &c)
00090 {
00091     copy(c);
00092     curveChanged();
00093     return *this;
00094 }
00095 
00126 void QwtCurve::setStyle(int style, int options)
00127 {
00128     d_options = options;
00129     d_style = style;
00130     curveChanged();
00131 }
00132 
00138 int QwtCurve::style() const 
00139 { 
00140     return d_style; 
00141 }
00142 
00148 void QwtCurve::setSymbol(const QwtSymbol &s )
00149 {
00150     d_sym = s;
00151     curveChanged();
00152 }
00153 
00158 const QwtSymbol &QwtCurve::symbol() const 
00159 { 
00160     return d_sym; 
00161 }
00162 
00163 
00168 void QwtCurve::setPen(const QPen &p)
00169 {
00170     if ( p != d_pen )
00171     {
00172         d_pen = p;
00173         curveChanged();
00174     }
00175 }
00176 
00181 const QPen& QwtCurve::pen() const 
00182 { 
00183     return d_pen; 
00184 }
00185 
00198 void QwtCurve::setBrush(const QBrush &brush)
00199 {
00200     if ( brush != d_brush )
00201     {
00202         d_brush = brush;
00203         curveChanged();
00204     }
00205 }
00206 
00212 const QBrush& QwtCurve::brush() const 
00213 {
00214     return d_brush;
00215 }
00216 
00217 
00224 void QwtCurve::setData(const double *x, const double *y, int size)
00225 {
00226     if (d_raw)
00227     {
00228         d_x.resetRawData(d_x.data(), d_x.size());
00229         d_y.resetRawData(d_y.data(), d_y.size());
00230     }
00231     d_x.duplicate(x, size);
00232     d_y.duplicate(y, size);
00233     d_raw = FALSE;
00234   d_rangeCache.isDirty = TRUE;
00235 
00236     curveChanged();
00237 }
00238 
00253 void QwtCurve::setRawData(const double *x, const double *y, int size)
00254 {
00255     if (d_raw)
00256     {
00257         d_x.resetRawData(d_x.data(), d_x.size());
00258         d_y.resetRawData(d_y.data(), d_y.size());
00259     }
00260 
00261     d_x.setRawData(x, size);
00262     d_y.setRawData(y, size);
00263     d_raw = TRUE;
00264   d_rangeCache.isDirty = TRUE;
00265 
00266     curveChanged();
00267 }
00268 
00273 void QwtCurve::setTitle(const QString &title)
00274 {
00275     d_title = title;
00276     curveChanged();
00277 }
00278 
00283 const QString &QwtCurve::title() const 
00284 { 
00285     return d_title; 
00286 }
00287 
00291 double QwtCurve::minXValue() const
00292 {
00293   if ( d_rangeCache.isDirty )
00294     ((QwtCurve *)this)->updateRangeCache();
00295 
00296     return d_rangeCache.minXValue;
00297 }
00298 
00302 double QwtCurve::minYValue() const
00303 {
00304   if ( d_rangeCache.isDirty )
00305     ((QwtCurve *)this)->updateRangeCache();
00306 
00307     return d_rangeCache.minYValue;
00308 }
00309 
00313 double QwtCurve::maxXValue() const
00314 {
00315   if ( d_rangeCache.isDirty )
00316     ((QwtCurve *)this)->updateRangeCache();
00317 
00318     return d_rangeCache.maxXValue;
00319 }
00320 
00324 double QwtCurve::maxYValue() const
00325 {
00326   if ( d_rangeCache.isDirty )
00327     ((QwtCurve *)this)->updateRangeCache();
00328 
00329     return d_rangeCache.maxYValue;
00330 }
00331 
00336 QwtCurve::QwtCurve(const QString &title)
00337 {
00338     init(title);
00339 }
00340 
00346 int QwtCurve::verifyRange(int &i1, int &i2)
00347 {
00348     int size = dataSize();
00349 
00350     if (size < 1) return 0;
00351 
00352     i1 = qwtLim(i1, 0, size-1);
00353     i2 = qwtLim(i2, 0, size-1);
00354     qwtSort(i1, i2, i1, i2);
00355 
00356     return (i2 - i1 + 1);
00357 }
00358 
00370 void QwtCurve::draw(QPainter *painter,
00371     const QwtDiMap &xMap, const QwtDiMap &yMap, int from, int to)
00372 {
00373     if ( !painter || dataSize() <= 0 )
00374         return;
00375 
00376     if (to < 0)
00377         to = dataSize() - 1;
00378 
00379     if ( verifyRange(from, to) > 0 )
00380     {
00381         painter->save();
00382         painter->setPen(d_pen);
00383 
00384         QBrush b = d_brush;
00385         if ( b.style() != Qt::NoBrush && !b.color().isValid() )
00386             b.setColor(d_pen.color());
00387 
00388         painter->setBrush(b);
00389 
00390         drawCurve(painter, d_style, xMap, yMap, from, to);
00391         painter->restore();
00392 
00393         if (d_sym.style() != QwtSymbol::None)
00394         {
00395             painter->save();
00396             drawSymbols(painter, d_sym, xMap, yMap, from, to);
00397             painter->restore();
00398         }
00399     }
00400 }
00401 
00414 void QwtCurve::drawCurve(QPainter *painter, int style,
00415     const QwtDiMap &xMap, const QwtDiMap &yMap, int from, int to)
00416 {
00417     switch (style)
00418     {
00419         case NoCurve:
00420             break;
00421         case Lines:
00422             drawLines(painter, xMap, yMap, from, to);
00423             break;
00424         case Sticks:
00425             drawSticks(painter, xMap, yMap, from, to);
00426             break;
00427         case Steps:
00428             drawSteps(painter, xMap, yMap, from, to);
00429             break;
00430         case Spline:
00431             if ( from > 0 || to < dataSize() - 1 )
00432                 drawLines(painter, xMap, yMap, from, to);
00433             else
00434                 drawSpline(painter, xMap, yMap);
00435             break;
00436         case Dots:
00437             drawDots(painter, xMap, yMap, from, to);
00438             break;
00439         default:
00440             break;
00441     }
00442 }
00443 
00454 void QwtCurve::drawLines(QPainter *painter,
00455     const QwtDiMap &xMap, const QwtDiMap &yMap, int from, int to)
00456 {
00457     QPointArray polyline(to - from + 1);
00458     for (register int i = from; i <= to; i++)
00459     {
00460         int x = xMap.transform(d_x[i]);
00461         int y = yMap.transform(d_y[i]);
00462 
00463         polyline.setPoint(i - from, x, y);
00464     }
00465 
00466     QwtPainter::drawPolyline(painter, polyline);
00467 
00468     if ( painter->brush().style() != Qt::NoBrush )
00469     {
00470         closePolyline(xMap, yMap, polyline);
00471         painter->setPen(QPen(QPen::NoPen));
00472         QwtPainter::drawPolygon(painter, polyline);
00473     }
00474 }
00475 
00486 void QwtCurve::drawSticks(QPainter *painter,
00487     const QwtDiMap &xMap, const QwtDiMap &yMap, int from, int to)
00488 {
00489     int x0 = xMap.transform(d_ref);
00490     int y0 = yMap.transform(d_ref);
00491 
00492     for (int i = from; i <= to; i++)
00493     {
00494         int x = xMap.transform(d_x[i]);
00495         int y = yMap.transform(d_y[i]);
00496 
00497         if (d_options & Xfy)
00498             QwtPainter::drawLine(painter, x0, y, x, y);
00499         else
00500             QwtPainter::drawLine(painter, x, y0, x, y);
00501     }
00502 }
00503 
00514 void QwtCurve::drawDots(QPainter *painter,
00515     const QwtDiMap &xMap, const QwtDiMap &yMap, int from, int to)
00516 {
00517     const bool doFill = painter->brush().style() != Qt::NoBrush;
00518 
00519     QPointArray polyline;
00520     if ( doFill )
00521         polyline.resize(to - from + 1);
00522 
00523     for (register int i = from; i <= to; i++)
00524     {
00525         int x = xMap.transform(d_x[i]);
00526         int y = yMap.transform(d_y[i]);
00527         QwtPainter::drawPoint(painter, x,y);
00528 
00529         if ( doFill )
00530             polyline.setPoint(i - from, x, y);
00531     }
00532 
00533     if ( doFill )
00534     {
00535         closePolyline(xMap, yMap, polyline);
00536         painter->setPen(QPen(QPen::NoPen));
00537         QwtPainter::drawPolygon(painter, polyline);
00538     }
00539 }
00540 
00551 void QwtCurve::drawSteps(QPainter *painter,
00552     const QwtDiMap &xMap, const QwtDiMap &yMap, int from, int to)
00553 {
00554     QPointArray polyline(2 * (to - from) + 1);
00555 
00556     bool inverted = d_options & Yfx;
00557     if ( d_options & Inverted )
00558         inverted = !inverted;
00559 
00560     int i,ip;
00561     for (i = from, ip = 0; i <= to; i++, ip += 2)
00562     {
00563         int x = xMap.transform(d_x[i]);
00564         int y = yMap.transform(d_y[i]);
00565 
00566         if ( ip > 0 )
00567         {
00568             if (inverted)
00569                 polyline.setPoint(ip - 1, polyline[ip-2].x(), y);
00570             else
00571                 polyline.setPoint(ip - 1, x, polyline[ip-2].y());
00572         }
00573 
00574         polyline.setPoint(ip, x, y);
00575     }
00576 
00577     QwtPainter::drawPolyline(painter, polyline);
00578 
00579     if ( painter->brush().style() != Qt::NoBrush )
00580     {
00581         closePolyline(xMap, yMap, polyline);
00582         painter->setPen(QPen(QPen::NoPen));
00583         QwtPainter::drawPolygon(painter, polyline);
00584     }
00585 }
00586 
00595 void QwtCurve::drawSpline(QPainter *painter,
00596     const QwtDiMap &xMap, const QwtDiMap &yMap)
00597 {
00598     register int i;
00599 
00600     int size = dataSize();
00601     double *txval = new double[size];
00602     double *tyval = new double[size];
00603 
00604 
00605     if ( !txval || !tyval )
00606     {
00607         if (txval) delete[] txval;
00608         if (tyval) delete[] tyval;
00609         return;
00610     }
00611 
00612     QPointArray polyline(d_splineSize);
00613 
00614     //
00615     // Transform x and y values to window coordinates
00616     // to avoid a distinction between linear and
00617     // logarithmic scales.
00618     //
00619     for (i=0;i<size;i++)
00620     {
00621         txval[i] = xMap.xTransform(d_x[i]);
00622         tyval[i] = yMap.xTransform(d_y[i]);
00623     }
00624 
00625     int stype;
00626     if (! (d_options & (Yfx|Xfy|Parametric)))
00627     {
00628         if (qwtChkMono(txval, size))
00629         {
00630             stype = Yfx;
00631         }
00632         else
00633         {
00634             if(qwtChkMono(tyval, size))
00635             {
00636                 stype = Xfy;
00637             }
00638             else
00639             {
00640                 stype = Parametric;
00641                 if ( (d_options & Periodic) ||
00642                     ( (d_x[0] == d_x[size-1])
00643                     && (d_y[0] == d_y[size-1])))
00644                 {
00645                     stype |= Periodic;
00646                 }
00647             }
00648         }
00649     }
00650     else
00651     {
00652         stype = d_options;
00653     }
00654 
00655     if (stype & Parametric)
00656     {
00657         double *param = new double[size];
00658         if (param)
00659         {
00660             //
00661             // setup parameter vector
00662             //
00663             param[0] = 0.0;
00664             for (i=1; i<size; i++)
00665             {
00666                 double delta = sqrt( qwtSqr(txval[i] - txval[i-1])
00667                               + qwtSqr( tyval[i] - tyval[i-1]));
00668                 param[i] = param[i-1] + qwtMax(delta, 1.0);
00669             }
00670 
00671             //
00672             // setup splines
00673             int rc = d_spx.recalc(param, txval, size, stype & Periodic);
00674             if (!rc)
00675                 rc = d_spy.recalc(param, tyval, size, stype & Periodic);
00676 
00677             if (rc)
00678             {
00679                 drawLines(painter, xMap, yMap, 0, size - 1);
00680             }
00681             else
00682             {
00683                 // fill point array
00684                 double delta = param[size - 1] / double(d_splineSize-1);
00685                 for (i=0;i<d_splineSize;i++)
00686                 {
00687                     double dtmp = delta * double(i);
00688                     polyline.setPoint(i, int(floor (d_spx.value(dtmp) + 0.5)),
00689                                   int(floor (d_spy.value(dtmp) + 0.5)));
00690                 }
00691             }
00692 
00693             delete[] param;
00694         }
00695     }
00696     else if (stype & Xfy)
00697     {
00698         if (tyval[size-1] < tyval[0])
00699         {
00700             qwtTwistArray(txval, size);
00701             qwtTwistArray(tyval, size);
00702         }
00703 
00704         // 1. Calculate spline coefficients
00705         int rc = d_spx.recalc(tyval, txval, size, stype & Periodic);
00706         if (rc)                         // an error occurred
00707         {
00708             drawLines(painter, xMap, yMap, 0, size - 1);
00709         }
00710         else                            // Spline OK
00711         {
00712             double ymin = qwtGetMin(tyval, size);
00713             double ymax = qwtGetMax(tyval, size);
00714             double delta = (ymax - ymin) / double(d_splineSize - 1);
00715 
00716             for (i=0;i<d_splineSize;i++)
00717             {
00718                 double dtmp = ymin + delta * double(i);
00719                 polyline.setPoint(i, int(floor(d_spx.value(dtmp) + 0.5)),
00720                               int(floor(dtmp + 0.5)));
00721             }
00722         }
00723     }
00724     else
00725     {
00726         if (txval[size-1] < txval[0])
00727         {
00728             qwtTwistArray(tyval, size);
00729             qwtTwistArray(txval, size);
00730         }
00731 
00732 
00733         // 1. Calculate spline coefficients
00734         int rc = d_spy.recalc(txval, tyval, size, stype & Periodic);
00735         if (rc)                         // error
00736         {
00737             drawLines(painter, xMap, yMap, 0, size - 1);
00738         }
00739         else                            // Spline OK
00740         {
00741             double xmin = qwtGetMin(txval, size);
00742             double xmax = qwtGetMax(txval, size);
00743             double delta = (xmax - xmin) / double(d_splineSize - 1);
00744 
00745             for (i=0;i<d_splineSize;i++)
00746             {
00747                 double dtmp = xmin + delta * double(i);
00748                 polyline.setPoint(i, int(floor (dtmp + 0.5)),
00749                               int(floor(d_spy.value(dtmp) + 0.5)));
00750             }
00751         }
00752     }
00753 
00754     delete[] txval;
00755     delete[] tyval;
00756 
00757     QwtPainter::drawPolyline(painter, polyline);
00758 
00759     if ( painter->brush().style() != Qt::NoBrush )
00760     {
00761         closePolyline(xMap, yMap, polyline);
00762         painter->setPen(QPen(QPen::NoPen));
00763         QwtPainter::drawPolygon(painter, polyline);
00764     }
00765 }
00766 
00797 void QwtCurve::setOptions(int opt)
00798 {
00799     d_options = opt;
00800     curveChanged();
00801 }
00802 
00807 int QwtCurve::options() const 
00808 { 
00809     return d_options; 
00810 }
00811 
00817 void QwtCurve::setSplineSize(int s)
00818 {
00819     d_splineSize = qwtMax(s, 10);
00820     curveChanged();
00821 }
00822 
00829 int QwtCurve::splineSize() const 
00830 { 
00831     return d_splineSize; 
00832 }
00833 
00843 void QwtCurve::closePolyline(const QwtDiMap &xMap, const QwtDiMap &yMap,
00844     QPointArray &pa) const
00845 {
00846     const int sz = pa.size();
00847     if ( sz < 2 )
00848         return;
00849 
00850     pa.resize(sz + 2);
00851 
00852     if ( d_options & QwtCurve::Xfy )
00853     {
00854         pa.setPoint(sz,
00855             xMap.transform(d_ref), pa.point(sz - 1).y());
00856         pa.setPoint(sz + 1,
00857             xMap.transform(d_ref), pa.point(0).y());
00858     }
00859     else
00860     {
00861         pa.setPoint(sz,
00862             pa.point(sz - 1).x(), yMap.transform(d_ref));
00863         pa.setPoint(pa.size() - 1,
00864             pa.point(0).x(), yMap.transform(d_ref));
00865     }
00866 }
00867 
00877 void QwtCurve::drawSymbols(QPainter *painter, QwtSymbol &symbol,
00878     const QwtDiMap &xMap, const QwtDiMap &yMap, int from, int to)
00879 {
00880     for (int i = from; i <= to; i++)
00881     {
00882         const int u = xMap.transform(d_x[i]);
00883         const int v = yMap.transform(d_y[i]);
00884 
00885         symbol.draw(painter, u, v);
00886     }
00887 }
00888 
00902 void QwtCurve::setBaseline(double ref)
00903 {
00904     d_ref = ref;
00905     curveChanged();
00906 }
00907 
00912 double QwtCurve::baseline() const 
00913 { 
00914     return d_ref; 
00915 }
00916 
00920 int QwtCurve::dataSize() const
00921 {
00922     return qwtMin(d_x.size(), d_y.size());
00923 }
00924 
00928 void QwtCurve::updateRangeCache()
00929 {
00930   d_rangeCache.minXValue = d_rangeCache.maxXValue =
00931     d_rangeCache.minYValue = d_rangeCache.maxYValue = 0.0;
00932 
00933   if ( d_x.size() > 0 )
00934   {
00935     const int xSize = d_x.size();
00936     const double *xData = d_x.data();
00937 
00938     d_rangeCache.minXValue = d_rangeCache.maxXValue = xData[0];
00939       for (register int i = 1; i < xSize; i++)
00940     {
00941       const double x = xData[i];
00942       if ( x < d_rangeCache.minXValue )
00943         d_rangeCache.minXValue = x;
00944       if ( x > d_rangeCache.maxXValue )
00945         d_rangeCache.maxXValue = x;
00946     }
00947   }
00948 
00949   if ( d_y.size() > 0 )
00950   {
00951     const int ySize = d_y.size();
00952     const double *yData = d_y.data();
00953 
00954     d_rangeCache.minYValue = d_rangeCache.maxYValue = yData[0];
00955       for (register int i = 1; i < ySize; i++)
00956     {
00957       const double y = yData[i];
00958       if ( y < d_rangeCache.minYValue )
00959         d_rangeCache.minYValue = y;
00960       if ( y > d_rangeCache.maxYValue )
00961         d_rangeCache.maxYValue = y;
00962     }
00963   }
00964 
00965   d_rangeCache.isDirty = FALSE;
00966 }
00967 
00975 void QwtCurve::curveChanged() 
00976 {
00977 }

Generated on Fri Nov 7 14:11:45 2003 for Qwt Developer's Guide by doxygen 1.3.2