qwt_plot_curve.cpp 29.9 KB
Newer Older
pixhawk's avatar
pixhawk committed
1 2 3 4 5 6 7 8 9
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
 * Qwt Widget Library
 * Copyright (C) 1997   Josef Wilgen
 * Copyright (C) 2002   Uwe Rathmann
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the Qwt License, Version 1.0
 *****************************************************************************/

Bryant's avatar
Bryant committed
10 11
#include "qwt_plot_curve.h"
#include "qwt_point_data.h"
pixhawk's avatar
pixhawk committed
12 13 14
#include "qwt_math.h"
#include "qwt_clipper.h"
#include "qwt_painter.h"
Bryant's avatar
Bryant committed
15
#include "qwt_scale_map.h"
pixhawk's avatar
pixhawk committed
16 17 18
#include "qwt_plot.h"
#include "qwt_curve_fitter.h"
#include "qwt_symbol.h"
Bryant's avatar
Bryant committed
19 20 21 22 23
#include "qwt_point_mapper.h"
#include <qpainter.h>
#include <qpixmap.h>
#include <qalgorithms.h>
#include <qmath.h>
pixhawk's avatar
pixhawk committed
24

Bryant's avatar
Bryant committed
25
static void qwtUpdateLegendIconSize( QwtPlotCurve *curve )
pixhawk's avatar
pixhawk committed
26
{
Bryant's avatar
Bryant committed
27 28 29 30 31
    if ( curve->symbol() && 
        curve->testLegendAttribute( QwtPlotCurve::LegendShowSymbol ) )
    {
        QSize sz = curve->symbol()->boundingRect().size();
        sz += QSize( 2, 2 ); // margin
pixhawk's avatar
pixhawk committed
32

Bryant's avatar
Bryant committed
33 34 35
        if ( curve->testLegendAttribute( QwtPlotCurve::LegendShowLine ) )
        {
            // Avoid, that the line is completely covered by the symbol
pixhawk's avatar
pixhawk committed
36

Bryant's avatar
Bryant committed
37 38 39
            int w = qCeil( 1.5 * sz.width() );
            if ( w % 2 )
                w++;
pixhawk's avatar
pixhawk committed
40

Bryant's avatar
Bryant committed
41
            sz.setWidth( qMax( 8, w ) );
pixhawk's avatar
pixhawk committed
42 43
        }

Bryant's avatar
Bryant committed
44
        curve->setLegendIconSize( sz );
pixhawk's avatar
pixhawk committed
45 46 47
    }
}

Bryant's avatar
Bryant committed
48
static int qwtVerifyRange( int size, int &i1, int &i2 )
pixhawk's avatar
pixhawk committed
49
{
Bryant's avatar
Bryant committed
50
    if ( size < 1 )
pixhawk's avatar
pixhawk committed
51 52
        return 0;

Bryant's avatar
Bryant committed
53 54
    i1 = qBound( 0, i1, size - 1 );
    i2 = qBound( 0, i2, size - 1 );
pixhawk's avatar
pixhawk committed
55 56

    if ( i1 > i2 )
Bryant's avatar
Bryant committed
57
        qSwap( i1, i2 );
pixhawk's avatar
pixhawk committed
58

Bryant's avatar
Bryant committed
59
    return ( i2 - i1 + 1 );
pixhawk's avatar
pixhawk committed
60 61 62 63 64 65
}

class QwtPlotCurve::PrivateData
{
public:
    PrivateData():
Bryant's avatar
Bryant committed
66 67 68 69 70 71 72 73 74
        style( QwtPlotCurve::Lines ),
        baseline( 0.0 ),
        symbol( NULL ),
        attributes( 0 ),
        paintAttributes( 
            QwtPlotCurve::ClipPolygons | QwtPlotCurve::FilterPoints ),
        legendAttributes( 0 )
    {
        pen = QPen( Qt::black );
pixhawk's avatar
pixhawk committed
75 76 77
        curveFitter = new QwtSplineCurveFitter;
    }

Bryant's avatar
Bryant committed
78 79
    ~PrivateData()
    {
pixhawk's avatar
pixhawk committed
80 81 82 83 84
        delete symbol;
        delete curveFitter;
    }

    QwtPlotCurve::CurveStyle style;
Bryant's avatar
Bryant committed
85
    double baseline;
pixhawk's avatar
pixhawk committed
86

Bryant's avatar
Bryant committed
87
    const QwtSymbol *symbol;
pixhawk's avatar
pixhawk committed
88 89 90 91 92
    QwtCurveFitter *curveFitter;

    QPen pen;
    QBrush brush;

Bryant's avatar
Bryant committed
93 94
    QwtPlotCurve::CurveAttributes attributes;
    QwtPlotCurve::PaintAttributes paintAttributes;
pixhawk's avatar
pixhawk committed
95

Bryant's avatar
Bryant committed
96
    QwtPlotCurve::LegendAttributes legendAttributes;
pixhawk's avatar
pixhawk committed
97 98 99 100
};

/*!
  Constructor
Bryant's avatar
Bryant committed
101
  \param title Title of the curve
pixhawk's avatar
pixhawk committed
102
*/
Bryant's avatar
Bryant committed
103 104
QwtPlotCurve::QwtPlotCurve( const QwtText &title ):
    QwtPlotSeriesItem( title )
pixhawk's avatar
pixhawk committed
105 106 107 108 109 110
{
    init();
}

/*!
  Constructor
Bryant's avatar
Bryant committed
111
  \param title Title of the curve
pixhawk's avatar
pixhawk committed
112
*/
Bryant's avatar
Bryant committed
113 114
QwtPlotCurve::QwtPlotCurve( const QString &title ):
    QwtPlotSeriesItem( QwtText( title ) )
pixhawk's avatar
pixhawk committed
115 116 117 118 119 120 121 122 123 124
{
    init();
}

//! Destructor
QwtPlotCurve::~QwtPlotCurve()
{
    delete d_data;
}

Bryant's avatar
Bryant committed
125
//! Initialize internal members
pixhawk's avatar
pixhawk committed
126 127
void QwtPlotCurve::init()
{
Bryant's avatar
Bryant committed
128 129
    setItemAttribute( QwtPlotItem::Legend );
    setItemAttribute( QwtPlotItem::AutoScale );
pixhawk's avatar
pixhawk committed
130 131

    d_data = new PrivateData;
Bryant's avatar
Bryant committed
132
    setData( new QwtPointSeriesData() );
pixhawk's avatar
pixhawk committed
133

Bryant's avatar
Bryant committed
134
    setZ( 20.0 );
pixhawk's avatar
pixhawk committed
135 136 137 138 139 140 141 142 143
}

//! \return QwtPlotItem::Rtti_PlotCurve
int QwtPlotCurve::rtti() const
{
    return QwtPlotItem::Rtti_PlotCurve;
}

/*!
Bryant's avatar
Bryant committed
144
  Specify an attribute how to draw the curve
pixhawk's avatar
pixhawk committed
145 146 147

  \param attribute Paint attribute
  \param on On/Off
Bryant's avatar
Bryant committed
148
  \sa testPaintAttribute()
pixhawk's avatar
pixhawk committed
149
*/
Bryant's avatar
Bryant committed
150
void QwtPlotCurve::setPaintAttribute( PaintAttribute attribute, bool on )
pixhawk's avatar
pixhawk committed
151 152 153 154 155 156 157 158
{
    if ( on )
        d_data->paintAttributes |= attribute;
    else
        d_data->paintAttributes &= ~attribute;
}

/*!
Bryant's avatar
Bryant committed
159 160
    \return True, when attribute is enabled
    \sa setPaintAttribute()
pixhawk's avatar
pixhawk committed
161
*/
Bryant's avatar
Bryant committed
162
bool QwtPlotCurve::testPaintAttribute( PaintAttribute attribute ) const
pixhawk's avatar
pixhawk committed
163
{
Bryant's avatar
Bryant committed
164
    return ( d_data->paintAttributes & attribute );
pixhawk's avatar
pixhawk committed
165 166 167
}

/*!
Bryant's avatar
Bryant committed
168 169 170 171 172
  Specify an attribute how to draw the legend icon

  \param attribute Attribute
  \param on On/Off
  /sa testLegendAttribute(). legendIcon()
pixhawk's avatar
pixhawk committed
173
*/
Bryant's avatar
Bryant committed
174
void QwtPlotCurve::setLegendAttribute( LegendAttribute attribute, bool on )
pixhawk's avatar
pixhawk committed
175
{
Bryant's avatar
Bryant committed
176 177 178 179 180 181 182 183 184
    if ( on != testLegendAttribute( attribute ) )
    {
        if ( on )
            d_data->legendAttributes |= attribute;
        else
            d_data->legendAttributes &= ~attribute;

        qwtUpdateLegendIconSize( this );
        legendChanged();
pixhawk's avatar
pixhawk committed
185 186 187 188
    }
}

/*!
Bryant's avatar
Bryant committed
189 190
  \return True, when attribute is enabled
  \sa setLegendAttribute()
pixhawk's avatar
pixhawk committed
191
*/
Bryant's avatar
Bryant committed
192
bool QwtPlotCurve::testLegendAttribute( LegendAttribute attribute ) const
193
{
Bryant's avatar
Bryant committed
194
    return ( d_data->legendAttributes & attribute );
pixhawk's avatar
pixhawk committed
195 196 197
}

/*!
Bryant's avatar
Bryant committed
198
  Set the curve's drawing style
pixhawk's avatar
pixhawk committed
199

Bryant's avatar
Bryant committed
200 201
  \param style Curve style
  \sa style()
pixhawk's avatar
pixhawk committed
202
*/
Bryant's avatar
Bryant committed
203
void QwtPlotCurve::setStyle( CurveStyle style )
204
{
Bryant's avatar
Bryant committed
205 206 207
    if ( style != d_data->style )
    {
        d_data->style = style;
pixhawk's avatar
pixhawk committed
208

Bryant's avatar
Bryant committed
209
        legendChanged();
pixhawk's avatar
pixhawk committed
210 211 212 213 214
        itemChanged();
    }
}

/*!
Bryant's avatar
Bryant committed
215 216
  \return Style of the curve
  \sa setStyle()
pixhawk's avatar
pixhawk committed
217
*/
Bryant's avatar
Bryant committed
218
QwtPlotCurve::CurveStyle QwtPlotCurve::style() const
219
{
Bryant's avatar
Bryant committed
220
    return d_data->style;
pixhawk's avatar
pixhawk committed
221 222 223
}

/*!
Bryant's avatar
Bryant committed
224 225 226 227 228 229 230 231
  \brief Assign a symbol

  The curve will take the ownership of the symbol, hence the previously
  set symbol will be delete by setting a new one. If \p symbol is 
  \c NULL no symbol will be drawn.

  \param symbol Symbol
  \sa symbol()
pixhawk's avatar
pixhawk committed
232
*/
Bryant's avatar
Bryant committed
233
void QwtPlotCurve::setSymbol( QwtSymbol *symbol )
pixhawk's avatar
pixhawk committed
234
{
Bryant's avatar
Bryant committed
235 236 237 238 239 240 241 242
    if ( symbol != d_data->symbol )
    {
        delete d_data->symbol;
        d_data->symbol = symbol;

        qwtUpdateLegendIconSize( this );

        legendChanged();
pixhawk's avatar
pixhawk committed
243 244 245 246 247
        itemChanged();
    }
}

/*!
Bryant's avatar
Bryant committed
248 249
  \return Current symbol or NULL, when no symbol has been assigned
  \sa setSymbol()
pixhawk's avatar
pixhawk committed
250
*/
Bryant's avatar
Bryant committed
251
const QwtSymbol *QwtPlotCurve::symbol() const
pixhawk's avatar
pixhawk committed
252
{
Bryant's avatar
Bryant committed
253
    return d_data->symbol;
pixhawk's avatar
pixhawk committed
254 255 256
}

/*!
Bryant's avatar
Bryant committed
257
  Build and assign a pen
pixhawk's avatar
pixhawk committed
258

Bryant's avatar
Bryant committed
259 260 261
  In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it
  non cosmetic ( see QPen::isCosmetic() ). This method has been introduced
  to hide this incompatibility.
pixhawk's avatar
pixhawk committed
262

Bryant's avatar
Bryant committed
263 264 265
  \param color Pen color
  \param width Pen width
  \param style Pen style
pixhawk's avatar
pixhawk committed
266

Bryant's avatar
Bryant committed
267 268 269
  \sa pen(), brush()
 */
void QwtPlotCurve::setPen( const QColor &color, qreal width, Qt::PenStyle style )
pixhawk's avatar
pixhawk committed
270
{
Bryant's avatar
Bryant committed
271
    setPen( QPen( color, width, style ) );
pixhawk's avatar
pixhawk committed
272 273 274
}

/*!
Bryant's avatar
Bryant committed
275
  Assign a pen
pixhawk's avatar
pixhawk committed
276

Bryant's avatar
Bryant committed
277 278
  \param pen New pen
  \sa pen(), brush()
pixhawk's avatar
pixhawk committed
279
*/
Bryant's avatar
Bryant committed
280
void QwtPlotCurve::setPen( const QPen &pen )
pixhawk's avatar
pixhawk committed
281
{
Bryant's avatar
Bryant committed
282 283 284 285 286 287 288
    if ( pen != d_data->pen )
    {
        d_data->pen = pen;

        legendChanged();
        itemChanged();
    }
pixhawk's avatar
pixhawk committed
289 290 291
}

/*!
Bryant's avatar
Bryant committed
292 293
  \return Pen used to draw the lines
  \sa setPen(), brush()
pixhawk's avatar
pixhawk committed
294
*/
Bryant's avatar
Bryant committed
295
const QPen& QwtPlotCurve::pen() const
pixhawk's avatar
pixhawk committed
296
{
Bryant's avatar
Bryant committed
297
    return d_data->pen;
pixhawk's avatar
pixhawk committed
298 299 300
}

/*!
Bryant's avatar
Bryant committed
301
  \brief Assign a brush.
pixhawk's avatar
pixhawk committed
302

Bryant's avatar
Bryant committed
303 304 305
   In case of brush.style() != QBrush::NoBrush
   and style() != QwtPlotCurve::Sticks
   the area between the curve and the baseline will be filled.
pixhawk's avatar
pixhawk committed
306

Bryant's avatar
Bryant committed
307 308 309 310
   In case !brush.color().isValid() the area will be filled by
   pen.color(). The fill algorithm simply connects the first and the
   last curve point to the baseline. So the curve data has to be sorted
   (ascending or descending).
pixhawk's avatar
pixhawk committed
311

Bryant's avatar
Bryant committed
312 313
  \param brush New brush
  \sa brush(), setBaseline(), baseline()
pixhawk's avatar
pixhawk committed
314
*/
Bryant's avatar
Bryant committed
315
void QwtPlotCurve::setBrush( const QBrush &brush )
pixhawk's avatar
pixhawk committed
316
{
Bryant's avatar
Bryant committed
317 318 319 320 321 322 323
    if ( brush != d_data->brush )
    {
        d_data->brush = brush;

        legendChanged();
        itemChanged();
    }
pixhawk's avatar
pixhawk committed
324 325 326
}

/*!
Bryant's avatar
Bryant committed
327 328
  \return Brush used to fill the area between lines and the baseline
  \sa setBrush(), setBaseline(), baseline()
pixhawk's avatar
pixhawk committed
329
*/
Bryant's avatar
Bryant committed
330
const QBrush& QwtPlotCurve::brush() const
pixhawk's avatar
pixhawk committed
331
{
Bryant's avatar
Bryant committed
332
    return d_data->brush;
pixhawk's avatar
pixhawk committed
333 334 335
}

/*!
Bryant's avatar
Bryant committed
336
  Draw an interval of the curve
pixhawk's avatar
pixhawk committed
337 338 339 340

  \param painter Painter
  \param xMap Maps x-values into pixel coordinates.
  \param yMap Maps y-values into pixel coordinates.
Bryant's avatar
Bryant committed
341
  \param canvasRect Contents rectangle of the canvas
pixhawk's avatar
pixhawk committed
342 343 344 345
  \param from Index of the first point to be painted
  \param to Index of the last point to be painted. If to < 0 the
         curve will be painted to its last point.

Bryant's avatar
Bryant committed
346
  \sa drawCurve(), drawSymbols(),
pixhawk's avatar
pixhawk committed
347
*/
Bryant's avatar
Bryant committed
348 349 350
void QwtPlotCurve::drawSeries( QPainter *painter,
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    const QRectF &canvasRect, int from, int to ) const
pixhawk's avatar
pixhawk committed
351
{
352
    const int numSamples = static_cast<int>(dataSize());
pixhawk's avatar
pixhawk committed
353

Bryant's avatar
Bryant committed
354
    if ( !painter || numSamples <= 0 )
pixhawk's avatar
pixhawk committed
355 356
        return;

Bryant's avatar
Bryant committed
357 358
    if ( to < 0 )
        to = numSamples - 1;
pixhawk's avatar
pixhawk committed
359

Bryant's avatar
Bryant committed
360
    if ( qwtVerifyRange( numSamples, from, to ) > 0 )
pixhawk's avatar
pixhawk committed
361 362
    {
        painter->save();
Bryant's avatar
Bryant committed
363
        painter->setPen( d_data->pen );
pixhawk's avatar
pixhawk committed
364 365

        /*
366
          Qt 4.0.0 is slow when drawing lines, but it's even
pixhawk's avatar
pixhawk committed
367 368 369 370
          slower when the painter has a brush. So we don't
          set the brush before we really need it.
         */

Bryant's avatar
Bryant committed
371
        drawCurve( painter, d_data->style, xMap, yMap, canvasRect, from, to );
pixhawk's avatar
pixhawk committed
372 373
        painter->restore();

Bryant's avatar
Bryant committed
374 375 376
        if ( d_data->symbol &&
            ( d_data->symbol->style() != QwtSymbol::NoSymbol ) )
        {
pixhawk's avatar
pixhawk committed
377
            painter->save();
Bryant's avatar
Bryant committed
378 379
            drawSymbols( painter, *d_data->symbol,
                xMap, yMap, canvasRect, from, to );
pixhawk's avatar
pixhawk committed
380 381 382 383 384 385
            painter->restore();
        }
    }
}

/*!
386
  \brief Draw the line part (without symbols) of a curve interval.
pixhawk's avatar
pixhawk committed
387 388 389 390
  \param painter Painter
  \param style curve style, see QwtPlotCurve::CurveStyle
  \param xMap x map
  \param yMap y map
Bryant's avatar
Bryant committed
391
  \param canvasRect Contents rectangle of the canvas
pixhawk's avatar
pixhawk committed
392 393 394 395
  \param from index of the first point to be painted
  \param to index of the last point to be painted
  \sa draw(), drawDots(), drawLines(), drawSteps(), drawSticks()
*/
Bryant's avatar
Bryant committed
396 397 398
void QwtPlotCurve::drawCurve( QPainter *painter, int style,
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    const QRectF &canvasRect, int from, int to ) const
pixhawk's avatar
pixhawk committed
399
{
Bryant's avatar
Bryant committed
400 401 402 403 404 405 406 407
    switch ( style )
    {
        case Lines:
            if ( testCurveAttribute( Fitted ) )
            {
                // we always need the complete
                // curve for fitting
                from = 0;
408
                to = static_cast<int>(dataSize()) - 1;
Bryant's avatar
Bryant committed
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
            }
            drawLines( painter, xMap, yMap, canvasRect, from, to );
            break;
        case Sticks:
            drawSticks( painter, xMap, yMap, canvasRect, from, to );
            break;
        case Steps:
            drawSteps( painter, xMap, yMap, canvasRect, from, to );
            break;
        case Dots:
            drawDots( painter, xMap, yMap, canvasRect, from, to );
            break;
        case NoCurve:
        default:
            break;
pixhawk's avatar
pixhawk committed
424 425 426 427 428 429 430 431 432 433 434 435
    }
}

/*!
  \brief Draw lines

  If the CurveAttribute Fitted is enabled a QwtCurveFitter tries
  to interpolate/smooth the curve, before it is painted.

  \param painter Painter
  \param xMap x map
  \param yMap y map
Bryant's avatar
Bryant committed
436
  \param canvasRect Contents rectangle of the canvas
pixhawk's avatar
pixhawk committed
437 438 439
  \param from index of the first point to be painted
  \param to index of the last point to be painted

440
  \sa setCurveAttribute(), setCurveFitter(), draw(),
pixhawk's avatar
pixhawk committed
441 442
      drawLines(), drawDots(), drawSteps(), drawSticks()
*/
Bryant's avatar
Bryant committed
443 444 445
void QwtPlotCurve::drawLines( QPainter *painter,
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    const QRectF &canvasRect, int from, int to ) const
pixhawk's avatar
pixhawk committed
446
{
Bryant's avatar
Bryant committed
447
    if ( from > to )
pixhawk's avatar
pixhawk committed
448 449
        return;

Bryant's avatar
Bryant committed
450 451 452 453
    const bool doAlign = QwtPainter::roundingAlignment( painter );
    const bool doFit = ( d_data->attributes & Fitted ) && d_data->curveFitter;
    const bool doFill = ( d_data->brush.style() != Qt::NoBrush )
            && ( d_data->brush.color().alpha() > 0 );
pixhawk's avatar
pixhawk committed
454

Bryant's avatar
Bryant committed
455 456 457 458 459 460 461 462 463 464 465 466 467 468
    QRectF clipRect;
    if ( d_data->paintAttributes & ClipPolygons )
    {
        qreal pw = qMax( qreal( 1.0 ), painter->pen().widthF());
        clipRect = canvasRect.adjusted(-pw, -pw, pw, pw);
    }

    bool doIntegers = false;

#if QT_VERSION < 0x040800

    // For Qt <= 4.7 the raster paint engine is significantly faster
    // for rendering QPolygon than for QPolygonF. So let's
    // see if we can use it.
pixhawk's avatar
pixhawk committed
469

Bryant's avatar
Bryant committed
470 471 472 473 474
    if ( painter->paintEngine()->type() == QPaintEngine::Raster )
    {
        // In case of filling or fitting performance doesn't count
        // because both operations are much more expensive
        // then drawing the polyline itself
pixhawk's avatar
pixhawk committed
475

Bryant's avatar
Bryant committed
476 477 478 479
        if ( !doFit && !doFill )
            doIntegers = true; 
    }
#endif
pixhawk's avatar
pixhawk committed
480

Bryant's avatar
Bryant committed
481
    const bool noDuplicates = d_data->paintAttributes & FilterPoints;
pixhawk's avatar
pixhawk committed
482

Bryant's avatar
Bryant committed
483 484 485 486
    QwtPointMapper mapper;
    mapper.setFlag( QwtPointMapper::RoundPoints, doAlign );
    mapper.setFlag( QwtPointMapper::WeedOutPoints, noDuplicates );
    mapper.setBoundingRect( canvasRect );
pixhawk's avatar
pixhawk committed
487

Bryant's avatar
Bryant committed
488 489 490 491
    if ( doIntegers )
    {
        const QPolygon polyline = mapper.toPolygon( 
            xMap, yMap, data(), from, to );
pixhawk's avatar
pixhawk committed
492

Bryant's avatar
Bryant committed
493 494 495 496
        if ( d_data->paintAttributes & ClipPolygons )
        {
            const QPolygon clipped = QwtClipper::clipPolygon( 
                clipRect.toAlignedRect(), polyline, false );
pixhawk's avatar
pixhawk committed
497

Bryant's avatar
Bryant committed
498
            QwtPainter::drawPolyline( painter, clipped );
pixhawk's avatar
pixhawk committed
499
        }
Bryant's avatar
Bryant committed
500 501 502
        else
        {
            QwtPainter::drawPolyline( painter, polyline );
pixhawk's avatar
pixhawk committed
503 504
        }
    }
Bryant's avatar
Bryant committed
505 506 507 508
    else
    {
        QPolygonF polyline = mapper.toPolygonF( xMap, yMap,
            data(), from, to );
pixhawk's avatar
pixhawk committed
509

Bryant's avatar
Bryant committed
510 511
        if ( doFit )
            polyline = d_data->curveFitter->fitCurve( polyline );
pixhawk's avatar
pixhawk committed
512

Bryant's avatar
Bryant committed
513 514 515 516
        if ( d_data->paintAttributes & ClipPolygons )
        {
            const QPolygonF clipped = QwtClipper::clipPolygonF( 
                clipRect, polyline, false );
pixhawk's avatar
pixhawk committed
517

Bryant's avatar
Bryant committed
518 519 520 521 522 523 524 525 526 527 528 529
            QwtPainter::drawPolyline( painter, clipped );
        }
        else
        {
            QwtPainter::drawPolyline( painter, polyline );
        }

        if ( doFill )
        {
            fillCurve( painter, xMap, yMap, canvasRect, polyline );
        }
    }
pixhawk's avatar
pixhawk committed
530 531 532 533 534 535 536 537
}

/*!
  Draw sticks

  \param painter Painter
  \param xMap x map
  \param yMap y map
Bryant's avatar
Bryant committed
538
  \param canvasRect Contents rectangle of the canvas
pixhawk's avatar
pixhawk committed
539 540 541 542 543
  \param from index of the first point to be painted
  \param to index of the last point to be painted

  \sa draw(), drawCurve(), drawDots(), drawLines(), drawSteps()
*/
Bryant's avatar
Bryant committed
544 545 546
void QwtPlotCurve::drawSticks( QPainter *painter,
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    const QRectF &, int from, int to ) const
pixhawk's avatar
pixhawk committed
547
{
Bryant's avatar
Bryant committed
548 549
    painter->save();
    painter->setRenderHint( QPainter::Antialiasing, false );
pixhawk's avatar
pixhawk committed
550

Bryant's avatar
Bryant committed
551 552 553 554 555 556 557 558 559
    const bool doAlign = QwtPainter::roundingAlignment( painter );

    double x0 = xMap.transform( d_data->baseline );
    double y0 = yMap.transform( d_data->baseline );
    if ( doAlign )
    {
        x0 = qRound( x0 );
        y0 = qRound( y0 );
    }
pixhawk's avatar
pixhawk committed
560

Bryant's avatar
Bryant committed
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577
    const Qt::Orientation o = orientation();

    const QwtSeriesData<QPointF> *series = data();

    for ( int i = from; i <= to; i++ )
    {
        const QPointF sample = series->sample( i );
        double xi = xMap.transform( sample.x() );
        double yi = yMap.transform( sample.y() );
        if ( doAlign )
        {
            xi = qRound( xi );
            yi = qRound( yi );
        }

        if ( o == Qt::Horizontal )
            QwtPainter::drawLine( painter, x0, yi, xi, yi );
pixhawk's avatar
pixhawk committed
578
        else
Bryant's avatar
Bryant committed
579
            QwtPainter::drawLine( painter, xi, y0, xi, yi );
pixhawk's avatar
pixhawk committed
580
    }
Bryant's avatar
Bryant committed
581 582

    painter->restore();
pixhawk's avatar
pixhawk committed
583 584 585 586 587 588 589 590
}

/*!
  Draw dots

  \param painter Painter
  \param xMap x map
  \param yMap y map
Bryant's avatar
Bryant committed
591
  \param canvasRect Contents rectangle of the canvas
pixhawk's avatar
pixhawk committed
592 593 594 595 596
  \param from index of the first point to be painted
  \param to index of the last point to be painted

  \sa draw(), drawCurve(), drawSticks(), drawLines(), drawSteps()
*/
Bryant's avatar
Bryant committed
597 598 599
void QwtPlotCurve::drawDots( QPainter *painter,
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    const QRectF &canvasRect, int from, int to ) const
pixhawk's avatar
pixhawk committed
600
{
Bryant's avatar
Bryant committed
601 602 603 604
    const QColor color = painter->pen().color();

    if ( painter->pen().style() == Qt::NoPen || color.alpha() == 0 )
    {
pixhawk's avatar
pixhawk committed
605
        return;
Bryant's avatar
Bryant committed
606
    }
pixhawk's avatar
pixhawk committed
607

Bryant's avatar
Bryant committed
608 609 610
    const bool doFill = ( d_data->brush.style() != Qt::NoBrush )
            && ( d_data->brush.color().alpha() > 0 );
    const bool doAlign = QwtPainter::roundingAlignment( painter );
pixhawk's avatar
pixhawk committed
611

Bryant's avatar
Bryant committed
612 613 614
    QwtPointMapper mapper;
    mapper.setBoundingRect( canvasRect );
    mapper.setFlag( QwtPointMapper::RoundPoints, doAlign );
pixhawk's avatar
pixhawk committed
615

Bryant's avatar
Bryant committed
616 617 618 619 620 621 622 623
    if ( d_data->paintAttributes & FilterPoints )
    {
        if ( ( color.alpha() == 255 )
            && !( painter->renderHints() & QPainter::Antialiasing ) )
        {
            mapper.setFlag( QwtPointMapper::WeedOutPoints, true );
        }
    }
pixhawk's avatar
pixhawk committed
624

Bryant's avatar
Bryant committed
625 626 627
    if ( doFill )
    {
        mapper.setFlag( QwtPointMapper::WeedOutPoints, false );
pixhawk's avatar
pixhawk committed
628

Bryant's avatar
Bryant committed
629 630
        QPolygonF points = mapper.toPointsF( 
            xMap, yMap, data(), from, to );
pixhawk's avatar
pixhawk committed
631

Bryant's avatar
Bryant committed
632 633 634 635 636 637 638 639 640
        QwtPainter::drawPoints( painter, points );
        fillCurve( painter, xMap, yMap, canvasRect, points );
    }
    else if ( d_data->paintAttributes & ImageBuffer )
    {
        const QImage image = mapper.toImage( xMap, yMap,
            data(), from, to, d_data->pen, 
            painter->testRenderHint( QPainter::Antialiasing ),
            renderThreadCount() );
pixhawk's avatar
pixhawk committed
641

Bryant's avatar
Bryant committed
642 643 644 645 646
        painter->drawImage( canvasRect.toAlignedRect(), image );
    }
    else if ( d_data->paintAttributes & MinimizeMemory )
    {
        const QwtSeriesData<QPointF> *series = data();
pixhawk's avatar
pixhawk committed
647

Bryant's avatar
Bryant committed
648 649 650
        for ( int i = from; i <= to; i++ )
        {
            const QPointF sample = series->sample( i );
pixhawk's avatar
pixhawk committed
651

Bryant's avatar
Bryant committed
652 653
            double xi = xMap.transform( sample.x() );
            double yi = yMap.transform( sample.y() );
pixhawk's avatar
pixhawk committed
654

Bryant's avatar
Bryant committed
655 656 657 658
            if ( doAlign )
            {
                xi = qRound( xi );
                yi = qRound( yi );
pixhawk's avatar
pixhawk committed
659
            }
Bryant's avatar
Bryant committed
660 661

            QwtPainter::drawPoint( painter, QPointF( xi, yi ) );
pixhawk's avatar
pixhawk committed
662 663
        }
    }
Bryant's avatar
Bryant committed
664 665 666 667 668 669 670 671 672 673 674 675 676
    else
    {
        if ( doAlign )
        {
            const QPolygon points = mapper.toPoints(
                xMap, yMap, data(), from, to ); 

            QwtPainter::drawPoints( painter, points );
        }
        else
        {
            const QPolygonF points = mapper.toPointsF( 
                xMap, yMap, data(), from, to );
pixhawk's avatar
pixhawk committed
677

Bryant's avatar
Bryant committed
678 679
            QwtPainter::drawPoints( painter, points );
        }
pixhawk's avatar
pixhawk committed
680 681 682 683 684 685
    }
}

/*!
  Draw step function

686
  The direction of the steps depends on Inverted attribute.
pixhawk's avatar
pixhawk committed
687 688 689 690

  \param painter Painter
  \param xMap x map
  \param yMap y map
Bryant's avatar
Bryant committed
691
  \param canvasRect Contents rectangle of the canvas
pixhawk's avatar
pixhawk committed
692 693 694 695 696 697
  \param from index of the first point to be painted
  \param to index of the last point to be painted

  \sa CurveAttribute, setCurveAttribute(),
      draw(), drawCurve(), drawDots(), drawLines(), drawSticks()
*/
Bryant's avatar
Bryant committed
698 699 700
void QwtPlotCurve::drawSteps( QPainter *painter,
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    const QRectF &canvasRect, int from, int to ) const
pixhawk's avatar
pixhawk committed
701
{
Bryant's avatar
Bryant committed
702
    const bool doAlign = QwtPainter::roundingAlignment( painter );
pixhawk's avatar
pixhawk committed
703

Bryant's avatar
Bryant committed
704 705 706 707
    QPolygonF polygon( 2 * ( to - from ) + 1 );
    QPointF *points = polygon.data();

    bool inverted = orientation() == Qt::Vertical;
pixhawk's avatar
pixhawk committed
708 709 710
    if ( d_data->attributes & Inverted )
        inverted = !inverted;

Bryant's avatar
Bryant committed
711 712 713 714 715 716 717 718 719 720 721 722 723
    const QwtSeriesData<QPointF> *series = data();

    int i, ip;
    for ( i = from, ip = 0; i <= to; i++, ip += 2 )
    {
        const QPointF sample = series->sample( i );
        double xi = xMap.transform( sample.x() );
        double yi = yMap.transform( sample.y() );
        if ( doAlign )
        {
            xi = qRound( xi );
            yi = qRound( yi );
        }
pixhawk's avatar
pixhawk committed
724

Bryant's avatar
Bryant committed
725 726 727 728 729 730 731 732 733 734
        if ( ip > 0 )
        {
            const QPointF &p0 = points[ip - 2];
            QPointF &p = points[ip - 1];

            if ( inverted )
            {
                p.rx() = p0.x();
                p.ry() = yi;
            }
pixhawk's avatar
pixhawk committed
735
            else
Bryant's avatar
Bryant committed
736 737 738 739
            {
                p.rx() = xi;
                p.ry() = p0.y();
            }
pixhawk's avatar
pixhawk committed
740 741
        }

Bryant's avatar
Bryant committed
742 743
        points[ip].rx() = xi;
        points[ip].ry() = yi;
pixhawk's avatar
pixhawk committed
744 745
    }

Bryant's avatar
Bryant committed
746 747 748 749
    if ( d_data->paintAttributes & ClipPolygons )
    {
        const QPolygonF clipped = QwtClipper::clipPolygonF( 
            canvasRect, polygon, false );
pixhawk's avatar
pixhawk committed
750

Bryant's avatar
Bryant committed
751 752 753 754 755 756
        QwtPainter::drawPolyline( painter, clipped );
    }
    else
    {
        QwtPainter::drawPolyline( painter, polygon );
    }
pixhawk's avatar
pixhawk committed
757 758

    if ( d_data->brush.style() != Qt::NoBrush )
Bryant's avatar
Bryant committed
759
        fillCurve( painter, xMap, yMap, canvasRect, polygon );
pixhawk's avatar
pixhawk committed
760 761 762 763
}


/*!
Bryant's avatar
Bryant committed
764
  Specify an attribute for drawing the curve
pixhawk's avatar
pixhawk committed
765 766 767 768 769 770

  \param attribute Curve attribute
  \param on On/Off

  /sa testCurveAttribute(), setCurveFitter()
*/
Bryant's avatar
Bryant committed
771
void QwtPlotCurve::setCurveAttribute( CurveAttribute attribute, bool on )
pixhawk's avatar
pixhawk committed
772
{
Bryant's avatar
Bryant committed
773
    if ( bool( d_data->attributes & attribute ) == on )
pixhawk's avatar
pixhawk committed
774 775 776 777 778 779 780 781 782 783 784 785 786 787
        return;

    if ( on )
        d_data->attributes |= attribute;
    else
        d_data->attributes &= ~attribute;

    itemChanged();
}

/*!
    \return true, if attribute is enabled
    \sa setCurveAttribute()
*/
Bryant's avatar
Bryant committed
788
bool QwtPlotCurve::testCurveAttribute( CurveAttribute attribute ) const
789
{
pixhawk's avatar
pixhawk committed
790 791 792 793
    return d_data->attributes & attribute;
}

/*!
Bryant's avatar
Bryant committed
794
  Assign a curve fitter
pixhawk's avatar
pixhawk committed
795

Bryant's avatar
Bryant committed
796 797
  The curve fitter "smooths" the curve points, when the Fitted
  CurveAttribute is set. setCurveFitter(NULL) also disables curve fitting.
pixhawk's avatar
pixhawk committed
798

Bryant's avatar
Bryant committed
799 800 801
  The curve fitter operates on the translated points ( = widget coordinates)
  to be functional for logarithmic scales. Obviously this is less performant
  for fitting algorithms, that reduce the number of points.
pixhawk's avatar
pixhawk committed
802

Bryant's avatar
Bryant committed
803 804 805
  For situations, where curve fitting is used to improve the performance
  of painting huge series of points it might be better to execute the fitter
  on the curve points once and to cache the result in the QwtSeriesData object.
pixhawk's avatar
pixhawk committed
806

Bryant's avatar
Bryant committed
807 808
  \param curveFitter() Curve fitter
  \sa Fitted
pixhawk's avatar
pixhawk committed
809
*/
Bryant's avatar
Bryant committed
810
void QwtPlotCurve::setCurveFitter( QwtCurveFitter *curveFitter )
pixhawk's avatar
pixhawk committed
811 812 813 814 815 816 817
{
    delete d_data->curveFitter;
    d_data->curveFitter = curveFitter;

    itemChanged();
}

Bryant's avatar
Bryant committed
818 819 820 821 822 823
/*!
  Get the curve fitter. If curve fitting is disabled NULL is returned.

  \return Curve fitter
  \sa setCurveFitter(), Fitted
*/
pixhawk's avatar
pixhawk committed
824 825 826 827 828
QwtCurveFitter *QwtPlotCurve::curveFitter() const
{
    return d_data->curveFitter;
}

829 830
/*!
  Fill the area between the curve and the baseline with
pixhawk's avatar
pixhawk committed
831 832 833 834 835
  the curve brush

  \param painter Painter
  \param xMap x map
  \param yMap y map
Bryant's avatar
Bryant committed
836 837
  \param canvasRect Contents rectangle of the canvas
  \param polygon Polygon - will be modified !
pixhawk's avatar
pixhawk committed
838

Bryant's avatar
Bryant committed
839
  \sa setBrush(), setBaseline(), setStyle()
pixhawk's avatar
pixhawk committed
840
*/
Bryant's avatar
Bryant committed
841 842 843
void QwtPlotCurve::fillCurve( QPainter *painter,
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    const QRectF &canvasRect, QPolygonF &polygon ) const
pixhawk's avatar
pixhawk committed
844 845 846 847
{
    if ( d_data->brush.style() == Qt::NoBrush )
        return;

Bryant's avatar
Bryant committed
848 849
    closePolyline( painter, xMap, yMap, polygon );
    if ( polygon.count() <= 2 ) // a line can't be filled
pixhawk's avatar
pixhawk committed
850 851
        return;

Bryant's avatar
Bryant committed
852 853 854 855 856 857
    QBrush brush = d_data->brush;
    if ( !brush.color().isValid() )
        brush.setColor( d_data->pen.color() );

    if ( d_data->paintAttributes & ClipPolygons )
        polygon = QwtClipper::clipPolygonF( canvasRect, polygon, true );
pixhawk's avatar
pixhawk committed
858 859 860

    painter->save();

Bryant's avatar
Bryant committed
861 862
    painter->setPen( Qt::NoPen );
    painter->setBrush( brush );
pixhawk's avatar
pixhawk committed
863

Bryant's avatar
Bryant committed
864
    QwtPainter::drawPolygon( painter, polygon );
pixhawk's avatar
pixhawk committed
865 866 867 868 869

    painter->restore();
}

/*!
Bryant's avatar
Bryant committed
870 871 872 873
  \brief Complete a polygon to be a closed polygon including the 
         area between the original polygon and the baseline.

  \param painter Painter
pixhawk's avatar
pixhawk committed
874 875
  \param xMap X map
  \param yMap Y map
Bryant's avatar
Bryant committed
876
  \param polygon Polygon to be completed
pixhawk's avatar
pixhawk committed
877
*/
Bryant's avatar
Bryant committed
878
void QwtPlotCurve::closePolyline( QPainter *painter,
pixhawk's avatar
pixhawk committed
879
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
Bryant's avatar
Bryant committed
880
    QPolygonF &polygon ) const
pixhawk's avatar
pixhawk committed
881
{
Bryant's avatar
Bryant committed
882
    if ( polygon.size() < 2 )
pixhawk's avatar
pixhawk committed
883 884
        return;

Bryant's avatar
Bryant committed
885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911
    const bool doAlign = QwtPainter::roundingAlignment( painter );

    double baseline = d_data->baseline;
    
    if ( orientation() == Qt::Vertical )
    {
        if ( yMap.transformation() )
            baseline = yMap.transformation()->bounded( baseline );

        double refY = yMap.transform( baseline );
        if ( doAlign )
            refY = qRound( refY );

        polygon += QPointF( polygon.last().x(), refY );
        polygon += QPointF( polygon.first().x(), refY );
    }
    else
    {
        if ( xMap.transformation() )
            baseline = xMap.transformation()->bounded( baseline );

        double refX = xMap.transform( baseline );
        if ( doAlign )
            refX = qRound( refX );

        polygon += QPointF( refX, polygon.last().y() );
        polygon += QPointF( refX, polygon.first().y() );
pixhawk's avatar
pixhawk committed
912 913 914 915
    }
}

/*!
Bryant's avatar
Bryant committed
916 917
  Draw symbols

pixhawk's avatar
pixhawk committed
918 919 920 921
  \param painter Painter
  \param symbol Curve symbol
  \param xMap x map
  \param yMap y map
Bryant's avatar
Bryant committed
922 923 924
  \param canvasRect Contents rectangle of the canvas
  \param from Index of the first point to be painted
  \param to Index of the last point to be painted
pixhawk's avatar
pixhawk committed
925

Bryant's avatar
Bryant committed
926
  \sa setSymbol(), drawSeries(), drawCurve()
pixhawk's avatar
pixhawk committed
927
*/
Bryant's avatar
Bryant committed
928 929 930
void QwtPlotCurve::drawSymbols( QPainter *painter, const QwtSymbol &symbol,
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    const QRectF &canvasRect, int from, int to ) const
pixhawk's avatar
pixhawk committed
931
{
Bryant's avatar
Bryant committed
932 933 934 935 936 937
    QwtPointMapper mapper;
    mapper.setFlag( QwtPointMapper::RoundPoints, 
        QwtPainter::roundingAlignment( painter ) );
    mapper.setFlag( QwtPointMapper::WeedOutPoints, 
        testPaintAttribute( QwtPlotCurve::FilterPoints ) );
    mapper.setBoundingRect( canvasRect );
pixhawk's avatar
pixhawk committed
938

Bryant's avatar
Bryant committed
939
    const int chunkSize = 500;
pixhawk's avatar
pixhawk committed
940

Bryant's avatar
Bryant committed
941 942 943
    for ( int i = from; i <= to; i += chunkSize )
    {
        const int n = qMin( chunkSize, to - i + 1 );
pixhawk's avatar
pixhawk committed
944

Bryant's avatar
Bryant committed
945 946
        const QPolygonF points = mapper.toPointsF( xMap, yMap,
            data(), i, i + n - 1 );
pixhawk's avatar
pixhawk committed
947

Bryant's avatar
Bryant committed
948 949
        if ( points.size() > 0 )
            symbol.drawSymbols( painter, points );
pixhawk's avatar
pixhawk committed
950 951 952 953 954 955 956
    }
}

/*!
  \brief Set the value of the baseline

  The baseline is needed for filling the curve with a brush or
957
  the Sticks drawing style.
Bryant's avatar
Bryant committed
958 959 960 961 962 963 964 965 966 967

  The interpretation of the baseline depends on the orientation().
  With Qt::Horizontal, the baseline is interpreted as a horizontal line
  at y = baseline(), with Qt::Vertical, it is interpreted as a vertical
  line at x = baseline().

  The default value is 0.0.

  \param value Value of the baseline
  \sa baseline(), setBrush(), setStyle(), QwtPlotAbstractSeriesItem::orientation()
pixhawk's avatar
pixhawk committed
968
*/
Bryant's avatar
Bryant committed
969
void QwtPlotCurve::setBaseline( double value )
pixhawk's avatar
pixhawk committed
970
{
Bryant's avatar
Bryant committed
971 972 973
    if ( d_data->baseline != value )
    {
        d_data->baseline = value;
pixhawk's avatar
pixhawk committed
974 975 976 977 978
        itemChanged();
    }
}

/*!
Bryant's avatar
Bryant committed
979 980
  \return Value of the baseline
  \sa setBaseline()
pixhawk's avatar
pixhawk committed
981
*/
982 983
double QwtPlotCurve::baseline() const
{
Bryant's avatar
Bryant committed
984
    return d_data->baseline;
pixhawk's avatar
pixhawk committed
985 986 987
}

/*!
Bryant's avatar
Bryant committed
988 989 990 991 992 993 994 995 996
  Find the closest curve point for a specific position

  \param pos Position, where to look for the closest curve point
  \param dist If dist != NULL, closestPoint() returns the distance between
              the position and the closest curve point
  \return Index of the closest curve point, or -1 if none can be found
          ( f.e when the curve has no points )
  \note closestPoint() implements a dumb algorithm, that iterates
        over all points
pixhawk's avatar
pixhawk committed
997
*/
Bryant's avatar
Bryant committed
998
int QwtPlotCurve::closestPoint( const QPoint &pos, double *dist ) const
pixhawk's avatar
pixhawk committed
999
{
Bryant's avatar
Bryant committed
1000
    const size_t numSamples = dataSize();
pixhawk's avatar
pixhawk committed
1001

Bryant's avatar
Bryant committed
1002
    if ( plot() == NULL || numSamples <= 0 )
pixhawk's avatar
pixhawk committed
1003 1004
        return -1;

Bryant's avatar
Bryant committed
1005 1006 1007 1008
    const QwtSeriesData<QPointF> *series = data();

    const QwtScaleMap xMap = plot()->canvasMap( xAxis() );
    const QwtScaleMap yMap = plot()->canvasMap( yAxis() );
pixhawk's avatar
pixhawk committed
1009 1010 1011 1012

    int index = -1;
    double dmin = 1.0e10;

Bryant's avatar
Bryant committed
1013 1014 1015 1016 1017 1018
    for ( uint i = 0; i < numSamples; i++ )
    {
        const QPointF sample = series->sample( i );

        const double cx = xMap.transform( sample.x() ) - pos.x();
        const double cy = yMap.transform( sample.y() ) - pos.y();
pixhawk's avatar
pixhawk committed
1019

Bryant's avatar
Bryant committed
1020 1021 1022
        const double f = qwtSqr( cx ) + qwtSqr( cy );
        if ( f < dmin )
        {
pixhawk's avatar
pixhawk committed
1023 1024 1025 1026 1027
            index = i;
            dmin = f;
        }
    }
    if ( dist )
Bryant's avatar
Bryant committed
1028
        *dist = qSqrt( dmin );
pixhawk's avatar
pixhawk committed
1029 1030 1031 1032

    return index;
}

Bryant's avatar
Bryant committed
1033 1034
/*!
   \return Icon representing the curve on the legend
pixhawk's avatar
pixhawk committed
1035

Bryant's avatar
Bryant committed
1036 1037 1038
   \param index Index of the legend entry 
                ( ignored as there is only one )
   \param size Icon size
pixhawk's avatar
pixhawk committed
1039

Bryant's avatar
Bryant committed
1040 1041 1042 1043 1044 1045
   \sa QwtPlotItem::setLegendIconSize(), QwtPlotItem::legendData()
 */
QwtGraphic QwtPlotCurve::legendIcon( int index, 
    const QSizeF &size ) const
{
    Q_UNUSED( index );
pixhawk's avatar
pixhawk committed
1046

Bryant's avatar
Bryant committed
1047 1048
    if ( size.isEmpty() )
        return QwtGraphic();
pixhawk's avatar
pixhawk committed
1049

Bryant's avatar
Bryant committed
1050 1051 1052
    QwtGraphic graphic;
    graphic.setDefaultSize( size );
    graphic.setRenderHint( QwtGraphic::RenderPensUnscaled, true );
pixhawk's avatar
pixhawk committed
1053

Bryant's avatar
Bryant committed
1054 1055 1056
    QPainter painter( &graphic );
    painter.setRenderHint( QPainter::Antialiasing,
        testRenderHint( QwtPlotItem::RenderAntialiased ) );
pixhawk's avatar
pixhawk committed
1057

Bryant's avatar
Bryant committed
1058 1059 1060 1061
    if ( d_data->legendAttributes == 0 ||
        d_data->legendAttributes & QwtPlotCurve::LegendShowBrush )
    {
        QBrush brush = d_data->brush;
pixhawk's avatar
pixhawk committed
1062

Bryant's avatar
Bryant committed
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075
        if ( brush.style() == Qt::NoBrush &&
            d_data->legendAttributes == 0 )
        {
            if ( style() != QwtPlotCurve::NoCurve )
            {
                brush = QBrush( pen().color() );
            }
            else if ( d_data->symbol &&
                ( d_data->symbol->style() != QwtSymbol::NoSymbol ) )
            {
                brush = QBrush( d_data->symbol->pen().color() );
            }
        }
pixhawk's avatar
pixhawk committed
1076

Bryant's avatar
Bryant committed
1077 1078 1079 1080 1081 1082
        if ( brush.style() != Qt::NoBrush )
        {
            QRectF r( 0, 0, size.width(), size.height() );
            painter.fillRect( r, brush );
        }
    }
pixhawk's avatar
pixhawk committed
1083

Bryant's avatar
Bryant committed
1084 1085 1086 1087 1088 1089
    if ( d_data->legendAttributes & QwtPlotCurve::LegendShowLine )
    {
        if ( pen() != Qt::NoPen )
        {
            QPen pn = pen();
            pn.setCapStyle( Qt::FlatCap );
pixhawk's avatar
pixhawk committed
1090

Bryant's avatar
Bryant committed
1091
            painter.setPen( pn );
pixhawk's avatar
pixhawk committed
1092

Bryant's avatar
Bryant committed
1093 1094
            const double y = 0.5 * size.height();
            QwtPainter::drawLine( &painter, 0.0, y, size.width(), y );
pixhawk's avatar
pixhawk committed
1095
        }
Bryant's avatar
Bryant committed
1096 1097 1098 1099 1100 1101 1102 1103
    }

    if ( d_data->legendAttributes & QwtPlotCurve::LegendShowSymbol )
    {
        if ( d_data->symbol )
        {
            QRectF r( 0, 0, size.width(), size.height() );
            d_data->symbol->drawSymbol( &painter, r );
pixhawk's avatar
pixhawk committed
1104 1105 1106
        }
    }

Bryant's avatar
Bryant committed
1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156
    return graphic;
}

/*!
  Initialize data with an array of points.

  \param samples Vector of points
  \note QVector is implicitly shared
  \note QPolygonF is derived from QVector<QPointF>
*/
void QwtPlotCurve::setSamples( const QVector<QPointF> &samples )
{
    setData( new QwtPointSeriesData( samples ) );
}

/*!
  Assign a series of points

  setSamples() is just a wrapper for setData() without any additional
  value - beside that it is easier to find for the developer.

  \param data Data
  \warning The item takes ownership of the data object, deleting
           it when its not used anymore.
*/
void QwtPlotCurve::setSamples( QwtSeriesData<QPointF> *data )
{
    setData( data );
}

#ifndef QWT_NO_COMPAT

/*!
  \brief Initialize the data by pointing to memory blocks which 
         are not managed by QwtPlotCurve.

  setRawSamples is provided for efficiency. 
  It is important to keep the pointers
  during the lifetime of the underlying QwtCPointerData class.

  \param xData pointer to x data
  \param yData pointer to y data
  \param size size of x and y

  \sa QwtCPointerData
*/
void QwtPlotCurve::setRawSamples( 
    const double *xData, const double *yData, int size )
{
    setData( new QwtCPointerData( xData, yData, size ) );
pixhawk's avatar
pixhawk committed
1157
}
Bryant's avatar
Bryant committed
1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191

/*!
  Set data by copying x- and y-values from specified memory blocks.
  Contrary to setRawSamples(), this function makes a 'deep copy' of
  the data.

  \param xData pointer to x values
  \param yData pointer to y values
  \param size size of xData and yData

  \sa QwtPointArrayData
*/
void QwtPlotCurve::setSamples( 
    const double *xData, const double *yData, int size )
{
    setData( new QwtPointArrayData( xData, yData, size ) );
}

/*!
  \brief Initialize data with x- and y-arrays (explicitly shared)

  \param xData x data
  \param yData y data

  \sa QwtPointArrayData
*/
void QwtPlotCurve::setSamples( const QVector<double> &xData,
    const QVector<double> &yData )
{
    setData( new QwtPointArrayData( xData, yData ) );
}

#endif // !QWT_NO_COMPAT