00001
00002
00003
00004
00005
00006
00007
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);
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
00604
00605
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
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
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
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
00693 int rc = d_spx.recalc(tyval, txval, size, stype & Periodic);
00694 if (rc)
00695 {
00696 drawLines(painter, xMap, yMap, 0, size - 1);
00697 }
00698 else
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
00722 int rc = d_spy.recalc(txval, tyval, size, stype & Periodic);
00723 if (rc)
00724 {
00725 drawLines(painter, xMap, yMap, 0, size - 1);
00726 }
00727 else
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 }