~ubuntu-branches/ubuntu/oneiric/qwt/oneiric-proposed

« back to all changes in this revision

Viewing changes to qwt-5.1.1/src/qwt_plot_curve.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Fathi Boudra
  • Date: 2009-04-12 23:25:58 UTC
  • mfrom: (1.1.4 upstream) (2.1.2 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090412232558-3bl06x785yr8xm8u
Tags: 5.1.2-1
* New upstream release.
* Bump compat/debhelper to 7.
* Bump Standards-Version to 3.8.1. No changes needed.
* Invert Maintainers and Uploaders field.
* Fix lintian warnings:
  - dh_clean _k deprecated.
  - missing dependency on libc.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
2
 
 * Qwt Widget Library
3
 
 * Copyright (C) 1997   Josef Wilgen
4
 
 * Copyright (C) 2002   Uwe Rathmann
5
 
 *
6
 
 * This library is free software; you can redistribute it and/or
7
 
 * modify it under the terms of the Qwt License, Version 1.0
8
 
 *****************************************************************************/
9
 
 
10
 
#include <qpainter.h>
11
 
#include <qpixmap.h>
12
 
#include <qbitarray.h>
13
 
#include "qwt_global.h"
14
 
#include "qwt_legend.h"
15
 
#include "qwt_legend_item.h"
16
 
#include "qwt_data.h"
17
 
#include "qwt_scale_map.h"
18
 
#include "qwt_double_rect.h"
19
 
#include "qwt_math.h"
20
 
#include "qwt_clipper.h"
21
 
#include "qwt_painter.h"
22
 
#include "qwt_plot.h"
23
 
#include "qwt_plot_canvas.h"
24
 
#include "qwt_curve_fitter.h"
25
 
#include "qwt_symbol.h"
26
 
#include "qwt_plot_curve.h"
27
 
 
28
 
#if QT_VERSION >= 0x040000
29
 
 
30
 
#include <qevent.h>
31
 
#include <qpaintengine.h>
32
 
 
33
 
class QwtPlotCurvePaintHelper: public QObject
34
 
{
35
 
public:
36
 
    QwtPlotCurvePaintHelper(const QwtPlotCurve *curve, int from, int to):
37
 
        _curve(curve),
38
 
        _from(from),
39
 
        _to(to)
40
 
    {
41
 
    }
42
 
 
43
 
    virtual bool eventFilter(QObject *, QEvent *event)
44
 
    {
45
 
        if ( event->type() == QEvent::Paint )
46
 
        {
47
 
            _curve->draw(_from, _to);
48
 
            return true;
49
 
        }
50
 
        return false;
51
 
    }
52
 
private:
53
 
    const QwtPlotCurve *_curve;
54
 
    int _from;
55
 
    int _to;
56
 
};
57
 
 
58
 
#endif // QT_VERSION >= 0x040000
59
 
 
60
 
static int verifyRange(int size, int &i1, int &i2)
61
 
{
62
 
    if (size < 1) 
63
 
        return 0;
64
 
 
65
 
    i1 = qwtLim(i1, 0, size-1);
66
 
    i2 = qwtLim(i2, 0, size-1);
67
 
 
68
 
    if ( i1 > i2 )
69
 
        qSwap(i1, i2);
70
 
 
71
 
    return (i2 - i1 + 1);
72
 
}
73
 
 
74
 
class QwtPlotCurve::PrivateData
75
 
{
76
 
public:
77
 
    class PixelMatrix: private QBitArray
78
 
    {
79
 
    public:
80
 
        PixelMatrix(const QRect& rect):
81
 
            QBitArray(rect.width() * rect.height()),
82
 
            _rect(rect)
83
 
        {
84
 
            fill(false);
85
 
        }
86
 
 
87
 
        inline bool testPixel(const QPoint& pos)
88
 
        {
89
 
            if ( !_rect.contains(pos) )
90
 
                return false;
91
 
 
92
 
            const int idx = _rect.width() * (pos.y() - _rect.y()) + 
93
 
                (pos.x() - _rect.x());
94
 
 
95
 
            const bool marked = testBit(idx);
96
 
            if ( !marked )
97
 
                setBit(idx, true);
98
 
 
99
 
            return !marked;
100
 
        }
101
 
 
102
 
    private:
103
 
        QRect _rect;
104
 
    };
105
 
 
106
 
    PrivateData():
107
 
        curveType(Yfx),
108
 
        style(QwtPlotCurve::Lines),
109
 
        reference(0.0),
110
 
        attributes(0),
111
 
        paintAttributes(0)
112
 
    {
113
 
        symbol = new QwtSymbol();
114
 
        pen = QPen(Qt::black);
115
 
        curveFitter = new QwtSplineCurveFitter;
116
 
    }
117
 
 
118
 
    ~PrivateData()
119
 
    {
120
 
        delete symbol;
121
 
        delete curveFitter;
122
 
    }
123
 
 
124
 
    QwtPlotCurve::CurveType curveType;
125
 
    QwtPlotCurve::CurveStyle style;
126
 
    double reference;
127
 
 
128
 
    QwtSymbol *symbol;
129
 
    QwtCurveFitter *curveFitter;
130
 
 
131
 
    QPen pen;
132
 
    QBrush brush;
133
 
 
134
 
    int attributes;
135
 
    int paintAttributes;
136
 
};
137
 
 
138
 
//! Constructor
139
 
QwtPlotCurve::QwtPlotCurve():
140
 
    QwtPlotItem(QwtText())
141
 
{
142
 
    init();
143
 
}
144
 
 
145
 
/*!
146
 
  Constructor
147
 
  \param title title of the curve   
148
 
*/
149
 
QwtPlotCurve::QwtPlotCurve(const QwtText &title):
150
 
    QwtPlotItem(title)
151
 
{
152
 
    init();
153
 
}
154
 
 
155
 
/*!
156
 
  Constructor
157
 
  \param title title of the curve   
158
 
*/
159
 
QwtPlotCurve::QwtPlotCurve(const QString &title):
160
 
    QwtPlotItem(QwtText(title))
161
 
{
162
 
    init();
163
 
}
164
 
 
165
 
//! Destructor
166
 
QwtPlotCurve::~QwtPlotCurve()
167
 
{
168
 
    delete d_xy;
169
 
    delete d_data;
170
 
}
171
 
 
172
 
/*!
173
 
  \brief Initialize data members
174
 
*/
175
 
void QwtPlotCurve::init()
176
 
{
177
 
    setItemAttribute(QwtPlotItem::Legend);
178
 
    setItemAttribute(QwtPlotItem::AutoScale);
179
 
 
180
 
    d_data = new PrivateData;
181
 
    d_xy = new QwtPolygonFData(QwtArray<QwtDoublePoint>());
182
 
 
183
 
    setZ(20.0);
184
 
}
185
 
 
186
 
//! \return QwtPlotItem::Rtti_PlotCurve
187
 
int QwtPlotCurve::rtti() const
188
 
{
189
 
    return QwtPlotItem::Rtti_PlotCurve;
190
 
}
191
 
 
192
 
/*!
193
 
  \brief Specify an attribute how to draw the curve
194
 
 
195
 
  The attributes can be used to modify the drawing algorithm.
196
 
 
197
 
  The following attributes are defined:<dl>
198
 
  <dt>PaintFiltered</dt>
199
 
  <dd>Tries to reduce the data that has to be painted, by sorting out
200
 
      duplicates, or paintings outside the visible area. Might have a
201
 
      notable impact on curves with many close points. 
202
 
      Only a couple of very basic filtering algos are implemented.</dd>
203
 
  <dt>ClipPolygons</dt>
204
 
  <dd>Clip polygons before painting them. In situations, where points
205
 
      are far outside the visible area this might be a great improvement
206
 
      for the painting performance ( especially on Windows ).
207
 
  </dl>
208
 
 
209
 
  The default is, that no paint attributes are enabled.
210
 
 
211
 
  \param attribute Paint attribute
212
 
  \param on On/Off
213
 
  /sa testPaintAttribute()
214
 
*/
215
 
void QwtPlotCurve::setPaintAttribute(PaintAttribute attribute, bool on)
216
 
{
217
 
    if ( on )
218
 
        d_data->paintAttributes |= attribute;
219
 
    else
220
 
        d_data->paintAttributes &= ~attribute;
221
 
}
222
 
 
223
 
/*!
224
 
    \brief Return the current paint attributes
225
 
    \sa setPaintAttribute
226
 
*/
227
 
bool QwtPlotCurve::testPaintAttribute(PaintAttribute attribute) const
228
 
{
229
 
    return (d_data->paintAttributes & attribute);
230
 
}
231
 
 
232
 
/*!
233
 
  \brief Set the curve's drawing style
234
 
 
235
 
  Valid styles are:
236
 
  <dl>
237
 
  <dt>NoCurve</dt>
238
 
  <dd>Don't draw a curve. Note: This doesn't affect the symbol. </dd>
239
 
  <dt>Lines</dt>
240
 
  <dd>Connect the points with straight lines. The lines might
241
 
      be interpolated depending on the 'Fitted' option. Curve
242
 
      fitting can be configured using setCurveFitter.</dd>
243
 
  <dt>Sticks</dt>
244
 
  <dd>Draw vertical sticks from a baseline which is defined by setBaseline().</dd>
245
 
  <dt>Steps</dt>
246
 
  <dd>Connect the points with a step function. The step function
247
 
      is drawn from the left to the right or vice versa,
248
 
      depending on the 'Inverted' option.</dd>
249
 
  <dt>Dots</dt>
250
 
  <dd>Draw dots at the locations of the data points. Note:
251
 
      This is different from a dotted line (see setPen()).</dd>
252
 
  <dt>UserCurve ...</dt>
253
 
  <dd>Styles >= UserCurve are reserved for derived
254
 
      classes of QwtPlotCurve that overload drawCurve() with
255
 
      additional application specific curve types.</dd>
256
 
  </dl>
257
 
  \sa style()
258
 
*/
259
 
void QwtPlotCurve::setStyle(CurveStyle style)
260
 
{
261
 
    if ( style != d_data->style )
262
 
    {
263
 
        d_data->style = style;
264
 
        itemChanged();
265
 
    }
266
 
}
267
 
 
268
 
/*!
269
 
    \brief Return the current style
270
 
    \sa setStyle()
271
 
*/
272
 
QwtPlotCurve::CurveStyle QwtPlotCurve::style() const 
273
 
274
 
    return d_data->style; 
275
 
}
276
 
 
277
 
/*!
278
 
  \brief Assign a symbol
279
 
  \param symbol Symbol
280
 
  \sa symbol()
281
 
*/
282
 
void QwtPlotCurve::setSymbol(const QwtSymbol &symbol )
283
 
{
284
 
    delete d_data->symbol;
285
 
    d_data->symbol = symbol.clone();
286
 
    itemChanged();
287
 
}
288
 
 
289
 
/*!
290
 
    \brief Return the current symbol
291
 
    \sa setSymbol()
292
 
*/
293
 
const QwtSymbol &QwtPlotCurve::symbol() const 
294
 
295
 
    return *d_data->symbol; 
296
 
}
297
 
 
298
 
/*!
299
 
  \brief Assign a pen
300
 
  \param pen New pen
301
 
  \sa pen(), brush()
302
 
*/
303
 
void QwtPlotCurve::setPen(const QPen &pen)
304
 
{
305
 
    if ( pen != d_data->pen )
306
 
    {
307
 
        d_data->pen = pen;
308
 
        itemChanged();
309
 
    }
310
 
}
311
 
 
312
 
/*!
313
 
    \brief Return the pen used to draw the lines
314
 
    \sa setPen(), brush()
315
 
*/
316
 
const QPen& QwtPlotCurve::pen() const 
317
 
318
 
    return d_data->pen; 
319
 
}
320
 
 
321
 
/*!
322
 
  \brief Assign a brush. 
323
 
         In case of brush.style() != QBrush::NoBrush 
324
 
         and style() != QwtPlotCurve::Sticks
325
 
         the area between the curve and the baseline will be filled.
326
 
         In case !brush.color().isValid() the area will be filled by
327
 
         pen.color(). The fill algorithm simply connects the first and the
328
 
         last curve point to the baseline. So the curve data has to be sorted 
329
 
         (ascending or descending). 
330
 
  \param brush New brush
331
 
  \sa brush(), setBaseline(), baseline()
332
 
*/
333
 
void QwtPlotCurve::setBrush(const QBrush &brush)
334
 
{
335
 
    if ( brush != d_data->brush )
336
 
    {
337
 
        d_data->brush = brush;
338
 
        itemChanged();
339
 
    }
340
 
}
341
 
 
342
 
/*!
343
 
  \brief Return the brush used to fill the area between lines and the baseline
344
 
  \sa setBrush(), setBaseline(), baseline()
345
 
*/
346
 
const QBrush& QwtPlotCurve::brush() const 
347
 
{
348
 
    return d_data->brush;
349
 
}
350
 
 
351
 
 
352
 
/*!
353
 
  Set data by copying x- and y-values from specified memory blocks.
354
 
  Contrary to setCurveRawData(), this function makes a 'deep copy' of
355
 
  the data.
356
 
 
357
 
  \param xData pointer to x values
358
 
  \param yData pointer to y values
359
 
  \param size size of xData and yData
360
 
 
361
 
  \sa QwtCPointerData
362
 
*/
363
 
void QwtPlotCurve::setData(const double *xData, const double *yData, int size)
364
 
{
365
 
    delete d_xy;
366
 
    d_xy = new QwtArrayData(xData, yData, size);
367
 
    itemChanged();
368
 
}
369
 
 
370
 
/*!
371
 
  \brief Initialize data with x- and y-arrays (explicitly shared)
372
 
 
373
 
  \param xData x data
374
 
  \param yData y data
375
 
 
376
 
  \sa QwtArrayData
377
 
*/
378
 
void QwtPlotCurve::setData(const QwtArray<double> &xData, 
379
 
    const QwtArray<double> &yData)
380
 
{
381
 
    delete d_xy;
382
 
    d_xy = new QwtArrayData(xData, yData);
383
 
    itemChanged();
384
 
}
385
 
 
386
 
/*!
387
 
  Initialize data with an array of points (explicitly shared).
388
 
 
389
 
  \param data Data
390
 
  \sa QwtPolygonFData
391
 
*/
392
 
#if QT_VERSION < 0x040000
393
 
void QwtPlotCurve::setData(const QwtArray<QwtDoublePoint> &data)
394
 
#else
395
 
void QwtPlotCurve::setData(const QPolygonF &data)
396
 
#endif
397
 
{
398
 
    delete d_xy;
399
 
    d_xy = new QwtPolygonFData(data);
400
 
    itemChanged();
401
 
}
402
 
 
403
 
/*!
404
 
  Initialize data with a pointer to QwtData.
405
 
 
406
 
  \param data Data
407
 
  \sa QwtData::copy()
408
 
*/
409
 
void QwtPlotCurve::setData(const QwtData &data)
410
 
{
411
 
    delete d_xy;
412
 
    d_xy = data.copy();
413
 
    itemChanged();
414
 
}
415
 
 
416
 
/*!
417
 
  \brief Initialize the data by pointing to memory blocks which are not managed
418
 
  by QwtPlotCurve.
419
 
 
420
 
  setRawData is provided for efficiency. It is important to keep the pointers
421
 
  during the lifetime of the underlying QwtCPointerData class.
422
 
 
423
 
  \param xData pointer to x data
424
 
  \param yData pointer to y data
425
 
  \param size size of x and y
426
 
 
427
 
  \sa QwtCPointerData::setData.
428
 
*/
429
 
void QwtPlotCurve::setRawData(const double *xData, const double *yData, int size)
430
 
{
431
 
    delete d_xy;
432
 
    d_xy = new QwtCPointerData(xData, yData, size);
433
 
    itemChanged();
434
 
}
435
 
 
436
 
/*!
437
 
  Returns the bounding rectangle of the curve data. If there is
438
 
  no bounding rect, like for empty data the rectangle is invalid.
439
 
  \sa QwtData::boundingRect(), QwtDoubleRect::isValid()
440
 
*/
441
 
 
442
 
QwtDoubleRect QwtPlotCurve::boundingRect() const
443
 
{
444
 
    if ( d_xy == NULL )
445
 
        return QwtDoubleRect(1.0, 1.0, -2.0, -2.0); // invalid
446
 
 
447
 
    return d_xy->boundingRect();
448
 
}
449
 
 
450
 
/*!
451
 
  \brief Draw the complete curve
452
 
 
453
 
  \param painter Painter
454
 
  \param xMap Maps x-values into pixel coordinates.
455
 
  \param yMap Maps y-values into pixel coordinates.
456
 
 
457
 
  \sa drawCurve(), drawSymbols()
458
 
*/
459
 
void QwtPlotCurve::draw(QPainter *painter,
460
 
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
461
 
    const QRect &) const
462
 
{
463
 
    draw(painter, xMap, yMap, 0, -1);
464
 
}
465
 
 
466
 
/*!
467
 
  \brief Draw a set of points of a curve.
468
 
 
469
 
  When observing an measurement while it is running, new points have to be
470
 
  added to an existing curve. drawCurve can be used to display them avoiding
471
 
  a complete redraw of the canvas.
472
 
 
473
 
  Setting plot()->canvas()->setAttribute(Qt::WA_PaintOutsidePaintEvent, true);
474
 
  will result in faster painting, if the paint engine of the canvas widget
475
 
  supports this feature. 
476
 
 
477
 
  \param from Index of the first point to be painted
478
 
  \param to Index of the last point to be painted. If to < 0 the
479
 
         curve will be painted to its last point.
480
 
 
481
 
  \sa drawCurve(), drawSymbols()
482
 
*/
483
 
void QwtPlotCurve::draw(int from, int to) const
484
 
{
485
 
    if ( !plot() )
486
 
        return;
487
 
 
488
 
    QwtPlotCanvas *canvas = plot()->canvas();
489
 
 
490
 
#if QT_VERSION >= 0x040000
491
 
    if ( canvas->paintEngine()->type() == QPaintEngine::OpenGL )
492
 
    {
493
 
        /*
494
 
            OpenGL alway repaint the complete widget.
495
 
            So for this operation OpenGL is one of the slowest
496
 
            environments.
497
 
         */
498
 
        canvas->repaint();
499
 
        return;
500
 
    }
501
 
 
502
 
    if ( !canvas->testAttribute(Qt::WA_WState_InPaintEvent) &&
503
 
        !canvas->testAttribute(Qt::WA_PaintOutsidePaintEvent) )
504
 
    {
505
 
        /*
506
 
          We save curve and range in helper and call repaint.
507
 
          The helper filters the Paint event, to repeat
508
 
          the QwtPlotCurve::draw, but now from inside the paint
509
 
          event.
510
 
         */
511
 
 
512
 
        QwtPlotCurvePaintHelper helper(this, from, to);
513
 
        canvas->installEventFilter(&helper);
514
 
 
515
 
        const bool noSystemBackground =
516
 
            canvas->testAttribute(Qt::WA_NoSystemBackground);
517
 
        canvas->setAttribute(Qt::WA_NoSystemBackground, true);
518
 
        canvas->repaint();
519
 
        canvas->setAttribute(Qt::WA_NoSystemBackground, noSystemBackground);
520
 
 
521
 
        return;
522
 
    }
523
 
#endif
524
 
 
525
 
    const QwtScaleMap xMap = plot()->canvasMap(xAxis());
526
 
    const QwtScaleMap yMap = plot()->canvasMap(yAxis());
527
 
 
528
 
    if ( canvas->testPaintAttribute(QwtPlotCanvas::PaintCached) &&
529
 
        canvas->paintCache() && !canvas->paintCache()->isNull() )
530
 
    {
531
 
        QPainter cachePainter((QPixmap *)canvas->paintCache());
532
 
        cachePainter.translate(-canvas->contentsRect().x(),
533
 
            -canvas->contentsRect().y());
534
 
 
535
 
        draw(&cachePainter, xMap, yMap, from, to);
536
 
    }
537
 
 
538
 
    QPainter painter(canvas);
539
 
 
540
 
    painter.setClipping(true);
541
 
    painter.setClipRect(canvas->contentsRect());
542
 
 
543
 
    draw(&painter, xMap, yMap, from, to);
544
 
}
545
 
 
546
 
/*!
547
 
  \brief Draw an interval of the curve
548
 
  \param painter Painter
549
 
  \param xMap maps x-values into pixel coordinates.
550
 
  \param yMap maps y-values into pixel coordinates.
551
 
  \param from index of the first point to be painted
552
 
  \param to index of the last point to be painted. If to < 0 the 
553
 
         curve will be painted to its last point.
554
 
 
555
 
  \sa drawCurve(), drawSymbols(),
556
 
*/
557
 
void QwtPlotCurve::draw(QPainter *painter,
558
 
    const QwtScaleMap &xMap, const QwtScaleMap &yMap, 
559
 
    int from, int to) const
560
 
{
561
 
    if ( !painter || dataSize() <= 0 )
562
 
        return;
563
 
 
564
 
    if (to < 0)
565
 
        to = dataSize() - 1;
566
 
 
567
 
    if ( verifyRange(dataSize(), from, to) > 0 )
568
 
    {
569
 
        painter->save();
570
 
        painter->setPen(d_data->pen);
571
 
 
572
 
        /*
573
 
          Qt 4.0.0 is slow when drawing lines, but it's even 
574
 
          slower when the painter has a brush. So we don't
575
 
          set the brush before we really need it.
576
 
         */
577
 
 
578
 
        drawCurve(painter, d_data->style, xMap, yMap, from, to);
579
 
        painter->restore();
580
 
 
581
 
        if (d_data->symbol->style() != QwtSymbol::NoSymbol)
582
 
        {
583
 
            painter->save();
584
 
            drawSymbols(painter, *d_data->symbol, xMap, yMap, from, to);
585
 
            painter->restore();
586
 
        }
587
 
    }
588
 
}
589
 
 
590
 
/*!
591
 
  \brief Draw the line part (without symbols) of a curve interval. 
592
 
  \param painter Painter
593
 
  \param style curve style, see QwtPlotCurve::CurveStyle
594
 
  \param xMap x map
595
 
  \param yMap y map
596
 
  \param from index of the first point to be painted
597
 
  \param to index of the last point to be painted
598
 
  \sa draw(), drawDots(), drawLines(), drawSteps(), drawSticks()
599
 
*/
600
 
 
601
 
void QwtPlotCurve::drawCurve(QPainter *painter, int style,
602
 
    const QwtScaleMap &xMap, const QwtScaleMap &yMap, 
603
 
    int from, int to) const
604
 
{
605
 
    switch (style)
606
 
    {
607
 
        case Lines:
608
 
            if ( testCurveAttribute(Fitted) )
609
 
            {
610
 
                // we always need the complete 
611
 
                // curve for fitting
612
 
                from = 0;
613
 
                to = dataSize() - 1;
614
 
            }
615
 
            drawLines(painter, xMap, yMap, from, to);
616
 
            break;
617
 
        case Sticks:
618
 
            drawSticks(painter, xMap, yMap, from, to);
619
 
            break;
620
 
        case Steps:
621
 
            drawSteps(painter, xMap, yMap, from, to);
622
 
            break;
623
 
        case Dots:
624
 
            drawDots(painter, xMap, yMap, from, to);
625
 
            break;
626
 
        case NoCurve:
627
 
        default:
628
 
            break;
629
 
    }
630
 
}
631
 
 
632
 
/*!
633
 
  \brief Draw lines
634
 
 
635
 
  If the CurveAttribute Fitted is enabled a QwtCurveFitter tries
636
 
  to interpolate/smooth the curve, before it is painted.
637
 
 
638
 
  \param painter Painter
639
 
  \param xMap x map
640
 
  \param yMap y map
641
 
  \param from index of the first point to be painted
642
 
  \param to index of the last point to be painted
643
 
 
644
 
  \sa setCurveAttribute(), setCurveFitter(), draw(), 
645
 
      drawLines(), drawDots(), drawSteps(), drawSticks()
646
 
*/
647
 
void QwtPlotCurve::drawLines(QPainter *painter,
648
 
    const QwtScaleMap &xMap, const QwtScaleMap &yMap, 
649
 
    int from, int to) const
650
 
{
651
 
    int size = to - from + 1;
652
 
    if ( size <= 0 )
653
 
        return;
654
 
 
655
 
    QwtPolygon polyline;
656
 
    if ( ( d_data->attributes & Fitted ) && d_data->curveFitter )
657
 
    {
658
 
        // Transform x and y values to window coordinates
659
 
        // to avoid a distinction between linear and
660
 
        // logarithmic scales.
661
 
 
662
 
#if QT_VERSION < 0x040000
663
 
        QwtArray<QwtDoublePoint> points(size);
664
 
#else
665
 
        QPolygonF points(size);
666
 
#endif
667
 
        for (int i = from; i <= to; i++)
668
 
        {
669
 
            QwtDoublePoint &p = points[i];
670
 
            p.setX( xMap.xTransform(x(i)) );
671
 
            p.setY( yMap.xTransform(y(i)) );
672
 
        }
673
 
 
674
 
        points = d_data->curveFitter->fitCurve(points);
675
 
        size = points.size();
676
 
 
677
 
        if ( size == 0 )
678
 
            return;
679
 
 
680
 
        // Round QwtDoublePoints to QPoints
681
 
        // When Qwt support for Qt3 has been dropped (Qwt 6.x)
682
 
        // we will use a doubles for painting and the following
683
 
        // step will be obsolete.
684
 
 
685
 
        polyline.resize(size);
686
 
 
687
 
        const QwtDoublePoint *p = points.data();
688
 
        QPoint *pl = polyline.data();
689
 
        if ( d_data->paintAttributes & PaintFiltered )
690
 
        {
691
 
 
692
 
            QPoint pp(qRound(p[0].x()), qRound(p[0].y()));
693
 
            pl[0] = pp;
694
 
 
695
 
            int count = 1;
696
 
            for (int i = 1; i < size; i++)
697
 
            {
698
 
                const QPoint pi(qRound(p[i].x()), qRound(p[i].y()));
699
 
                if ( pi != pp )
700
 
                {
701
 
                    pl[count++] = pi;
702
 
                    pp = pi;
703
 
                }
704
 
            }
705
 
            if ( count != size )
706
 
                polyline.resize(count);
707
 
        }
708
 
        else
709
 
        {
710
 
            for ( int i = 0; i < size; i++ )
711
 
            {
712
 
                pl[i].setX( qRound(p[i].x()) );
713
 
                pl[i].setY( qRound(p[i].y()) );
714
 
            }
715
 
        }
716
 
    }
717
 
    else
718
 
    {
719
 
        polyline.resize(size);
720
 
 
721
 
        if ( d_data->paintAttributes & PaintFiltered )
722
 
        {
723
 
            QPoint pp( xMap.transform(x(from)), yMap.transform(y(from)) );
724
 
            polyline.setPoint(0, pp);
725
 
 
726
 
            int count = 1;
727
 
            for (int i = from + 1; i <= to; i++)
728
 
            {
729
 
                const QPoint pi(xMap.transform(x(i)), yMap.transform(y(i)));
730
 
                if ( pi != pp )
731
 
                {
732
 
                    polyline.setPoint(count, pi);
733
 
                    count++;
734
 
 
735
 
                    pp = pi;
736
 
                }
737
 
            }
738
 
            if ( count != size )
739
 
                polyline.resize(count);
740
 
        }
741
 
        else
742
 
        {
743
 
            for (int i = from; i <= to; i++)
744
 
            {
745
 
                int xi = xMap.transform(x(i));
746
 
                int yi = yMap.transform(y(i));
747
 
 
748
 
                polyline.setPoint(i - from, xi, yi);
749
 
            }
750
 
        }
751
 
    }
752
 
 
753
 
    if ( d_data->paintAttributes & ClipPolygons )
754
 
        polyline = QwtClipper::clipPolygon(painter->window(), polyline);
755
 
 
756
 
    QwtPainter::drawPolyline(painter, polyline);
757
 
 
758
 
    if ( d_data->brush.style() != Qt::NoBrush )
759
 
        fillCurve(painter, xMap, yMap, polyline);
760
 
}
761
 
 
762
 
/*!
763
 
  Draw sticks
764
 
 
765
 
  \param painter Painter
766
 
  \param xMap x map
767
 
  \param yMap y map
768
 
  \param from index of the first point to be painted
769
 
  \param to index of the last point to be painted
770
 
 
771
 
  \sa draw(), drawCurve(), drawDots(), drawLines(), drawSteps()
772
 
*/
773
 
void QwtPlotCurve::drawSticks(QPainter *painter,
774
 
    const QwtScaleMap &xMap, const QwtScaleMap &yMap, 
775
 
    int from, int to) const
776
 
{
777
 
    int x0 = xMap.transform(d_data->reference);
778
 
    int y0 = yMap.transform(d_data->reference);
779
 
 
780
 
    for (int i = from; i <= to; i++)
781
 
    {
782
 
        const int xi = xMap.transform(x(i));
783
 
        const int yi = yMap.transform(y(i));
784
 
 
785
 
        if (d_data->curveType == Xfy)
786
 
            QwtPainter::drawLine(painter, x0, yi, xi, yi);
787
 
        else
788
 
            QwtPainter::drawLine(painter, xi, y0, xi, yi);
789
 
    }
790
 
}
791
 
 
792
 
/*!
793
 
  Draw dots
794
 
 
795
 
  \param painter Painter
796
 
  \param xMap x map
797
 
  \param yMap y map
798
 
  \param from index of the first point to be painted
799
 
  \param to index of the last point to be painted
800
 
 
801
 
  \sa draw(), drawCurve(), drawSticks(), drawLines(), drawSteps()
802
 
*/
803
 
void QwtPlotCurve::drawDots(QPainter *painter,
804
 
    const QwtScaleMap &xMap, const QwtScaleMap &yMap, 
805
 
    int from, int to) const
806
 
{
807
 
    const QRect window = painter->window();
808
 
    if ( window.isEmpty() )
809
 
        return;
810
 
 
811
 
    const bool doFill = d_data->brush.style() != Qt::NoBrush;
812
 
 
813
 
    QwtPolygon polyline;
814
 
    if ( doFill )
815
 
        polyline.resize(to - from + 1);
816
 
 
817
 
    if ( to > from && d_data->paintAttributes & PaintFiltered )
818
 
    {
819
 
        if ( doFill )   
820
 
        {
821
 
            QPoint pp( xMap.transform(x(from)), yMap.transform(y(from)) );
822
 
 
823
 
            QwtPainter::drawPoint(painter, pp.x(), pp.y());
824
 
            polyline.setPoint(0, pp);
825
 
 
826
 
            int count = 1;
827
 
            for (int i = from + 1; i <= to; i++)
828
 
            {
829
 
                const QPoint pi(xMap.transform(x(i)), yMap.transform(y(i)));
830
 
                if ( pi != pp )
831
 
                {
832
 
                    QwtPainter::drawPoint(painter, pi.x(), pi.y());
833
 
 
834
 
                    polyline.setPoint(count, pi);
835
 
                    count++;
836
 
 
837
 
                    pp = pi;
838
 
                }
839
 
            }
840
 
            if ( int(polyline.size()) != count )
841
 
                polyline.resize(count);
842
 
        }
843
 
        else
844
 
        {
845
 
            // if we don't need to fill, we can sort out
846
 
            // duplicates independent from the order
847
 
 
848
 
            PrivateData::PixelMatrix pixelMatrix(window);
849
 
 
850
 
            for (int i = from; i <= to; i++)
851
 
            {
852
 
                const QPoint p( xMap.transform(x(i)),
853
 
                    yMap.transform(y(i)) );
854
 
 
855
 
                if ( pixelMatrix.testPixel(p) )
856
 
                    QwtPainter::drawPoint(painter, p.x(), p.y());
857
 
            }
858
 
        }
859
 
    }
860
 
    else
861
 
    {
862
 
        for (int i = from; i <= to; i++)
863
 
        {
864
 
            const int xi = xMap.transform(x(i));
865
 
            const int yi = yMap.transform(y(i));
866
 
            QwtPainter::drawPoint(painter, xi, yi);
867
 
 
868
 
            if ( doFill )
869
 
                polyline.setPoint(i - from, xi, yi);
870
 
        }
871
 
    }
872
 
 
873
 
    if ( doFill )
874
 
    {
875
 
        if ( d_data->paintAttributes & ClipPolygons )
876
 
            polyline = QwtClipper::clipPolygon(painter->window(), polyline);
877
 
 
878
 
        fillCurve(painter, xMap, yMap, polyline);
879
 
    }
880
 
}
881
 
 
882
 
/*!
883
 
  Draw step function
884
 
 
885
 
  The direction of the steps depends on Inverted attribute. 
886
 
 
887
 
  \param painter Painter
888
 
  \param xMap x map
889
 
  \param yMap y map
890
 
  \param from index of the first point to be painted
891
 
  \param to index of the last point to be painted
892
 
 
893
 
  \sa CurveAttribute, setCurveAttribute(),
894
 
      draw(), drawCurve(), drawDots(), drawLines(), drawSticks()
895
 
*/
896
 
void QwtPlotCurve::drawSteps(QPainter *painter,
897
 
    const QwtScaleMap &xMap, const QwtScaleMap &yMap, 
898
 
    int from, int to) const
899
 
{
900
 
    QwtPolygon polyline(2 * (to - from) + 1);
901
 
 
902
 
    bool inverted = d_data->curveType == Yfx;
903
 
    if ( d_data->attributes & Inverted )
904
 
        inverted = !inverted;
905
 
 
906
 
    int i,ip;
907
 
    for (i = from, ip = 0; i <= to; i++, ip += 2)
908
 
    {
909
 
        const int xi = xMap.transform(x(i));
910
 
        const int yi = yMap.transform(y(i));
911
 
 
912
 
        if ( ip > 0 )
913
 
        {
914
 
            if (inverted)
915
 
                polyline.setPoint(ip - 1, polyline[ip-2].x(), yi);
916
 
            else
917
 
                polyline.setPoint(ip - 1, xi, polyline[ip-2].y());
918
 
        }
919
 
 
920
 
        polyline.setPoint(ip, xi, yi);
921
 
    }
922
 
 
923
 
    if ( d_data->paintAttributes & ClipPolygons )
924
 
        polyline = QwtClipper::clipPolygon(painter->window(), polyline);
925
 
 
926
 
    QwtPainter::drawPolyline(painter, polyline);
927
 
 
928
 
    if ( d_data->brush.style() != Qt::NoBrush )
929
 
        fillCurve(painter, xMap, yMap, polyline);
930
 
}
931
 
 
932
 
 
933
 
/*!
934
 
  \brief Specify an attribute for drawing the curve
935
 
 
936
 
  The attributes can be used to modify the drawing style.
937
 
  The following attributes are defined:<dl>
938
 
  <dt>Fitted</dt>
939
 
  <dd>For Lines only. A QwtCurveFitter tries to
940
 
      interpolate/smooth the curve, before it is painted.
941
 
      Note that curve fitting requires temorary memory
942
 
      for calculating coefficients and additional points. 
943
 
      If painting in Fitted mode is slow it might be better
944
 
      to fit the points, before they are passed to QwtPlotCurve.
945
 
  </dd>
946
 
  <dt>Inverted</dt>
947
 
  <dd>For Steps only. Draws a step function
948
 
      from the right to the left.</dd></dl>
949
 
 
950
 
  \param attribute Curve attribute
951
 
  \param on On/Off
952
 
 
953
 
  /sa testCurveAttribute(), setCurveFitter()
954
 
*/
955
 
void QwtPlotCurve::setCurveAttribute(CurveAttribute attribute, bool on)
956
 
{
957
 
    if ( bool(d_data->attributes & attribute) == on )
958
 
        return;
959
 
 
960
 
    if ( on )
961
 
        d_data->attributes |= attribute;
962
 
    else
963
 
        d_data->attributes &= ~attribute;
964
 
 
965
 
    itemChanged();
966
 
}
967
 
 
968
 
/*!
969
 
    \return true, if attribute is enabled
970
 
    \sa setCurveAttribute()
971
 
*/
972
 
bool QwtPlotCurve::testCurveAttribute(CurveAttribute attribute) const 
973
 
974
 
    return d_data->attributes & attribute;
975
 
}
976
 
 
977
 
/*!
978
 
  Assign the curve type
979
 
 
980
 
  <dt>QwtPlotCurve::Yfx
981
 
  <dd>Draws y as a function of x (the default). The
982
 
      baseline is interpreted as a horizontal line
983
 
      with y = baseline().</dd>
984
 
  <dt>QwtPlotCurve::Xfy
985
 
  <dd>Draws x as a function of y. The baseline is
986
 
      interpreted as a vertical line with x = baseline().</dd>
987
 
 
988
 
  The baseline is used for aligning the sticks, or
989
 
  filling the curve with a brush.
990
 
 
991
 
  \sa curveType()
992
 
*/
993
 
void QwtPlotCurve::setCurveType(CurveType curveType)
994
 
{
995
 
    if ( d_data->curveType != curveType )
996
 
    {
997
 
        d_data->curveType = curveType;
998
 
        itemChanged();
999
 
    }
1000
 
}
1001
 
 
1002
 
/*!
1003
 
   Return the curve type
1004
 
   \sa setCurveType()
1005
 
*/
1006
 
QwtPlotCurve::CurveType QwtPlotCurve::curveType() const
1007
 
{
1008
 
    return d_data->curveType;
1009
 
}
1010
 
 
1011
 
void QwtPlotCurve::setCurveFitter(QwtCurveFitter *curveFitter)
1012
 
{
1013
 
    delete d_data->curveFitter;
1014
 
    d_data->curveFitter = curveFitter;
1015
 
 
1016
 
    itemChanged();
1017
 
}
1018
 
 
1019
 
QwtCurveFitter *QwtPlotCurve::curveFitter() const
1020
 
{
1021
 
    return d_data->curveFitter;
1022
 
}
1023
 
 
1024
 
/*! 
1025
 
  Fill the area between the curve and the baseline with 
1026
 
  the curve brush
1027
 
 
1028
 
  \param painter Painter
1029
 
  \param xMap x map
1030
 
  \param yMap y map
1031
 
  \param pa Polygon
1032
 
 
1033
 
  \sa setBrush(), setBaseline(), setCurveType()
1034
 
*/
1035
 
 
1036
 
void QwtPlotCurve::fillCurve(QPainter *painter,
1037
 
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
1038
 
    QwtPolygon &pa) const
1039
 
{
1040
 
    if ( d_data->brush.style() == Qt::NoBrush )
1041
 
        return;
1042
 
 
1043
 
    closePolyline(xMap, yMap, pa);
1044
 
    if ( pa.count() <= 2 ) // a line can't be filled
1045
 
        return;
1046
 
 
1047
 
    QBrush b = d_data->brush;
1048
 
    if ( !b.color().isValid() )
1049
 
        b.setColor(d_data->pen.color());
1050
 
 
1051
 
    painter->save();
1052
 
 
1053
 
    painter->setPen(QPen(Qt::NoPen));
1054
 
    painter->setBrush(b);
1055
 
 
1056
 
    QwtPainter::drawPolygon(painter, pa);
1057
 
 
1058
 
    painter->restore();
1059
 
}
1060
 
 
1061
 
/*!
1062
 
  \brief Complete a polygon to be a closed polygon 
1063
 
         including the area between the original polygon
1064
 
         and the baseline.
1065
 
  \param xMap X map
1066
 
  \param yMap Y map
1067
 
  \param pa Polygon to be completed
1068
 
*/
1069
 
 
1070
 
void QwtPlotCurve::closePolyline(
1071
 
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
1072
 
    QwtPolygon &pa) const
1073
 
{
1074
 
    const int sz = pa.size();
1075
 
    if ( sz < 2 )
1076
 
        return;
1077
 
 
1078
 
    pa.resize(sz + 2);
1079
 
 
1080
 
    if ( d_data->curveType == QwtPlotCurve::Xfy )
1081
 
    {
1082
 
        pa.setPoint(sz,
1083
 
            xMap.transform(d_data->reference), pa.point(sz - 1).y());
1084
 
        pa.setPoint(sz + 1,
1085
 
            xMap.transform(d_data->reference), pa.point(0).y());
1086
 
    }
1087
 
    else
1088
 
    {
1089
 
        pa.setPoint(sz,
1090
 
            pa.point(sz - 1).x(), yMap.transform(d_data->reference));
1091
 
        pa.setPoint(pa.size() - 1,
1092
 
            pa.point(0).x(), yMap.transform(d_data->reference));
1093
 
    }
1094
 
}
1095
 
 
1096
 
/*!
1097
 
  \brief Draw symbols
1098
 
  \param painter Painter
1099
 
  \param symbol Curve symbol
1100
 
  \param xMap x map
1101
 
  \param yMap y map
1102
 
  \param from index of the first point to be painted
1103
 
  \param to index of the last point to be painted
1104
 
 
1105
 
  \sa setSymbol(), draw(), drawCurve()
1106
 
*/
1107
 
void QwtPlotCurve::drawSymbols(QPainter *painter, const QwtSymbol &symbol,
1108
 
    const QwtScaleMap &xMap, const QwtScaleMap &yMap, 
1109
 
    int from, int to) const
1110
 
{
1111
 
    painter->setBrush(symbol.brush());
1112
 
    painter->setPen(symbol.pen());
1113
 
 
1114
 
    QRect rect;
1115
 
    rect.setSize(QwtPainter::metricsMap().screenToLayout(symbol.size()));
1116
 
 
1117
 
    if ( to > from && d_data->paintAttributes & PaintFiltered )
1118
 
    {
1119
 
        const QRect window = painter->window();
1120
 
        if ( window.isEmpty() )
1121
 
            return;
1122
 
 
1123
 
        PrivateData::PixelMatrix pixelMatrix(window);
1124
 
 
1125
 
        for (int i = from; i <= to; i++)
1126
 
        {
1127
 
            const QPoint pi( xMap.transform(x(i)),
1128
 
                yMap.transform(y(i)) );
1129
 
 
1130
 
            if ( pixelMatrix.testPixel(pi) )
1131
 
            {
1132
 
                rect.moveCenter(pi);
1133
 
                symbol.draw(painter, rect);
1134
 
            }
1135
 
        }
1136
 
    }
1137
 
    else
1138
 
    {
1139
 
        for (int i = from; i <= to; i++)
1140
 
        {
1141
 
            const int xi = xMap.transform(x(i));
1142
 
            const int yi = yMap.transform(y(i));
1143
 
 
1144
 
            rect.moveCenter(QPoint(xi, yi));
1145
 
            symbol.draw(painter, rect);
1146
 
        }
1147
 
    }
1148
 
}
1149
 
 
1150
 
/*!
1151
 
  \brief Set the value of the baseline
1152
 
 
1153
 
  The baseline is needed for filling the curve with a brush or
1154
 
  the Sticks drawing style. 
1155
 
  The default value is 0.0. The interpretation
1156
 
  of the baseline depends on the CurveType. With QwtPlotCurve::Yfx,
1157
 
  the baseline is interpreted as a horizontal line at y = baseline(),
1158
 
  with QwtPlotCurve::Yfy, it is interpreted as a vertical line at
1159
 
  x = baseline().
1160
 
  \param reference baseline
1161
 
  \sa baseline(), setBrush(), setStyle(), setCurveType()
1162
 
*/
1163
 
void QwtPlotCurve::setBaseline(double reference)
1164
 
{
1165
 
    if ( d_data->reference != reference )
1166
 
    {
1167
 
        d_data->reference = reference;
1168
 
        itemChanged();
1169
 
    }
1170
 
}
1171
 
 
1172
 
/*!
1173
 
    Return the value of the baseline
1174
 
    \sa setBaseline
1175
 
*/
1176
 
double QwtPlotCurve::baseline() const 
1177
 
1178
 
    return d_data->reference; 
1179
 
}
1180
 
 
1181
 
/*!
1182
 
  Return the size of the data arrays
1183
 
  \sa setData()
1184
 
*/
1185
 
int QwtPlotCurve::dataSize() const
1186
 
{
1187
 
    return d_xy->size();
1188
 
}
1189
 
 
1190
 
int QwtPlotCurve::closestPoint(const QPoint &pos, double *dist) const
1191
 
{
1192
 
    if ( plot() == NULL || dataSize() <= 0 )
1193
 
        return -1;
1194
 
 
1195
 
    const QwtScaleMap xMap = plot()->canvasMap(xAxis());
1196
 
    const QwtScaleMap yMap = plot()->canvasMap(yAxis());
1197
 
 
1198
 
    int index = -1;
1199
 
    double dmin = 1.0e10;
1200
 
 
1201
 
    for (int i=0; i < dataSize(); i++)
1202
 
    {
1203
 
        const double cx = xMap.xTransform(x(i)) - pos.x();
1204
 
        const double cy = yMap.xTransform(y(i)) - pos.y();
1205
 
 
1206
 
        const double f = qwtSqr(cx) + qwtSqr(cy);
1207
 
        if (f < dmin)
1208
 
        {
1209
 
            index = i;
1210
 
            dmin = f;
1211
 
        }
1212
 
    }
1213
 
    if ( dist )
1214
 
        *dist = sqrt(dmin);
1215
 
 
1216
 
    return index;
1217
 
}
1218
 
 
1219
 
//!  Update the widget that represents the curve on the legend
1220
 
void QwtPlotCurve::updateLegend(QwtLegend *legend) const
1221
 
{
1222
 
    if ( !legend )
1223
 
        return;
1224
 
 
1225
 
    QwtPlotItem::updateLegend(legend);
1226
 
 
1227
 
    QWidget *widget = legend->find(this);
1228
 
    if ( !widget || !widget->inherits("QwtLegendItem") )
1229
 
        return;
1230
 
 
1231
 
    QwtLegendItem *legendItem = (QwtLegendItem *)widget;
1232
 
 
1233
 
#if QT_VERSION < 0x040000
1234
 
    const bool doUpdate = legendItem->isUpdatesEnabled();
1235
 
#else
1236
 
    const bool doUpdate = legendItem->updatesEnabled();
1237
 
#endif
1238
 
    legendItem->setUpdatesEnabled(false);
1239
 
 
1240
 
    const int policy = legend->displayPolicy();
1241
 
 
1242
 
    if (policy == QwtLegend::FixedIdentifier)
1243
 
    {
1244
 
        int mode = legend->identifierMode();
1245
 
 
1246
 
        if (mode & QwtLegendItem::ShowLine)
1247
 
            legendItem->setCurvePen(pen());
1248
 
 
1249
 
        if (mode & QwtLegendItem::ShowSymbol)
1250
 
            legendItem->setSymbol(symbol());
1251
 
 
1252
 
        if (mode & QwtLegendItem::ShowText)
1253
 
            legendItem->setText(title());
1254
 
        else
1255
 
            legendItem->setText(QwtText());
1256
 
 
1257
 
        legendItem->setIdentifierMode(mode);
1258
 
    }
1259
 
    else if (policy == QwtLegend::AutoIdentifier)
1260
 
    {
1261
 
        int mode = 0;
1262
 
 
1263
 
        if (QwtPlotCurve::NoCurve != style())
1264
 
        {
1265
 
            legendItem->setCurvePen(pen());
1266
 
            mode |= QwtLegendItem::ShowLine;
1267
 
        }
1268
 
        if (QwtSymbol::NoSymbol != symbol().style())
1269
 
        {
1270
 
            legendItem->setSymbol(symbol());
1271
 
            mode |= QwtLegendItem::ShowSymbol;
1272
 
        }
1273
 
        if ( !title().isEmpty() )
1274
 
        {
1275
 
            legendItem->setText(title());
1276
 
            mode |= QwtLegendItem::ShowText;
1277
 
        }
1278
 
        else
1279
 
        {
1280
 
            legendItem->setText(QwtText());
1281
 
        }
1282
 
        legendItem->setIdentifierMode(mode);
1283
 
    }
1284
 
 
1285
 
    legendItem->setUpdatesEnabled(doUpdate);
1286
 
    legendItem->update();
1287
 
}