qwt_plot_curve.cpp
Go to the documentation of this file.
00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
00002  * Qwt Widget Library
00003  * Copyright (C) 1997   Josef Wilgen
00004  * Copyright (C) 2002   Uwe Rathmann
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the Qwt License, Version 1.0
00008  *****************************************************************************/
00009 
00010 #include "qwt_plot_curve.h"
00011 #include "qwt_point_data.h"
00012 #include "qwt_math.h"
00013 #include "qwt_clipper.h"
00014 #include "qwt_painter.h"
00015 #include "qwt_scale_map.h"
00016 #include "qwt_plot.h"
00017 #include "qwt_spline_curve_fitter.h"
00018 #include "qwt_symbol.h"
00019 #include "qwt_point_mapper.h"
00020 #include <qpainter.h>
00021 #include <qpixmap.h>
00022 #include <qalgorithms.h>
00023 #include <qmath.h>
00024 
00025 static inline QRectF qwtIntersectedClipRect( const QRectF &rect, QPainter *painter )
00026 {
00027     QRectF clipRect = rect;
00028     if ( painter->hasClipping() )
00029     {
00030 #if QT_VERSION >= 0x040800
00031         const QRectF r = painter->clipBoundingRect();
00032 #else
00033         const QRectF r = painter->clipRegion().boundingRect();
00034 #endif
00035         clipRect &= r;
00036     }
00037 
00038     return clipRect;
00039 }
00040 
00041 static void qwtUpdateLegendIconSize( QwtPlotCurve *curve )
00042 {
00043     if ( curve->symbol() && 
00044         curve->testLegendAttribute( QwtPlotCurve::LegendShowSymbol ) )
00045     {
00046         QSize sz = curve->symbol()->boundingRect().size();
00047         sz += QSize( 2, 2 ); // margin
00048 
00049         if ( curve->testLegendAttribute( QwtPlotCurve::LegendShowLine ) )
00050         {
00051             // Avoid, that the line is completely covered by the symbol
00052 
00053             int w = qCeil( 1.5 * sz.width() );
00054             if ( w % 2 )
00055                 w++;
00056 
00057             sz.setWidth( qMax( 8, w ) );
00058         }
00059 
00060         curve->setLegendIconSize( sz );
00061     }
00062 }
00063 
00064 static int qwtVerifyRange( int size, int &i1, int &i2 )
00065 {
00066     if ( size < 1 )
00067         return 0;
00068 
00069     i1 = qBound( 0, i1, size - 1 );
00070     i2 = qBound( 0, i2, size - 1 );
00071 
00072     if ( i1 > i2 )
00073         qSwap( i1, i2 );
00074 
00075     return ( i2 - i1 + 1 );
00076 }
00077 
00078 class QwtPlotCurve::PrivateData
00079 {
00080 public:
00081     PrivateData():
00082         style( QwtPlotCurve::Lines ),
00083         baseline( 0.0 ),
00084         symbol( NULL ),
00085         pen( Qt::black ),
00086         attributes( 0 ),
00087         paintAttributes( 
00088             QwtPlotCurve::ClipPolygons | QwtPlotCurve::FilterPoints ),
00089         legendAttributes( 0 )
00090     {
00091         curveFitter = new QwtSplineCurveFitter;
00092     }
00093 
00094     ~PrivateData()
00095     {
00096         delete symbol;
00097         delete curveFitter;
00098     }
00099 
00100     QwtPlotCurve::CurveStyle style;
00101     double baseline;
00102 
00103     const QwtSymbol *symbol;
00104     QwtCurveFitter *curveFitter;
00105 
00106     QPen pen;
00107     QBrush brush;
00108 
00109     QwtPlotCurve::CurveAttributes attributes;
00110     QwtPlotCurve::PaintAttributes paintAttributes;
00111 
00112     QwtPlotCurve::LegendAttributes legendAttributes;
00113 };
00114 
00119 QwtPlotCurve::QwtPlotCurve( const QwtText &title ):
00120     QwtPlotSeriesItem( title )
00121 {
00122     init();
00123 }
00124 
00129 QwtPlotCurve::QwtPlotCurve( const QString &title ):
00130     QwtPlotSeriesItem( QwtText( title ) )
00131 {
00132     init();
00133 }
00134 
00136 QwtPlotCurve::~QwtPlotCurve()
00137 {
00138     delete d_data;
00139 }
00140 
00142 void QwtPlotCurve::init()
00143 {
00144     setItemAttribute( QwtPlotItem::Legend );
00145     setItemAttribute( QwtPlotItem::AutoScale );
00146 
00147     d_data = new PrivateData;
00148     setData( new QwtPointSeriesData() );
00149 
00150     setZ( 20.0 );
00151 }
00152 
00154 int QwtPlotCurve::rtti() const
00155 {
00156     return QwtPlotItem::Rtti_PlotCurve;
00157 }
00158 
00166 void QwtPlotCurve::setPaintAttribute( PaintAttribute attribute, bool on )
00167 {
00168     if ( on )
00169         d_data->paintAttributes |= attribute;
00170     else
00171         d_data->paintAttributes &= ~attribute;
00172 }
00173 
00178 bool QwtPlotCurve::testPaintAttribute( PaintAttribute attribute ) const
00179 {
00180     return ( d_data->paintAttributes & attribute );
00181 }
00182 
00190 void QwtPlotCurve::setLegendAttribute( LegendAttribute attribute, bool on )
00191 {
00192     if ( on != testLegendAttribute( attribute ) )
00193     {
00194         if ( on )
00195             d_data->legendAttributes |= attribute;
00196         else
00197             d_data->legendAttributes &= ~attribute;
00198 
00199         qwtUpdateLegendIconSize( this );
00200         legendChanged();
00201     }
00202 }
00203 
00208 bool QwtPlotCurve::testLegendAttribute( LegendAttribute attribute ) const
00209 {
00210     return ( d_data->legendAttributes & attribute );
00211 }
00212 
00219 void QwtPlotCurve::setStyle( CurveStyle style )
00220 {
00221     if ( style != d_data->style )
00222     {
00223         d_data->style = style;
00224 
00225         legendChanged();
00226         itemChanged();
00227     }
00228 }
00229 
00234 QwtPlotCurve::CurveStyle QwtPlotCurve::style() const
00235 {
00236     return d_data->style;
00237 }
00238 
00249 void QwtPlotCurve::setSymbol( QwtSymbol *symbol )
00250 {
00251     if ( symbol != d_data->symbol )
00252     {
00253         delete d_data->symbol;
00254         d_data->symbol = symbol;
00255 
00256         qwtUpdateLegendIconSize( this );
00257 
00258         legendChanged();
00259         itemChanged();
00260     }
00261 }
00262 
00267 const QwtSymbol *QwtPlotCurve::symbol() const
00268 {
00269     return d_data->symbol;
00270 }
00271 
00285 void QwtPlotCurve::setPen( const QColor &color, qreal width, Qt::PenStyle style )
00286 {
00287     setPen( QPen( color, width, style ) );
00288 }
00289 
00296 void QwtPlotCurve::setPen( const QPen &pen )
00297 {
00298     if ( pen != d_data->pen )
00299     {
00300         d_data->pen = pen;
00301 
00302         legendChanged();
00303         itemChanged();
00304     }
00305 }
00306 
00311 const QPen& QwtPlotCurve::pen() const
00312 {
00313     return d_data->pen;
00314 }
00315 
00331 void QwtPlotCurve::setBrush( const QBrush &brush )
00332 {
00333     if ( brush != d_data->brush )
00334     {
00335         d_data->brush = brush;
00336 
00337         legendChanged();
00338         itemChanged();
00339     }
00340 }
00341 
00346 const QBrush& QwtPlotCurve::brush() const
00347 {
00348     return d_data->brush;
00349 }
00350 
00364 void QwtPlotCurve::drawSeries( QPainter *painter,
00365     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00366     const QRectF &canvasRect, int from, int to ) const
00367 {
00368     const size_t numSamples = dataSize();
00369 
00370     if ( !painter || numSamples <= 0 )
00371         return;
00372 
00373     if ( to < 0 )
00374         to = numSamples - 1;
00375 
00376     if ( qwtVerifyRange( numSamples, from, to ) > 0 )
00377     {
00378         painter->save();
00379         painter->setPen( d_data->pen );
00380 
00381         /*
00382           Qt 4.0.0 is slow when drawing lines, but it's even
00383           slower when the painter has a brush. So we don't
00384           set the brush before we really need it.
00385          */
00386 
00387         drawCurve( painter, d_data->style, xMap, yMap, canvasRect, from, to );
00388         painter->restore();
00389 
00390         if ( d_data->symbol &&
00391             ( d_data->symbol->style() != QwtSymbol::NoSymbol ) )
00392         {
00393             painter->save();
00394             drawSymbols( painter, *d_data->symbol,
00395                 xMap, yMap, canvasRect, from, to );
00396             painter->restore();
00397         }
00398     }
00399 }
00400 
00412 void QwtPlotCurve::drawCurve( QPainter *painter, int style,
00413     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00414     const QRectF &canvasRect, int from, int to ) const
00415 {
00416     switch ( style )
00417     {
00418         case Lines:
00419             if ( testCurveAttribute( Fitted ) )
00420             {
00421                 // we always need the complete
00422                 // curve for fitting
00423                 from = 0;
00424                 to = dataSize() - 1;
00425             }
00426             drawLines( painter, xMap, yMap, canvasRect, from, to );
00427             break;
00428         case Sticks:
00429             drawSticks( painter, xMap, yMap, canvasRect, from, to );
00430             break;
00431         case Steps:
00432             drawSteps( painter, xMap, yMap, canvasRect, from, to );
00433             break;
00434         case Dots:
00435             drawDots( painter, xMap, yMap, canvasRect, from, to );
00436             break;
00437         case LinesAndDots:
00438         {
00439             if ( testCurveAttribute( Fitted ) )
00440             {
00441                 from = 0;
00442                 to = dataSize() - 1;
00443             }
00444             drawLines( painter, xMap, yMap, canvasRect, from, to );
00445 
00446             QPen prev_pen = painter->pen();
00447             QPen new_pen  = prev_pen;
00448             new_pen.setWidth( prev_pen.width() * 3);
00449 
00450             painter->setPen( new_pen );
00451             drawDots( painter, xMap, yMap, canvasRect, from, to );
00452             painter->setPen( prev_pen );
00453         }
00454         break;
00455         case NoCurve:
00456         default:
00457             break;
00458     }
00459 }
00460 
00477 void QwtPlotCurve::drawLines( QPainter *painter,
00478     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00479     const QRectF &canvasRect, int from, int to ) const
00480 {
00481     if ( from > to )
00482         return;
00483 
00484     const bool doFit = ( d_data->attributes & Fitted ) && d_data->curveFitter;
00485     const bool doAlign = !doFit && QwtPainter::roundingAlignment( painter );
00486     const bool doFill = ( d_data->brush.style() != Qt::NoBrush )
00487             && ( d_data->brush.color().alpha() > 0 );
00488 
00489     QRectF clipRect;
00490     if ( d_data->paintAttributes & ClipPolygons )
00491     {
00492         clipRect = qwtIntersectedClipRect( canvasRect, painter );
00493 
00494         const qreal pw = qMax( qreal( 1.0 ), painter->pen().widthF());
00495         clipRect = clipRect.adjusted(-pw, -pw, pw, pw);
00496     }
00497 
00498     bool doIntegers = false;
00499 
00500 #if QT_VERSION < 0x040800
00501     if ( painter->paintEngine()->type() == QPaintEngine::Raster )
00502     {
00503 
00504         // For Qt <= 4.7 the raster paint engine is significantly faster
00505         // for rendering QPolygon than for QPolygonF. So let's
00506         // see if we can use it.
00507 
00508         // In case of filling or fitting performance doesn't count
00509         // because both operations are much more expensive
00510         // then drawing the polyline itself
00511 
00512         if ( !doFit && !doFill )
00513             doIntegers = true; 
00514     }
00515 #endif
00516 
00517     QwtPointMapper mapper;
00518 
00519     if ( doAlign )
00520     {
00521         mapper.setFlag( QwtPointMapper::RoundPoints, true );
00522         mapper.setFlag( QwtPointMapper::WeedOutIntermediatePoints, 
00523             testPaintAttribute( FilterPointsAggressive ) );
00524     }
00525 
00526     mapper.setFlag( QwtPointMapper::WeedOutPoints, 
00527         testPaintAttribute( FilterPoints ) || 
00528         testPaintAttribute( FilterPointsAggressive ) );
00529 
00530     mapper.setBoundingRect( canvasRect );
00531 
00532     if ( doIntegers )
00533     {
00534         QPolygon polyline = mapper.toPolygon( 
00535             xMap, yMap, data(), from, to );
00536 
00537         if ( testPaintAttribute( ClipPolygons ) )
00538         {
00539             QwtClipper::clipPolygon( clipRect, polyline, false );
00540         }
00541 
00542         QwtPainter::drawPolyline( painter, polyline );
00543     }
00544     else
00545     {
00546         QPolygonF polyline = mapper.toPolygonF( xMap, yMap, data(), from, to );
00547 
00548         if ( doFill )
00549         {
00550             if ( doFit )
00551             {
00552                 // it might be better to extend and draw the curvePath, but for 
00553                 // the moment we keep an implementation, where we translate the
00554                 // path back to a polyline.
00555 
00556                 polyline = d_data->curveFitter->fitCurve( polyline );
00557             }
00558 
00559             if ( painter->pen().style() != Qt::NoPen )
00560             {
00561                 // here we are wasting memory for the filled copy,
00562                 // do polygon clipping twice etc .. TODO
00563 
00564                 QPolygonF filled = polyline;
00565                 fillCurve( painter, xMap, yMap, canvasRect, filled );
00566                 filled.clear();
00567 
00568                 if ( d_data->paintAttributes & ClipPolygons )
00569                     QwtClipper::clipPolygonF( clipRect, polyline, false );
00570 
00571                 QwtPainter::drawPolyline( painter, polyline );
00572             }
00573             else
00574             {
00575                 fillCurve( painter, xMap, yMap, canvasRect, polyline );
00576             }
00577         }
00578         else
00579         {
00580             if ( testPaintAttribute( ClipPolygons ) )
00581             {
00582                 QwtClipper::clipPolygonF( clipRect, polyline, false );
00583             }
00584 
00585             if ( doFit )
00586             {
00587                 if ( d_data->curveFitter->mode() == QwtCurveFitter::Path )
00588                 {
00589                     const QPainterPath curvePath = 
00590                         d_data->curveFitter->fitCurvePath( polyline );
00591 
00592                     painter->drawPath( curvePath );
00593                 }
00594                 else
00595                 {
00596                     polyline = d_data->curveFitter->fitCurve( polyline );
00597                     QwtPainter::drawPolyline( painter, polyline );
00598                 }
00599             }
00600             else
00601             {
00602                 QwtPainter::drawPolyline( painter, polyline );
00603             }
00604         }
00605     }
00606 }
00607 
00620 void QwtPlotCurve::drawSticks( QPainter *painter,
00621     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00622     const QRectF &, int from, int to ) const
00623 {
00624     painter->save();
00625     painter->setRenderHint( QPainter::Antialiasing, false );
00626 
00627     const bool doAlign = QwtPainter::roundingAlignment( painter );
00628 
00629     double x0 = xMap.transform( d_data->baseline );
00630     double y0 = yMap.transform( d_data->baseline );
00631     if ( doAlign )
00632     {
00633         x0 = qRound( x0 );
00634         y0 = qRound( y0 );
00635     }
00636 
00637     const Qt::Orientation o = orientation();
00638 
00639     const QwtSeriesData<QPointF> *series = data();
00640 
00641     for ( int i = from; i <= to; i++ )
00642     {
00643         const QPointF sample = series->sample( i );
00644         double xi = xMap.transform( sample.x() );
00645         double yi = yMap.transform( sample.y() );
00646         if ( doAlign )
00647         {
00648             xi = qRound( xi );
00649             yi = qRound( yi );
00650         }
00651 
00652         if ( o == Qt::Horizontal )
00653             QwtPainter::drawLine( painter, x0, yi, xi, yi );
00654         else
00655             QwtPainter::drawLine( painter, xi, y0, xi, yi );
00656     }
00657 
00658     painter->restore();
00659 }
00660 
00673 void QwtPlotCurve::drawDots( QPainter *painter,
00674     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00675     const QRectF &canvasRect, int from, int to ) const
00676 {
00677     const QColor color = painter->pen().color();
00678 
00679     if ( painter->pen().style() == Qt::NoPen || color.alpha() == 0 )
00680     {
00681         return;
00682     }
00683 
00684     const bool doFill = ( d_data->brush.style() != Qt::NoBrush )
00685             && ( d_data->brush.color().alpha() > 0 );
00686     const bool doAlign = QwtPainter::roundingAlignment( painter );
00687 
00688     QwtPointMapper mapper;
00689     mapper.setBoundingRect( canvasRect );
00690     mapper.setFlag( QwtPointMapper::RoundPoints, doAlign );
00691 
00692     if ( d_data->paintAttributes & FilterPoints )
00693     {
00694         if ( ( color.alpha() == 255 )
00695             && !( painter->renderHints() & QPainter::Antialiasing ) )
00696         {
00697             mapper.setFlag( QwtPointMapper::WeedOutPoints, true );
00698         }
00699     }
00700 
00701     if ( doFill )
00702     {
00703         mapper.setFlag( QwtPointMapper::WeedOutPoints, false );
00704 
00705         QPolygonF points = mapper.toPointsF( 
00706             xMap, yMap, data(), from, to );
00707 
00708         QwtPainter::drawPoints( painter, points );
00709         fillCurve( painter, xMap, yMap, canvasRect, points );
00710     }
00711     else if ( d_data->paintAttributes & ImageBuffer )
00712     {
00713         const QImage image = mapper.toImage( xMap, yMap,
00714             data(), from, to, d_data->pen, 
00715             painter->testRenderHint( QPainter::Antialiasing ),
00716             renderThreadCount() );
00717 
00718         painter->drawImage( canvasRect.toAlignedRect(), image );
00719     }
00720     else if ( d_data->paintAttributes & MinimizeMemory )
00721     {
00722         const QwtSeriesData<QPointF> *series = data();
00723 
00724         for ( int i = from; i <= to; i++ )
00725         {
00726             const QPointF sample = series->sample( i );
00727 
00728             double xi = xMap.transform( sample.x() );
00729             double yi = yMap.transform( sample.y() );
00730 
00731             if ( doAlign )
00732             {
00733                 xi = qRound( xi );
00734                 yi = qRound( yi );
00735             }
00736 
00737             QwtPainter::drawPoint( painter, QPointF( xi, yi ) );
00738         }
00739     }
00740     else
00741     {
00742         if ( doAlign )
00743         {
00744             const QPolygon points = mapper.toPoints(
00745                 xMap, yMap, data(), from, to ); 
00746 
00747             QwtPainter::drawPoints( painter, points );
00748         }
00749         else
00750         {
00751             const QPolygonF points = mapper.toPointsF( 
00752                 xMap, yMap, data(), from, to );
00753 
00754             QwtPainter::drawPoints( painter, points );
00755         }
00756     }
00757 }
00758 
00774 void QwtPlotCurve::drawSteps( QPainter *painter,
00775     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00776     const QRectF &canvasRect, int from, int to ) const
00777 {
00778     const bool doAlign = QwtPainter::roundingAlignment( painter );
00779 
00780     QPolygonF polygon( 2 * ( to - from ) + 1 );
00781     QPointF *points = polygon.data();
00782 
00783     bool inverted = orientation() == Qt::Vertical;
00784     if ( d_data->attributes & Inverted )
00785         inverted = !inverted;
00786 
00787     const QwtSeriesData<QPointF> *series = data();
00788 
00789     int i, ip;
00790     for ( i = from, ip = 0; i <= to; i++, ip += 2 )
00791     {
00792         const QPointF sample = series->sample( i );
00793         double xi = xMap.transform( sample.x() );
00794         double yi = yMap.transform( sample.y() );
00795         if ( doAlign )
00796         {
00797             xi = qRound( xi );
00798             yi = qRound( yi );
00799         }
00800 
00801         if ( ip > 0 )
00802         {
00803             const QPointF &p0 = points[ip - 2];
00804             QPointF &p = points[ip - 1];
00805 
00806             if ( inverted )
00807             {
00808                 p.rx() = p0.x();
00809                 p.ry() = yi;
00810             }
00811             else
00812             {
00813                 p.rx() = xi;
00814                 p.ry() = p0.y();
00815             }
00816         }
00817 
00818         points[ip].rx() = xi;
00819         points[ip].ry() = yi;
00820     }
00821 
00822     if ( d_data->paintAttributes & ClipPolygons )
00823     {
00824         QRectF clipRect = qwtIntersectedClipRect( canvasRect, painter );
00825 
00826         const qreal pw = qMax( qreal( 1.0 ), painter->pen().widthF());
00827         clipRect = clipRect.adjusted(-pw, -pw, pw, pw);
00828 
00829         const QPolygonF clipped = QwtClipper::clippedPolygonF( 
00830             clipRect, polygon, false );
00831 
00832         QwtPainter::drawPolyline( painter, clipped );
00833     }
00834     else
00835     {
00836         QwtPainter::drawPolyline( painter, polygon );
00837     }
00838 
00839     if ( d_data->brush.style() != Qt::NoBrush )
00840         fillCurve( painter, xMap, yMap, canvasRect, polygon );
00841 }
00842 
00843 
00852 void QwtPlotCurve::setCurveAttribute( CurveAttribute attribute, bool on )
00853 {
00854     if ( bool( d_data->attributes & attribute ) == on )
00855         return;
00856 
00857     if ( on )
00858         d_data->attributes |= attribute;
00859     else
00860         d_data->attributes &= ~attribute;
00861 
00862     itemChanged();
00863 }
00864 
00869 bool QwtPlotCurve::testCurveAttribute( CurveAttribute attribute ) const
00870 {
00871     return d_data->attributes & attribute;
00872 }
00873 
00891 void QwtPlotCurve::setCurveFitter( QwtCurveFitter *curveFitter )
00892 {
00893     delete d_data->curveFitter;
00894     d_data->curveFitter = curveFitter;
00895 
00896     itemChanged();
00897 }
00898 
00905 QwtCurveFitter *QwtPlotCurve::curveFitter() const
00906 {
00907     return d_data->curveFitter;
00908 }
00909 
00922 void QwtPlotCurve::fillCurve( QPainter *painter,
00923     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00924     const QRectF &canvasRect, QPolygonF &polygon ) const
00925 {
00926     if ( d_data->brush.style() == Qt::NoBrush )
00927         return;
00928 
00929     closePolyline( painter, xMap, yMap, polygon );
00930     if ( polygon.count() <= 2 ) // a line can't be filled
00931         return;
00932 
00933     QBrush brush = d_data->brush;
00934     if ( !brush.color().isValid() )
00935         brush.setColor( d_data->pen.color() );
00936 
00937     if ( d_data->paintAttributes & ClipPolygons )
00938     {
00939         const QRectF clipRect = qwtIntersectedClipRect( canvasRect, painter );
00940         QwtClipper::clipPolygonF( clipRect, polygon, true );
00941     }
00942 
00943     painter->save();
00944 
00945     painter->setPen( Qt::NoPen );
00946     painter->setBrush( brush );
00947 
00948     QwtPainter::drawPolygon( painter, polygon );
00949 
00950     painter->restore();
00951 }
00952 
00962 void QwtPlotCurve::closePolyline( QPainter *painter,
00963     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00964     QPolygonF &polygon ) const
00965 {
00966     if ( polygon.size() < 2 )
00967         return;
00968 
00969     const bool doAlign = QwtPainter::roundingAlignment( painter );
00970 
00971     double baseline = d_data->baseline;
00972     
00973     if ( orientation() == Qt::Vertical )
00974     {
00975         if ( yMap.transformation() )
00976             baseline = yMap.transformation()->bounded( baseline );
00977 
00978         double refY = yMap.transform( baseline );
00979         if ( doAlign )
00980             refY = qRound( refY );
00981 
00982         polygon += QPointF( polygon.last().x(), refY );
00983         polygon += QPointF( polygon.first().x(), refY );
00984     }
00985     else
00986     {
00987         if ( xMap.transformation() )
00988             baseline = xMap.transformation()->bounded( baseline );
00989 
00990         double refX = xMap.transform( baseline );
00991         if ( doAlign )
00992             refX = qRound( refX );
00993 
00994         polygon += QPointF( refX, polygon.last().y() );
00995         polygon += QPointF( refX, polygon.first().y() );
00996     }
00997 }
00998 
01012 void QwtPlotCurve::drawSymbols( QPainter *painter, const QwtSymbol &symbol,
01013     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
01014     const QRectF &canvasRect, int from, int to ) const
01015 {
01016     QwtPointMapper mapper;
01017     mapper.setFlag( QwtPointMapper::RoundPoints, 
01018         QwtPainter::roundingAlignment( painter ) );
01019     mapper.setFlag( QwtPointMapper::WeedOutPoints, 
01020         testPaintAttribute( QwtPlotCurve::FilterPoints ) );
01021 
01022     const QRectF clipRect = qwtIntersectedClipRect( canvasRect, painter );
01023     mapper.setBoundingRect( clipRect );
01024 
01025     const int chunkSize = 500;
01026 
01027     for ( int i = from; i <= to; i += chunkSize )
01028     {
01029         const int n = qMin( chunkSize, to - i + 1 );
01030 
01031         const QPolygonF points = mapper.toPointsF( xMap, yMap,
01032             data(), i, i + n - 1 );
01033 
01034         if ( points.size() > 0 )
01035             symbol.drawSymbols( painter, points );
01036     }
01037 }
01038 
01055 void QwtPlotCurve::setBaseline( double value )
01056 {
01057     if ( d_data->baseline != value )
01058     {
01059         d_data->baseline = value;
01060         itemChanged();
01061     }
01062 }
01063 
01068 double QwtPlotCurve::baseline() const
01069 {
01070     return d_data->baseline;
01071 }
01072 
01084 int QwtPlotCurve::closestPoint( const QPoint &pos, double *dist ) const
01085 {
01086     const size_t numSamples = dataSize();
01087 
01088     if ( plot() == NULL || numSamples <= 0 )
01089         return -1;
01090 
01091     const QwtSeriesData<QPointF> *series = data();
01092 
01093     const QwtScaleMap xMap = plot()->canvasMap( xAxis() );
01094     const QwtScaleMap yMap = plot()->canvasMap( yAxis() );
01095 
01096     int index = -1;
01097     double dmin = 1.0e10;
01098 
01099     for ( uint i = 0; i < numSamples; i++ )
01100     {
01101         const QPointF sample = series->sample( i );
01102 
01103         const double cx = xMap.transform( sample.x() ) - pos.x();
01104         const double cy = yMap.transform( sample.y() ) - pos.y();
01105 
01106         const double f = qwtSqr( cx ) + qwtSqr( cy );
01107         if ( f < dmin )
01108         {
01109             index = i;
01110             dmin = f;
01111         }
01112     }
01113     if ( dist )
01114         *dist = qSqrt( dmin );
01115 
01116     return index;
01117 }
01118 
01128 QwtGraphic QwtPlotCurve::legendIcon( int index, 
01129     const QSizeF &size ) const
01130 {
01131     Q_UNUSED( index );
01132 
01133     if ( size.isEmpty() )
01134         return QwtGraphic();
01135 
01136     QwtGraphic graphic;
01137     graphic.setDefaultSize( size );
01138     graphic.setRenderHint( QwtGraphic::RenderPensUnscaled, true );
01139 
01140     QPainter painter( &graphic );
01141     painter.setRenderHint( QPainter::Antialiasing,
01142         testRenderHint( QwtPlotItem::RenderAntialiased ) );
01143 
01144     if ( d_data->legendAttributes == 0 ||
01145         d_data->legendAttributes & QwtPlotCurve::LegendShowBrush )
01146     {
01147         QBrush brush = d_data->brush;
01148 
01149         if ( brush.style() == Qt::NoBrush &&
01150             d_data->legendAttributes == 0 )
01151         {
01152             if ( style() != QwtPlotCurve::NoCurve )
01153             {
01154                 brush = QBrush( pen().color() );
01155             }
01156             else if ( d_data->symbol &&
01157                 ( d_data->symbol->style() != QwtSymbol::NoSymbol ) )
01158             {
01159                 brush = QBrush( d_data->symbol->pen().color() );
01160             }
01161         }
01162 
01163         if ( brush.style() != Qt::NoBrush )
01164         {
01165             QRectF r( 0, 0, size.width(), size.height() );
01166             painter.fillRect( r, brush );
01167         }
01168     }
01169 
01170     if ( d_data->legendAttributes & QwtPlotCurve::LegendShowLine )
01171     {
01172         if ( pen() != Qt::NoPen )
01173         {
01174             QPen pn = pen();
01175             pn.setCapStyle( Qt::FlatCap );
01176 
01177             painter.setPen( pn );
01178 
01179             const double y = 0.5 * size.height();
01180             QwtPainter::drawLine( &painter, 0.0, y, size.width(), y );
01181         }
01182     }
01183 
01184     if ( d_data->legendAttributes & QwtPlotCurve::LegendShowSymbol )
01185     {
01186         if ( d_data->symbol )
01187         {
01188             QRectF r( 0, 0, size.width(), size.height() );
01189             d_data->symbol->drawSymbol( &painter, r );
01190         }
01191     }
01192 
01193     return graphic;
01194 }
01195 
01203 void QwtPlotCurve::setSamples( const QVector<QPointF> &samples )
01204 {
01205     setData( new QwtPointSeriesData( samples ) );
01206 }
01207 
01218 void QwtPlotCurve::setSamples( QwtSeriesData<QPointF> *data )
01219 {
01220     setData( data );
01221 }
01222 
01223 #ifndef QWT_NO_COMPAT
01224 
01239 void QwtPlotCurve::setRawSamples( 
01240     const double *xData, const double *yData, int size )
01241 {
01242     setData( new QwtCPointerData( xData, yData, size ) );
01243 }
01244 
01256 void QwtPlotCurve::setSamples( 
01257     const double *xData, const double *yData, int size )
01258 {
01259     setData( new QwtPointArrayData( xData, yData, size ) );
01260 }
01261 
01270 void QwtPlotCurve::setSamples( const QVector<double> &xData,
01271     const QVector<double> &yData )
01272 {
01273     setData( new QwtPointArrayData( xData, yData ) );
01274 }
01275 
01276 #endif // !QWT_NO_COMPAT
01277 


plotjuggler
Author(s): Davide Faconti
autogenerated on Wed Jul 3 2019 19:28:05