00001
00002
00003
00004
00005
00006
00007
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
00616
00617
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
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
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
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
00705 int rc = d_spx.recalc(tyval, txval, size, stype & Periodic);
00706 if (rc)
00707 {
00708 drawLines(painter, xMap, yMap, 0, size - 1);
00709 }
00710 else
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
00734 int rc = d_spy.recalc(txval, tyval, size, stype & Periodic);
00735 if (rc)
00736 {
00737 drawLines(painter, xMap, yMap, 0, size - 1);
00738 }
00739 else
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 }