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

« back to all changes in this revision

Viewing changes to src/qwt_plot_curve.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Fathi Boudra
  • Date: 2011-06-10 11:22:47 UTC
  • mfrom: (1.1.6 upstream) (2.1.4 sid)
  • Revision ID: james.westby@ubuntu.com-20110610112247-0i1019vvmzaq6p86
Tags: 6.0.0-1
* New upstream release (Closes: #624107):
  - drop Qt3 support. (Closes: #604379, #626868)
* Register documentation with doc-base. (Closes: #626567)
* Drop patches:
  - 01_makefiles.diff
  - 02_add_missing_warnings.diff
  - 03_qwt_branch_pull_r544.diff
* Add qwt_install_paths.patch to fix the hardcoded installation paths.
* Update debian/control:
  - drop libqt3-mt-dev build dependency.
  - bump Standards-Version to 3.9.2 (no changes).
  - drop Qt3 related packages.
  - due to bump soname (and as we dropper Qt3 support):
    - libqwt5-qt4-dev -> libqwt-dev
    - libqwt5-qt4 -> libqwt6
    - libqwt5-doc -> libqwt-doc
* Update debian/copyright file.
* Update debian/rules: drop Qt3 packages support.

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 "qwt_plot_curve.h"
 
11
#include "qwt_math.h"
 
12
#include "qwt_clipper.h"
 
13
#include "qwt_painter.h"
 
14
#include "qwt_legend.h"
 
15
#include "qwt_legend_item.h"
 
16
#include "qwt_scale_map.h"
 
17
#include "qwt_plot.h"
 
18
#include "qwt_plot_canvas.h"
 
19
#include "qwt_curve_fitter.h"
 
20
#include "qwt_symbol.h"
 
21
#include <qpainter.h>
 
22
#include <qpixmap.h>
 
23
#include <qalgorithms.h>
 
24
#include <qmath.h>
 
25
 
 
26
static int verifyRange( int size, int &i1, int &i2 )
 
27
{
 
28
    if ( size < 1 )
 
29
        return 0;
 
30
 
 
31
    i1 = qBound( 0, i1, size - 1 );
 
32
    i2 = qBound( 0, i2, size - 1 );
 
33
 
 
34
    if ( i1 > i2 )
 
35
        qSwap( i1, i2 );
 
36
 
 
37
    return ( i2 - i1 + 1 );
 
38
}
 
39
 
 
40
class QwtPlotCurve::PrivateData
 
41
{
 
42
public:
 
43
    PrivateData():
 
44
        style( QwtPlotCurve::Lines ),
 
45
        baseline( 0.0 ),
 
46
        symbol( NULL ),
 
47
        attributes( 0 ),
 
48
        paintAttributes( QwtPlotCurve::ClipPolygons ),
 
49
        legendAttributes( 0 )
 
50
    {
 
51
        pen = QPen( Qt::black );
 
52
        curveFitter = new QwtSplineCurveFitter;
 
53
    }
 
54
 
 
55
    ~PrivateData()
 
56
    {
 
57
        delete symbol;
 
58
        delete curveFitter;
 
59
    }
 
60
 
 
61
    QwtPlotCurve::CurveStyle style;
 
62
    double baseline;
 
63
 
 
64
    const QwtSymbol *symbol;
 
65
    QwtCurveFitter *curveFitter;
 
66
 
 
67
    QPen pen;
 
68
    QBrush brush;
 
69
 
 
70
    QwtPlotCurve::CurveAttributes attributes;
 
71
    QwtPlotCurve::PaintAttributes paintAttributes;
 
72
 
 
73
    QwtPlotCurve::LegendAttributes legendAttributes;
 
74
};
 
75
 
 
76
/*!
 
77
  Constructor
 
78
  \param title Title of the curve
 
79
*/
 
80
QwtPlotCurve::QwtPlotCurve( const QwtText &title ):
 
81
    QwtPlotSeriesItem<QPointF>( title )
 
82
{
 
83
    init();
 
84
}
 
85
 
 
86
/*!
 
87
  Constructor
 
88
  \param title Title of the curve
 
89
*/
 
90
QwtPlotCurve::QwtPlotCurve( const QString &title ):
 
91
    QwtPlotSeriesItem<QPointF>( QwtText( title ) )
 
92
{
 
93
    init();
 
94
}
 
95
 
 
96
//! Destructor
 
97
QwtPlotCurve::~QwtPlotCurve()
 
98
{
 
99
    delete d_data;
 
100
}
 
101
 
 
102
//! Initialize internal members
 
103
void QwtPlotCurve::init()
 
104
{
 
105
    setItemAttribute( QwtPlotItem::Legend );
 
106
    setItemAttribute( QwtPlotItem::AutoScale );
 
107
 
 
108
    d_data = new PrivateData;
 
109
    d_series = new QwtPointSeriesData();
 
110
 
 
111
    setZ( 20.0 );
 
112
}
 
113
 
 
114
//! \return QwtPlotItem::Rtti_PlotCurve
 
115
int QwtPlotCurve::rtti() const
 
116
{
 
117
    return QwtPlotItem::Rtti_PlotCurve;
 
118
}
 
119
 
 
120
/*!
 
121
  Specify an attribute how to draw the curve
 
122
 
 
123
  \param attribute Paint attribute
 
124
  \param on On/Off
 
125
  \sa testPaintAttribute()
 
126
*/
 
127
void QwtPlotCurve::setPaintAttribute( PaintAttribute attribute, bool on )
 
128
{
 
129
    if ( on )
 
130
        d_data->paintAttributes |= attribute;
 
131
    else
 
132
        d_data->paintAttributes &= ~attribute;
 
133
}
 
134
 
 
135
/*!
 
136
    \brief Return the current paint attributes
 
137
    \sa setPaintAttribute()
 
138
*/
 
139
bool QwtPlotCurve::testPaintAttribute( PaintAttribute attribute ) const
 
140
{
 
141
    return ( d_data->paintAttributes & attribute );
 
142
}
 
143
 
 
144
/*!
 
145
  Specify an attribute how to draw the legend identifier
 
146
 
 
147
  \param attribute Attribute
 
148
  \param on On/Off
 
149
  /sa testLegendAttribute()
 
150
*/
 
151
void QwtPlotCurve::setLegendAttribute( LegendAttribute attribute, bool on )
 
152
{
 
153
    if ( on )
 
154
        d_data->legendAttributes |= attribute;
 
155
    else
 
156
        d_data->legendAttributes &= ~attribute;
 
157
}
 
158
 
 
159
/*!
 
160
    \brief Return the current paint attributes
 
161
    \sa setLegendAttribute()
 
162
*/
 
163
bool QwtPlotCurve::testLegendAttribute( LegendAttribute attribute ) const
 
164
{
 
165
    return ( d_data->legendAttributes & attribute );
 
166
}
 
167
 
 
168
/*!
 
169
  Set the curve's drawing style
 
170
 
 
171
  \param style Curve style
 
172
  \sa style()
 
173
*/
 
174
void QwtPlotCurve::setStyle( CurveStyle style )
 
175
{
 
176
    if ( style != d_data->style )
 
177
    {
 
178
        d_data->style = style;
 
179
        itemChanged();
 
180
    }
 
181
}
 
182
 
 
183
/*!
 
184
    Return the current style
 
185
    \sa setStyle()
 
186
*/
 
187
QwtPlotCurve::CurveStyle QwtPlotCurve::style() const
 
188
{
 
189
    return d_data->style;
 
190
}
 
191
 
 
192
/*!
 
193
  Assign a symbol
 
194
 
 
195
  \param symbol Symbol
 
196
  \sa symbol()
 
197
*/
 
198
void QwtPlotCurve::setSymbol( const QwtSymbol *symbol )
 
199
{
 
200
    if ( symbol != d_data->symbol )
 
201
    {
 
202
        delete d_data->symbol;
 
203
        d_data->symbol = symbol;
 
204
        itemChanged();
 
205
    }
 
206
}
 
207
 
 
208
/*!
 
209
  \return Current symbol or NULL, when no symbol has been assigned
 
210
  \sa setSymbol()
 
211
*/
 
212
const QwtSymbol *QwtPlotCurve::symbol() const
 
213
{
 
214
    return d_data->symbol;
 
215
}
 
216
 
 
217
/*!
 
218
  Assign a pen
 
219
 
 
220
  \param pen New pen
 
221
  \sa pen(), brush()
 
222
*/
 
223
void QwtPlotCurve::setPen( const QPen &pen )
 
224
{
 
225
    if ( pen != d_data->pen )
 
226
    {
 
227
        d_data->pen = pen;
 
228
        itemChanged();
 
229
    }
 
230
}
 
231
 
 
232
/*!
 
233
  \return Pen used to draw the lines
 
234
  \sa setPen(), brush()
 
235
*/
 
236
const QPen& QwtPlotCurve::pen() const
 
237
{
 
238
    return d_data->pen;
 
239
}
 
240
 
 
241
/*!
 
242
  \brief Assign a brush.
 
243
 
 
244
   In case of brush.style() != QBrush::NoBrush
 
245
   and style() != QwtPlotCurve::Sticks
 
246
   the area between the curve and the baseline will be filled.
 
247
 
 
248
   In case !brush.color().isValid() the area will be filled by
 
249
   pen.color(). The fill algorithm simply connects the first and the
 
250
   last curve point to the baseline. So the curve data has to be sorted
 
251
   (ascending or descending).
 
252
 
 
253
  \param brush New brush
 
254
  \sa brush(), setBaseline(), baseline()
 
255
*/
 
256
void QwtPlotCurve::setBrush( const QBrush &brush )
 
257
{
 
258
    if ( brush != d_data->brush )
 
259
    {
 
260
        d_data->brush = brush;
 
261
        itemChanged();
 
262
    }
 
263
}
 
264
 
 
265
/*!
 
266
  \return Brush used to fill the area between lines and the baseline
 
267
  \sa setBrush(), setBaseline(), baseline()
 
268
*/
 
269
const QBrush& QwtPlotCurve::brush() const
 
270
{
 
271
    return d_data->brush;
 
272
}
 
273
 
 
274
/*!
 
275
  Draw an interval of the curve
 
276
 
 
277
  \param painter Painter
 
278
  \param xMap Maps x-values into pixel coordinates.
 
279
  \param yMap Maps y-values into pixel coordinates.
 
280
  \param canvasRect Contents rect of the canvas
 
281
  \param from Index of the first point to be painted
 
282
  \param to Index of the last point to be painted. If to < 0 the
 
283
         curve will be painted to its last point.
 
284
 
 
285
  \sa drawCurve(), drawSymbols(),
 
286
*/
 
287
void QwtPlotCurve::drawSeries( QPainter *painter,
 
288
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
 
289
    const QRectF &canvasRect, int from, int to ) const
 
290
{
 
291
    if ( !painter || dataSize() <= 0 )
 
292
        return;
 
293
 
 
294
    if ( to < 0 )
 
295
        to = dataSize() - 1;
 
296
 
 
297
    if ( verifyRange( dataSize(), from, to ) > 0 )
 
298
    {
 
299
        painter->save();
 
300
        painter->setPen( d_data->pen );
 
301
 
 
302
        /*
 
303
          Qt 4.0.0 is slow when drawing lines, but it's even
 
304
          slower when the painter has a brush. So we don't
 
305
          set the brush before we really need it.
 
306
         */
 
307
 
 
308
        drawCurve( painter, d_data->style, xMap, yMap, canvasRect, from, to );
 
309
        painter->restore();
 
310
 
 
311
        if ( d_data->symbol &&
 
312
            ( d_data->symbol->style() != QwtSymbol::NoSymbol ) )
 
313
        {
 
314
            painter->save();
 
315
            drawSymbols( painter, *d_data->symbol,
 
316
                xMap, yMap, canvasRect, from, to );
 
317
            painter->restore();
 
318
        }
 
319
    }
 
320
}
 
321
 
 
322
/*!
 
323
  \brief Draw the line part (without symbols) of a curve interval.
 
324
  \param painter Painter
 
325
  \param style curve style, see QwtPlotCurve::CurveStyle
 
326
  \param xMap x map
 
327
  \param yMap y map
 
328
  \param canvasRect Contents rect of the canvas
 
329
  \param from index of the first point to be painted
 
330
  \param to index of the last point to be painted
 
331
  \sa draw(), drawDots(), drawLines(), drawSteps(), drawSticks()
 
332
*/
 
333
void QwtPlotCurve::drawCurve( QPainter *painter, int style,
 
334
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
 
335
    const QRectF &canvasRect, int from, int to ) const
 
336
{
 
337
    switch ( style )
 
338
    {
 
339
        case Lines:
 
340
            if ( testCurveAttribute( Fitted ) )
 
341
            {
 
342
                // we always need the complete
 
343
                // curve for fitting
 
344
                from = 0;
 
345
                to = dataSize() - 1;
 
346
            }
 
347
            drawLines( painter, xMap, yMap, canvasRect, from, to );
 
348
            break;
 
349
        case Sticks:
 
350
            drawSticks( painter, xMap, yMap, canvasRect, from, to );
 
351
            break;
 
352
        case Steps:
 
353
            drawSteps( painter, xMap, yMap, canvasRect, from, to );
 
354
            break;
 
355
        case Dots:
 
356
            drawDots( painter, xMap, yMap, canvasRect, from, to );
 
357
            break;
 
358
        case NoCurve:
 
359
        default:
 
360
            break;
 
361
    }
 
362
}
 
363
 
 
364
/*!
 
365
  \brief Draw lines
 
366
 
 
367
  If the CurveAttribute Fitted is enabled a QwtCurveFitter tries
 
368
  to interpolate/smooth the curve, before it is painted.
 
369
 
 
370
  \param painter Painter
 
371
  \param xMap x map
 
372
  \param yMap y map
 
373
  \param canvasRect Contents rect of the canvas
 
374
  \param from index of the first point to be painted
 
375
  \param to index of the last point to be painted
 
376
 
 
377
  \sa setCurveAttribute(), setCurveFitter(), draw(),
 
378
      drawLines(), drawDots(), drawSteps(), drawSticks()
 
379
*/
 
380
void QwtPlotCurve::drawLines( QPainter *painter,
 
381
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
 
382
    const QRectF &canvasRect, int from, int to ) const
 
383
{
 
384
    int size = to - from + 1;
 
385
    if ( size <= 0 )
 
386
        return;
 
387
 
 
388
    const bool doAlign = QwtPainter::roundingAlignment( painter );
 
389
 
 
390
    QPolygonF polyline( size );
 
391
 
 
392
    QPointF *points = polyline.data();
 
393
    for ( int i = from; i <= to; i++ )
 
394
    {
 
395
        const QPointF sample = d_series->sample( i );
 
396
 
 
397
        double x = xMap.transform( sample.x() );
 
398
        double y = yMap.transform( sample.y() );
 
399
        if ( doAlign )
 
400
        {
 
401
            x = qRound( x );
 
402
            y = qRound( y );
 
403
        }
 
404
 
 
405
        points[i - from].rx() = x;
 
406
        points[i - from].ry() = y;
 
407
    }
 
408
 
 
409
    if ( ( d_data->attributes & Fitted ) && d_data->curveFitter )
 
410
        polyline = d_data->curveFitter->fitCurve( polyline );
 
411
 
 
412
    if ( d_data->paintAttributes & ClipPolygons )
 
413
    {
 
414
        qreal pw = qMax( qreal( 1.0 ), painter->pen().widthF());
 
415
        const QPolygonF clipped = QwtClipper::clipPolygonF( 
 
416
            canvasRect.adjusted(-pw, -pw, pw, pw), polyline, false );
 
417
 
 
418
        QwtPainter::drawPolyline( painter, clipped );
 
419
    }
 
420
    else
 
421
    {
 
422
        QwtPainter::drawPolyline( painter, polyline );
 
423
    }
 
424
 
 
425
    if ( d_data->brush.style() != Qt::NoBrush )
 
426
        fillCurve( painter, xMap, yMap, canvasRect, polyline );
 
427
}
 
428
 
 
429
/*!
 
430
  Draw sticks
 
431
 
 
432
  \param painter Painter
 
433
  \param xMap x map
 
434
  \param yMap y map
 
435
  \param canvasRect Contents rect of the canvas
 
436
  \param from index of the first point to be painted
 
437
  \param to index of the last point to be painted
 
438
 
 
439
  \sa draw(), drawCurve(), drawDots(), drawLines(), drawSteps()
 
440
*/
 
441
void QwtPlotCurve::drawSticks( QPainter *painter,
 
442
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
 
443
    const QRectF &, int from, int to ) const
 
444
{
 
445
    painter->save();
 
446
    painter->setRenderHint( QPainter::Antialiasing, false );
 
447
 
 
448
    const bool doAlign = QwtPainter::roundingAlignment( painter );
 
449
 
 
450
    double x0 = xMap.transform( d_data->baseline );
 
451
    double y0 = yMap.transform( d_data->baseline );
 
452
    if ( doAlign )
 
453
    {
 
454
        x0 = qRound( x0 );
 
455
        y0 = qRound( y0 );
 
456
    }
 
457
 
 
458
    const Qt::Orientation o = orientation();
 
459
 
 
460
    for ( int i = from; i <= to; i++ )
 
461
    {
 
462
        const QPointF sample = d_series->sample( i );
 
463
        double xi = xMap.transform( sample.x() );
 
464
        double yi = yMap.transform( sample.y() );
 
465
        if ( doAlign )
 
466
        {
 
467
            xi = qRound( xi );
 
468
            yi = qRound( yi );
 
469
        }
 
470
 
 
471
        if ( o == Qt::Horizontal )
 
472
            QwtPainter::drawLine( painter, x0, yi, xi, yi );
 
473
        else
 
474
            QwtPainter::drawLine( painter, xi, y0, xi, yi );
 
475
    }
 
476
 
 
477
    painter->restore();
 
478
}
 
479
 
 
480
/*!
 
481
  Draw dots
 
482
 
 
483
  \param painter Painter
 
484
  \param xMap x map
 
485
  \param yMap y map
 
486
  \param canvasRect Contents rect of the canvas
 
487
  \param from index of the first point to be painted
 
488
  \param to index of the last point to be painted
 
489
 
 
490
  \sa draw(), drawCurve(), drawSticks(), drawLines(), drawSteps()
 
491
*/
 
492
void QwtPlotCurve::drawDots( QPainter *painter,
 
493
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
 
494
    const QRectF &canvasRect, int from, int to ) const
 
495
{
 
496
    const bool doFill = d_data->brush.style() != Qt::NoBrush;
 
497
    const bool doAlign = QwtPainter::roundingAlignment( painter );
 
498
 
 
499
    QPolygonF polyline;
 
500
    if ( doFill )
 
501
        polyline.resize( to - from + 1 );
 
502
 
 
503
    QPointF *points = polyline.data();
 
504
 
 
505
    for ( int i = from; i <= to; i++ )
 
506
    {
 
507
        const QPointF sample = d_series->sample( i );
 
508
        double xi = xMap.transform( sample.x() );
 
509
        double yi = yMap.transform( sample.y() );
 
510
        if ( doAlign )
 
511
        {
 
512
            xi = qRound( xi );
 
513
            yi = qRound( yi );
 
514
        }
 
515
 
 
516
        QwtPainter::drawPoint( painter, QPointF( xi, yi ) );
 
517
 
 
518
        if ( doFill )
 
519
        {
 
520
            points[i - from].rx() = xi;
 
521
            points[i - from].ry() = yi;
 
522
        }
 
523
    }
 
524
 
 
525
    if ( doFill )
 
526
        fillCurve( painter, xMap, yMap, canvasRect, polyline );
 
527
}
 
528
 
 
529
/*!
 
530
  Draw step function
 
531
 
 
532
  The direction of the steps depends on Inverted attribute.
 
533
 
 
534
  \param painter Painter
 
535
  \param xMap x map
 
536
  \param yMap y map
 
537
  \param canvasRect Contents rect of the canvas
 
538
  \param from index of the first point to be painted
 
539
  \param to index of the last point to be painted
 
540
 
 
541
  \sa CurveAttribute, setCurveAttribute(),
 
542
      draw(), drawCurve(), drawDots(), drawLines(), drawSticks()
 
543
*/
 
544
void QwtPlotCurve::drawSteps( QPainter *painter,
 
545
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
 
546
    const QRectF &canvasRect, int from, int to ) const
 
547
{
 
548
    const bool doAlign = QwtPainter::roundingAlignment( painter );
 
549
 
 
550
    QPolygonF polygon( 2 * ( to - from ) + 1 );
 
551
    QPointF *points = polygon.data();
 
552
 
 
553
    bool inverted = orientation() == Qt::Vertical;
 
554
    if ( d_data->attributes & Inverted )
 
555
        inverted = !inverted;
 
556
 
 
557
    int i, ip;
 
558
    for ( i = from, ip = 0; i <= to; i++, ip += 2 )
 
559
    {
 
560
        const QPointF sample = d_series->sample( i );
 
561
        double xi = xMap.transform( sample.x() );
 
562
        double yi = yMap.transform( sample.y() );
 
563
        if ( doAlign )
 
564
        {
 
565
            xi = qRound( xi );
 
566
            yi = qRound( yi );
 
567
        }
 
568
 
 
569
        if ( ip > 0 )
 
570
        {
 
571
            const QPointF &p0 = points[ip - 2];
 
572
            QPointF &p = points[ip - 1];
 
573
 
 
574
            if ( inverted )
 
575
            {
 
576
                p.rx() = p0.x();
 
577
                p.ry() = yi;
 
578
            }
 
579
            else
 
580
            {
 
581
                p.rx() = xi;
 
582
                p.ry() = p0.y();
 
583
            }
 
584
        }
 
585
 
 
586
        points[ip].rx() = xi;
 
587
        points[ip].ry() = yi;
 
588
    }
 
589
 
 
590
    if ( d_data->paintAttributes & ClipPolygons )
 
591
    {
 
592
        const QPolygonF clipped = QwtClipper::clipPolygonF( 
 
593
            canvasRect, polygon, false );
 
594
 
 
595
        QwtPainter::drawPolyline( painter, clipped );
 
596
    }
 
597
    else
 
598
    {
 
599
        QwtPainter::drawPolyline( painter, polygon );
 
600
    }
 
601
 
 
602
    if ( d_data->brush.style() != Qt::NoBrush )
 
603
        fillCurve( painter, xMap, yMap, canvasRect, polygon );
 
604
}
 
605
 
 
606
 
 
607
/*!
 
608
  Specify an attribute for drawing the curve
 
609
 
 
610
  \param attribute Curve attribute
 
611
  \param on On/Off
 
612
 
 
613
  /sa testCurveAttribute(), setCurveFitter()
 
614
*/
 
615
void QwtPlotCurve::setCurveAttribute( CurveAttribute attribute, bool on )
 
616
{
 
617
    if ( bool( d_data->attributes & attribute ) == on )
 
618
        return;
 
619
 
 
620
    if ( on )
 
621
        d_data->attributes |= attribute;
 
622
    else
 
623
        d_data->attributes &= ~attribute;
 
624
 
 
625
    itemChanged();
 
626
}
 
627
 
 
628
/*!
 
629
    \return true, if attribute is enabled
 
630
    \sa setCurveAttribute()
 
631
*/
 
632
bool QwtPlotCurve::testCurveAttribute( CurveAttribute attribute ) const
 
633
{
 
634
    return d_data->attributes & attribute;
 
635
}
 
636
 
 
637
/*!
 
638
  Assign a curve fitter
 
639
 
 
640
  The curve fitter "smooths" the curve points, when the Fitted
 
641
  CurveAttribute is set. setCurveFitter(NULL) also disables curve fitting.
 
642
 
 
643
  The curve fitter operates on the translated points ( = widget coordinates)
 
644
  to be functional for logarithmic scales. Obviously this is less performant
 
645
  for fitting algorithms, that reduce the number of points.
 
646
 
 
647
  For situations, where curve fitting is used to improve the performance
 
648
  of painting huge series of points it might be better to execute the fitter
 
649
  on the curve points once and to cache the result in the QwtSeriesData object.
 
650
 
 
651
  \param curveFitter() Curve fitter
 
652
  \sa Fitted
 
653
*/
 
654
void QwtPlotCurve::setCurveFitter( QwtCurveFitter *curveFitter )
 
655
{
 
656
    delete d_data->curveFitter;
 
657
    d_data->curveFitter = curveFitter;
 
658
 
 
659
    itemChanged();
 
660
}
 
661
 
 
662
/*!
 
663
  Get the curve fitter. If curve fitting is disabled NULL is returned.
 
664
 
 
665
  \return Curve fitter
 
666
  \sa setCurveFitter(), Fitted
 
667
*/
 
668
QwtCurveFitter *QwtPlotCurve::curveFitter() const
 
669
{
 
670
    return d_data->curveFitter;
 
671
}
 
672
 
 
673
/*!
 
674
  Fill the area between the curve and the baseline with
 
675
  the curve brush
 
676
 
 
677
  \param painter Painter
 
678
  \param xMap x map
 
679
  \param yMap y map
 
680
  \param canvasRect Contents rect of the canvas
 
681
  \param polygon Polygon - will be modified !
 
682
 
 
683
  \sa setBrush(), setBaseline(), setStyle()
 
684
*/
 
685
void QwtPlotCurve::fillCurve( QPainter *painter,
 
686
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
 
687
    const QRectF &canvasRect, QPolygonF &polygon ) const
 
688
{
 
689
    if ( d_data->brush.style() == Qt::NoBrush )
 
690
        return;
 
691
 
 
692
    closePolyline( painter, xMap, yMap, polygon );
 
693
    if ( polygon.count() <= 2 ) // a line can't be filled
 
694
        return;
 
695
 
 
696
    QBrush brush = d_data->brush;
 
697
    if ( !brush.color().isValid() )
 
698
        brush.setColor( d_data->pen.color() );
 
699
 
 
700
    if ( d_data->paintAttributes & ClipPolygons )
 
701
        polygon = QwtClipper::clipPolygonF( canvasRect, polygon, true );
 
702
 
 
703
    painter->save();
 
704
 
 
705
    painter->setPen( Qt::NoPen );
 
706
    painter->setBrush( brush );
 
707
 
 
708
    QwtPainter::drawPolygon( painter, polygon );
 
709
 
 
710
    painter->restore();
 
711
}
 
712
 
 
713
/*!
 
714
  \brief Complete a polygon to be a closed polygon including the 
 
715
         area between the original polygon and the baseline.
 
716
 
 
717
  \param painter Painter
 
718
  \param xMap X map
 
719
  \param yMap Y map
 
720
  \param polygon Polygon to be completed
 
721
*/
 
722
void QwtPlotCurve::closePolyline( QPainter *painter,
 
723
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
 
724
    QPolygonF &polygon ) const
 
725
{
 
726
    if ( polygon.size() < 2 )
 
727
        return;
 
728
 
 
729
    const bool doAlign = QwtPainter::roundingAlignment( painter );
 
730
 
 
731
    double baseline = d_data->baseline;
 
732
    
 
733
    if ( orientation() == Qt::Vertical )
 
734
    {
 
735
        if ( yMap.transformation()->type() == QwtScaleTransformation::Log10 )
 
736
        {
 
737
            if ( baseline < QwtScaleMap::LogMin )
 
738
                baseline = QwtScaleMap::LogMin;
 
739
        }
 
740
 
 
741
        double refY = yMap.transform( baseline );
 
742
        if ( doAlign )
 
743
            refY = qRound( refY );
 
744
 
 
745
        polygon += QPointF( polygon.last().x(), refY );
 
746
        polygon += QPointF( polygon.first().x(), refY );
 
747
    }
 
748
    else
 
749
    {
 
750
        if ( xMap.transformation()->type() == QwtScaleTransformation::Log10 )
 
751
        {
 
752
            if ( baseline < QwtScaleMap::LogMin )
 
753
                baseline = QwtScaleMap::LogMin;
 
754
        }
 
755
 
 
756
        double refX = xMap.transform( baseline );
 
757
        if ( doAlign )
 
758
            refX = qRound( refX );
 
759
 
 
760
        polygon += QPointF( refX, polygon.last().y() );
 
761
        polygon += QPointF( refX, polygon.first().y() );
 
762
    }
 
763
}
 
764
 
 
765
/*!
 
766
  Draw symbols
 
767
 
 
768
  \param painter Painter
 
769
  \param symbol Curve symbol
 
770
  \param xMap x map
 
771
  \param yMap y map
 
772
  \param canvasRect Contents rect of the canvas
 
773
  \param from Index of the first point to be painted
 
774
  \param to Index of the last point to be painted
 
775
 
 
776
  \sa setSymbol(), drawSeries(), drawCurve()
 
777
*/
 
778
void QwtPlotCurve::drawSymbols( QPainter *painter, const QwtSymbol &symbol,
 
779
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
 
780
    const QRectF &canvasRect, int from, int to ) const
 
781
{
 
782
    const bool doAlign = QwtPainter::roundingAlignment( painter );
 
783
 
 
784
    bool usePixmap = testPaintAttribute( CacheSymbols );
 
785
    if ( usePixmap && !doAlign )
 
786
    {
 
787
        // Don't use the pixmap, when the paint device
 
788
        // could generate scalable vectors
 
789
 
 
790
        usePixmap = false;
 
791
    }
 
792
 
 
793
    if ( usePixmap )
 
794
    {
 
795
        QPixmap pm( symbol.boundingSize() );
 
796
        pm.fill( Qt::transparent );
 
797
 
 
798
        const double pw2 = 0.5 * pm.width();
 
799
        const double ph2 = 0.5 * pm.height();
 
800
 
 
801
        QPainter p( &pm );
 
802
        p.setRenderHints( painter->renderHints() );
 
803
        symbol.drawSymbol( &p, QPointF( pw2, ph2 ) );
 
804
        p.end();
 
805
 
 
806
        for ( int i = from; i <= to; i++ )
 
807
        {
 
808
            const QPointF sample = d_series->sample( i );
 
809
 
 
810
            double xi = xMap.transform( sample.x() );
 
811
            double yi = yMap.transform( sample.y() );
 
812
            if ( doAlign )
 
813
            {
 
814
                xi = qRound( xi );
 
815
                yi = qRound( yi );
 
816
            }
 
817
 
 
818
            if ( canvasRect.contains( xi, yi ) )
 
819
            {
 
820
                const int left = qCeil( xi ) - pw2;
 
821
                const int top = qCeil( yi ) - ph2;
 
822
 
 
823
                painter->drawPixmap( left, top, pm );
 
824
            }
 
825
        }
 
826
    }
 
827
    else
 
828
    {
 
829
        const int chunkSize = 500;
 
830
 
 
831
        for ( int i = from; i <= to; i += chunkSize )
 
832
        {
 
833
            const int n = qMin( chunkSize, to - i + 1 );
 
834
 
 
835
            QPolygonF points;
 
836
            for ( int j = 0; j < n; j++ )
 
837
            {
 
838
                const QPointF sample = d_series->sample( i + j );
 
839
 
 
840
                const double xi = xMap.transform( sample.x() );
 
841
                const double yi = yMap.transform( sample.y() );
 
842
 
 
843
                if ( canvasRect.contains( xi, yi ) )
 
844
                    points += QPointF( xi, yi );
 
845
            }
 
846
 
 
847
            if ( points.size() > 0 )
 
848
                symbol.drawSymbols( painter, points );
 
849
        }
 
850
    }
 
851
}
 
852
 
 
853
/*!
 
854
  \brief Set the value of the baseline
 
855
 
 
856
  The baseline is needed for filling the curve with a brush or
 
857
  the Sticks drawing style.
 
858
  The interpretation of the baseline depends on the CurveType.
 
859
  With QwtPlotCurve::Yfx, the baseline is interpreted as a horizontal line
 
860
  at y = baseline(), with QwtPlotCurve::Yfy, it is interpreted as a vertical
 
861
  line at x = baseline().
 
862
 
 
863
  The default value is 0.0.
 
864
 
 
865
  \param value Value of the baseline
 
866
  \sa baseline(), setBrush(), setStyle(), setStyle()
 
867
*/
 
868
void QwtPlotCurve::setBaseline( double value )
 
869
{
 
870
    if ( d_data->baseline != value )
 
871
    {
 
872
        d_data->baseline = value;
 
873
        itemChanged();
 
874
    }
 
875
}
 
876
 
 
877
/*!
 
878
  \return Value of the baseline
 
879
  \sa setBaseline()
 
880
*/
 
881
double QwtPlotCurve::baseline() const
 
882
{
 
883
    return d_data->baseline;
 
884
}
 
885
 
 
886
/*!
 
887
  Find the closest curve point for a specific position
 
888
 
 
889
  \param pos Position, where to look for the closest curve point
 
890
  \param dist If dist != NULL, closestPoint() returns the distance between
 
891
              the position and the clostest curve point
 
892
  \return Index of the closest curve point, or -1 if none can be found
 
893
          ( f.e when the curve has no points )
 
894
  \note closestPoint() implements a dumb algorithm, that iterates
 
895
        over all points
 
896
*/
 
897
int QwtPlotCurve::closestPoint( const QPoint &pos, double *dist ) const
 
898
{
 
899
    if ( plot() == NULL || dataSize() <= 0 )
 
900
        return -1;
 
901
 
 
902
    const QwtScaleMap xMap = plot()->canvasMap( xAxis() );
 
903
    const QwtScaleMap yMap = plot()->canvasMap( yAxis() );
 
904
 
 
905
    int index = -1;
 
906
    double dmin = 1.0e10;
 
907
 
 
908
    for ( uint i = 0; i < dataSize(); i++ )
 
909
    {
 
910
        const QPointF sample = d_series->sample( i );
 
911
 
 
912
        const double cx = xMap.transform( sample.x() ) - pos.x();
 
913
        const double cy = yMap.transform( sample.y() ) - pos.y();
 
914
 
 
915
        const double f = qwtSqr( cx ) + qwtSqr( cy );
 
916
        if ( f < dmin )
 
917
        {
 
918
            index = i;
 
919
            dmin = f;
 
920
        }
 
921
    }
 
922
    if ( dist )
 
923
        *dist = qSqrt( dmin );
 
924
 
 
925
    return index;
 
926
}
 
927
 
 
928
/*!
 
929
   \brief Update the widget that represents the item on the legend
 
930
 
 
931
   \param legend Legend
 
932
   \sa drawLegendIdentifier(), legendItem(), QwtPlotItem::Legend
 
933
*/
 
934
void QwtPlotCurve::updateLegend( QwtLegend *legend ) const
 
935
{
 
936
    if ( legend && testItemAttribute( QwtPlotItem::Legend )
 
937
        && ( d_data->legendAttributes & QwtPlotCurve::LegendShowSymbol )
 
938
        && d_data->symbol
 
939
        && d_data->symbol->style() != QwtSymbol::NoSymbol )
 
940
    {
 
941
        QWidget *lgdItem = legend->find( this );
 
942
        if ( lgdItem == NULL )
 
943
        {
 
944
            lgdItem = legendItem();
 
945
            if ( lgdItem )
 
946
                legend->insert( this, lgdItem );
 
947
        }
 
948
        if ( lgdItem && lgdItem->inherits( "QwtLegendItem" ) )
 
949
        {
 
950
            QwtLegendItem *l = ( QwtLegendItem * )lgdItem;
 
951
            l->setIdentifierSize( d_data->symbol->boundingSize() );
 
952
        }
 
953
    }
 
954
 
 
955
    QwtPlotItem::updateLegend( legend );
 
956
}
 
957
 
 
958
/*!
 
959
  \brief Draw the identifier representing the curve on the legend
 
960
 
 
961
  \param painter Painter
 
962
  \param rect Bounding rectangle for the identifier
 
963
 
 
964
  \sa setLegendAttribute(), QwtPlotItem::Legend
 
965
*/
 
966
void QwtPlotCurve::drawLegendIdentifier(
 
967
    QPainter *painter, const QRectF &rect ) const
 
968
{
 
969
    if ( rect.isEmpty() )
 
970
        return;
 
971
 
 
972
    const int dim = qMin( rect.width(), rect.height() );
 
973
 
 
974
    QSize size( dim, dim );
 
975
 
 
976
    QRectF r( 0, 0, size.width(), size.height() );
 
977
    r.moveCenter( rect.center() );
 
978
 
 
979
    if ( d_data->legendAttributes == 0 )
 
980
    {
 
981
        QBrush brush = d_data->brush;
 
982
        if ( brush.style() == Qt::NoBrush )
 
983
        {
 
984
            if ( style() != QwtPlotCurve::NoCurve )
 
985
                brush = QBrush( pen().color() );
 
986
            else if ( d_data->symbol &&
 
987
                ( d_data->symbol->style() != QwtSymbol::NoSymbol ) )
 
988
            {
 
989
                brush = QBrush( d_data->symbol->pen().color() );
 
990
            }
 
991
        }
 
992
        if ( brush.style() != Qt::NoBrush )
 
993
            painter->fillRect( r, brush );
 
994
    }
 
995
    if ( d_data->legendAttributes & QwtPlotCurve::LegendShowBrush )
 
996
    {
 
997
        if ( d_data->brush.style() != Qt::NoBrush )
 
998
            painter->fillRect( r, d_data->brush );
 
999
    }
 
1000
    if ( d_data->legendAttributes & QwtPlotCurve::LegendShowLine )
 
1001
    {
 
1002
        if ( pen() != Qt::NoPen )
 
1003
        {
 
1004
            painter->setPen( pen() );
 
1005
            QwtPainter::drawLine( painter, rect.left(), rect.center().y(),
 
1006
                                  rect.right() - 1.0, rect.center().y() );
 
1007
        }
 
1008
    }
 
1009
    if ( d_data->legendAttributes & QwtPlotCurve::LegendShowSymbol )
 
1010
    {
 
1011
        if ( d_data->symbol &&
 
1012
            ( d_data->symbol->style() != QwtSymbol::NoSymbol ) )
 
1013
        {
 
1014
            QSize symbolSize = d_data->symbol->boundingSize();
 
1015
            symbolSize -= QSize( 2, 2 );
 
1016
 
 
1017
            // scale the symbol size down if it doesn't fit into rect.
 
1018
 
 
1019
            double xRatio = 1.0;
 
1020
            if ( rect.width() < symbolSize.width() )
 
1021
                xRatio = rect.width() / symbolSize.width();
 
1022
            double yRatio = 1.0;
 
1023
            if ( rect.height() < symbolSize.height() )
 
1024
                yRatio = rect.height() / symbolSize.height();
 
1025
 
 
1026
            const double ratio = qMin( xRatio, yRatio );
 
1027
 
 
1028
            painter->save();
 
1029
            painter->scale( ratio, ratio );
 
1030
 
 
1031
            d_data->symbol->drawSymbol( painter, rect.center() / ratio );
 
1032
 
 
1033
            painter->restore();
 
1034
        }
 
1035
    }
 
1036
}
 
1037
 
 
1038
/*!
 
1039
  Initialize data with an array of points (explicitly shared).
 
1040
 
 
1041
  \param samples Vector of points
 
1042
*/
 
1043
void QwtPlotCurve::setSamples( const QVector<QPointF> &samples )
 
1044
{
 
1045
    delete d_series;
 
1046
    d_series = new QwtPointSeriesData( samples );
 
1047
    itemChanged();
 
1048
}
 
1049
 
 
1050
#ifndef QWT_NO_COMPAT
 
1051
 
 
1052
/*!
 
1053
  \brief Initialize the data by pointing to memory blocks which 
 
1054
         are not managed by QwtPlotCurve.
 
1055
 
 
1056
  setRawSamples is provided for efficiency. 
 
1057
  It is important to keep the pointers
 
1058
  during the lifetime of the underlying QwtCPointerData class.
 
1059
 
 
1060
  \param xData pointer to x data
 
1061
  \param yData pointer to y data
 
1062
  \param size size of x and y
 
1063
 
 
1064
  \sa QwtCPointerData
 
1065
*/
 
1066
void QwtPlotCurve::setRawSamples( 
 
1067
    const double *xData, const double *yData, int size )
 
1068
{
 
1069
    delete d_series;
 
1070
    d_series = new QwtCPointerData( xData, yData, size );
 
1071
    itemChanged();
 
1072
}
 
1073
 
 
1074
/*!
 
1075
  Set data by copying x- and y-values from specified memory blocks.
 
1076
  Contrary to setRawSamples(), this function makes a 'deep copy' of
 
1077
  the data.
 
1078
 
 
1079
  \param xData pointer to x values
 
1080
  \param yData pointer to y values
 
1081
  \param size size of xData and yData
 
1082
 
 
1083
  \sa QwtPointArrayData
 
1084
*/
 
1085
void QwtPlotCurve::setSamples( 
 
1086
    const double *xData, const double *yData, int size )
 
1087
{
 
1088
    delete d_series;
 
1089
    d_series = new QwtPointArrayData( xData, yData, size );
 
1090
    itemChanged();
 
1091
}
 
1092
 
 
1093
/*!
 
1094
  \brief Initialize data with x- and y-arrays (explicitly shared)
 
1095
 
 
1096
  \param xData x data
 
1097
  \param yData y data
 
1098
 
 
1099
  \sa QwtPointArrayData
 
1100
*/
 
1101
void QwtPlotCurve::setSamples( const QVector<double> &xData,
 
1102
    const QVector<double> &yData )
 
1103
{
 
1104
    delete d_series;
 
1105
    d_series = new QwtPointArrayData( xData, yData );
 
1106
    itemChanged();
 
1107
}
 
1108
#endif // !QWT_NO_COMPAT
 
1109