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             polyline = QwtClipper::clipPolygon( 
00540                 clipRect.toAlignedRect(), polyline, false );
00541         }
00542 
00543         QwtPainter::drawPolyline( painter, polyline );
00544     }
00545     else
00546     {
00547         QPolygonF polyline = mapper.toPolygonF( xMap, yMap, data(), from, to );
00548 
00549         if ( doFill )
00550         {
00551             if ( doFit )
00552             {
00553                 // it might be better to extend and draw the curvePath, but for 
00554                 // the moment we keep an implementation, where we translate the
00555                 // path back to a polyline.
00556 
00557                 polyline = d_data->curveFitter->fitCurve( polyline );
00558             }
00559 
00560             if ( painter->pen().style() != Qt::NoPen )
00561             {
00562                 // here we are wasting memory for the filled copy,
00563                 // do polygon clipping twice etc .. TODO
00564 
00565                 QPolygonF filled = polyline;
00566                 fillCurve( painter, xMap, yMap, canvasRect, filled );
00567                 filled.clear();
00568 
00569                 if ( d_data->paintAttributes & ClipPolygons )
00570                     polyline = QwtClipper::clipPolygonF( clipRect, polyline, false );
00571 
00572                 QwtPainter::drawPolyline( painter, polyline );
00573             }
00574             else
00575             {
00576                 fillCurve( painter, xMap, yMap, canvasRect, polyline );
00577             }
00578         }
00579         else
00580         {
00581             if ( testPaintAttribute( ClipPolygons ) )
00582             {
00583                 polyline = QwtClipper::clipPolygonF(
00584                     clipRect, polyline, false );
00585             }
00586 
00587             if ( doFit )
00588             {
00589                 if ( d_data->curveFitter->mode() == QwtCurveFitter::Path )
00590                 {
00591                     const QPainterPath curvePath = 
00592                         d_data->curveFitter->fitCurvePath( polyline );
00593 
00594                     painter->drawPath( curvePath );
00595                 }
00596                 else
00597                 {
00598                     polyline = d_data->curveFitter->fitCurve( polyline );
00599                     QwtPainter::drawPolyline( painter, polyline );
00600                 }
00601             }
00602             else
00603             {
00604                 QwtPainter::drawPolyline( painter, polyline );
00605             }
00606         }
00607     }
00608 }
00609 
00622 void QwtPlotCurve::drawSticks( QPainter *painter,
00623     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00624     const QRectF &, int from, int to ) const
00625 {
00626     painter->save();
00627     painter->setRenderHint( QPainter::Antialiasing, false );
00628 
00629     const bool doAlign = QwtPainter::roundingAlignment( painter );
00630 
00631     double x0 = xMap.transform( d_data->baseline );
00632     double y0 = yMap.transform( d_data->baseline );
00633     if ( doAlign )
00634     {
00635         x0 = qRound( x0 );
00636         y0 = qRound( y0 );
00637     }
00638 
00639     const Qt::Orientation o = orientation();
00640 
00641     const QwtSeriesData<QPointF> *series = data();
00642 
00643     for ( int i = from; i <= to; i++ )
00644     {
00645         const QPointF sample = series->sample( i );
00646         double xi = xMap.transform( sample.x() );
00647         double yi = yMap.transform( sample.y() );
00648         if ( doAlign )
00649         {
00650             xi = qRound( xi );
00651             yi = qRound( yi );
00652         }
00653 
00654         if ( o == Qt::Horizontal )
00655             QwtPainter::drawLine( painter, x0, yi, xi, yi );
00656         else
00657             QwtPainter::drawLine( painter, xi, y0, xi, yi );
00658     }
00659 
00660     painter->restore();
00661 }
00662 
00675 void QwtPlotCurve::drawDots( QPainter *painter,
00676     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00677     const QRectF &canvasRect, int from, int to ) const
00678 {
00679     const QColor color = painter->pen().color();
00680 
00681     if ( painter->pen().style() == Qt::NoPen || color.alpha() == 0 )
00682     {
00683         return;
00684     }
00685 
00686     const bool doFill = ( d_data->brush.style() != Qt::NoBrush )
00687             && ( d_data->brush.color().alpha() > 0 );
00688     const bool doAlign = QwtPainter::roundingAlignment( painter );
00689 
00690     QwtPointMapper mapper;
00691     mapper.setBoundingRect( canvasRect );
00692     mapper.setFlag( QwtPointMapper::RoundPoints, doAlign );
00693 
00694     if ( d_data->paintAttributes & FilterPoints )
00695     {
00696         if ( ( color.alpha() == 255 )
00697             && !( painter->renderHints() & QPainter::Antialiasing ) )
00698         {
00699             mapper.setFlag( QwtPointMapper::WeedOutPoints, true );
00700         }
00701     }
00702 
00703     if ( doFill )
00704     {
00705         mapper.setFlag( QwtPointMapper::WeedOutPoints, false );
00706 
00707         QPolygonF points = mapper.toPointsF( 
00708             xMap, yMap, data(), from, to );
00709 
00710         QwtPainter::drawPoints( painter, points );
00711         fillCurve( painter, xMap, yMap, canvasRect, points );
00712     }
00713     else if ( d_data->paintAttributes & ImageBuffer )
00714     {
00715         const QImage image = mapper.toImage( xMap, yMap,
00716             data(), from, to, d_data->pen, 
00717             painter->testRenderHint( QPainter::Antialiasing ),
00718             renderThreadCount() );
00719 
00720         painter->drawImage( canvasRect.toAlignedRect(), image );
00721     }
00722     else if ( d_data->paintAttributes & MinimizeMemory )
00723     {
00724         const QwtSeriesData<QPointF> *series = data();
00725 
00726         for ( int i = from; i <= to; i++ )
00727         {
00728             const QPointF sample = series->sample( i );
00729 
00730             double xi = xMap.transform( sample.x() );
00731             double yi = yMap.transform( sample.y() );
00732 
00733             if ( doAlign )
00734             {
00735                 xi = qRound( xi );
00736                 yi = qRound( yi );
00737             }
00738 
00739             QwtPainter::drawPoint( painter, QPointF( xi, yi ) );
00740         }
00741     }
00742     else
00743     {
00744         if ( doAlign )
00745         {
00746             const QPolygon points = mapper.toPoints(
00747                 xMap, yMap, data(), from, to ); 
00748 
00749             QwtPainter::drawPoints( painter, points );
00750         }
00751         else
00752         {
00753             const QPolygonF points = mapper.toPointsF( 
00754                 xMap, yMap, data(), from, to );
00755 
00756             QwtPainter::drawPoints( painter, points );
00757         }
00758     }
00759 }
00760 
00776 void QwtPlotCurve::drawSteps( QPainter *painter,
00777     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00778     const QRectF &canvasRect, int from, int to ) const
00779 {
00780     const bool doAlign = QwtPainter::roundingAlignment( painter );
00781 
00782     QPolygonF polygon( 2 * ( to - from ) + 1 );
00783     QPointF *points = polygon.data();
00784 
00785     bool inverted = orientation() == Qt::Vertical;
00786     if ( d_data->attributes & Inverted )
00787         inverted = !inverted;
00788 
00789     const QwtSeriesData<QPointF> *series = data();
00790 
00791     int i, ip;
00792     for ( i = from, ip = 0; i <= to; i++, ip += 2 )
00793     {
00794         const QPointF sample = series->sample( i );
00795         double xi = xMap.transform( sample.x() );
00796         double yi = yMap.transform( sample.y() );
00797         if ( doAlign )
00798         {
00799             xi = qRound( xi );
00800             yi = qRound( yi );
00801         }
00802 
00803         if ( ip > 0 )
00804         {
00805             const QPointF &p0 = points[ip - 2];
00806             QPointF &p = points[ip - 1];
00807 
00808             if ( inverted )
00809             {
00810                 p.rx() = p0.x();
00811                 p.ry() = yi;
00812             }
00813             else
00814             {
00815                 p.rx() = xi;
00816                 p.ry() = p0.y();
00817             }
00818         }
00819 
00820         points[ip].rx() = xi;
00821         points[ip].ry() = yi;
00822     }
00823 
00824     if ( d_data->paintAttributes & ClipPolygons )
00825     {
00826         QRectF clipRect = qwtIntersectedClipRect( canvasRect, painter );
00827 
00828         const qreal pw = qMax( qreal( 1.0 ), painter->pen().widthF());
00829         clipRect = clipRect.adjusted(-pw, -pw, pw, pw);
00830 
00831         const QPolygonF clipped = QwtClipper::clipPolygonF( 
00832             clipRect, polygon, false );
00833 
00834         QwtPainter::drawPolyline( painter, clipped );
00835     }
00836     else
00837     {
00838         QwtPainter::drawPolyline( painter, polygon );
00839     }
00840 
00841     if ( d_data->brush.style() != Qt::NoBrush )
00842         fillCurve( painter, xMap, yMap, canvasRect, polygon );
00843 }
00844 
00845 
00854 void QwtPlotCurve::setCurveAttribute( CurveAttribute attribute, bool on )
00855 {
00856     if ( bool( d_data->attributes & attribute ) == on )
00857         return;
00858 
00859     if ( on )
00860         d_data->attributes |= attribute;
00861     else
00862         d_data->attributes &= ~attribute;
00863 
00864     itemChanged();
00865 }
00866 
00871 bool QwtPlotCurve::testCurveAttribute( CurveAttribute attribute ) const
00872 {
00873     return d_data->attributes & attribute;
00874 }
00875 
00893 void QwtPlotCurve::setCurveFitter( QwtCurveFitter *curveFitter )
00894 {
00895     delete d_data->curveFitter;
00896     d_data->curveFitter = curveFitter;
00897 
00898     itemChanged();
00899 }
00900 
00907 QwtCurveFitter *QwtPlotCurve::curveFitter() const
00908 {
00909     return d_data->curveFitter;
00910 }
00911 
00924 void QwtPlotCurve::fillCurve( QPainter *painter,
00925     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00926     const QRectF &canvasRect, QPolygonF &polygon ) const
00927 {
00928     if ( d_data->brush.style() == Qt::NoBrush )
00929         return;
00930 
00931     closePolyline( painter, xMap, yMap, polygon );
00932     if ( polygon.count() <= 2 ) // a line can't be filled
00933         return;
00934 
00935     QBrush brush = d_data->brush;
00936     if ( !brush.color().isValid() )
00937         brush.setColor( d_data->pen.color() );
00938 
00939     if ( d_data->paintAttributes & ClipPolygons )
00940     {
00941         const QRectF clipRect = qwtIntersectedClipRect( canvasRect, painter );
00942         polygon = QwtClipper::clipPolygonF( clipRect, polygon, true );
00943     }
00944 
00945     painter->save();
00946 
00947     painter->setPen( Qt::NoPen );
00948     painter->setBrush( brush );
00949 
00950     QwtPainter::drawPolygon( painter, polygon );
00951 
00952     painter->restore();
00953 }
00954 
00964 void QwtPlotCurve::closePolyline( QPainter *painter,
00965     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00966     QPolygonF &polygon ) const
00967 {
00968     if ( polygon.size() < 2 )
00969         return;
00970 
00971     const bool doAlign = QwtPainter::roundingAlignment( painter );
00972 
00973     double baseline = d_data->baseline;
00974     
00975     if ( orientation() == Qt::Vertical )
00976     {
00977         if ( yMap.transformation() )
00978             baseline = yMap.transformation()->bounded( baseline );
00979 
00980         double refY = yMap.transform( baseline );
00981         if ( doAlign )
00982             refY = qRound( refY );
00983 
00984         polygon += QPointF( polygon.last().x(), refY );
00985         polygon += QPointF( polygon.first().x(), refY );
00986     }
00987     else
00988     {
00989         if ( xMap.transformation() )
00990             baseline = xMap.transformation()->bounded( baseline );
00991 
00992         double refX = xMap.transform( baseline );
00993         if ( doAlign )
00994             refX = qRound( refX );
00995 
00996         polygon += QPointF( refX, polygon.last().y() );
00997         polygon += QPointF( refX, polygon.first().y() );
00998     }
00999 }
01000 
01014 void QwtPlotCurve::drawSymbols( QPainter *painter, const QwtSymbol &symbol,
01015     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
01016     const QRectF &canvasRect, int from, int to ) const
01017 {
01018     QwtPointMapper mapper;
01019     mapper.setFlag( QwtPointMapper::RoundPoints, 
01020         QwtPainter::roundingAlignment( painter ) );
01021     mapper.setFlag( QwtPointMapper::WeedOutPoints, 
01022         testPaintAttribute( QwtPlotCurve::FilterPoints ) );
01023 
01024     const QRectF clipRect = qwtIntersectedClipRect( canvasRect, painter );
01025     mapper.setBoundingRect( clipRect );
01026 
01027     const int chunkSize = 500;
01028 
01029     for ( int i = from; i <= to; i += chunkSize )
01030     {
01031         const int n = qMin( chunkSize, to - i + 1 );
01032 
01033         const QPolygonF points = mapper.toPointsF( xMap, yMap,
01034             data(), i, i + n - 1 );
01035 
01036         if ( points.size() > 0 )
01037             symbol.drawSymbols( painter, points );
01038     }
01039 }
01040 
01057 void QwtPlotCurve::setBaseline( double value )
01058 {
01059     if ( d_data->baseline != value )
01060     {
01061         d_data->baseline = value;
01062         itemChanged();
01063     }
01064 }
01065 
01070 double QwtPlotCurve::baseline() const
01071 {
01072     return d_data->baseline;
01073 }
01074 
01086 int QwtPlotCurve::closestPoint( const QPoint &pos, double *dist ) const
01087 {
01088     const size_t numSamples = dataSize();
01089 
01090     if ( plot() == NULL || numSamples <= 0 )
01091         return -1;
01092 
01093     const QwtSeriesData<QPointF> *series = data();
01094 
01095     const QwtScaleMap xMap = plot()->canvasMap( xAxis() );
01096     const QwtScaleMap yMap = plot()->canvasMap( yAxis() );
01097 
01098     int index = -1;
01099     double dmin = 1.0e10;
01100 
01101     for ( uint i = 0; i < numSamples; i++ )
01102     {
01103         const QPointF sample = series->sample( i );
01104 
01105         const double cx = xMap.transform( sample.x() ) - pos.x();
01106         const double cy = yMap.transform( sample.y() ) - pos.y();
01107 
01108         const double f = qwtSqr( cx ) + qwtSqr( cy );
01109         if ( f < dmin )
01110         {
01111             index = i;
01112             dmin = f;
01113         }
01114     }
01115     if ( dist )
01116         *dist = qSqrt( dmin );
01117 
01118     return index;
01119 }
01120 
01130 QwtGraphic QwtPlotCurve::legendIcon( int index, 
01131     const QSizeF &size ) const
01132 {
01133     Q_UNUSED( index );
01134 
01135     if ( size.isEmpty() )
01136         return QwtGraphic();
01137 
01138     QwtGraphic graphic;
01139     graphic.setDefaultSize( size );
01140     graphic.setRenderHint( QwtGraphic::RenderPensUnscaled, true );
01141 
01142     QPainter painter( &graphic );
01143     painter.setRenderHint( QPainter::Antialiasing,
01144         testRenderHint( QwtPlotItem::RenderAntialiased ) );
01145 
01146     if ( d_data->legendAttributes == 0 ||
01147         d_data->legendAttributes & QwtPlotCurve::LegendShowBrush )
01148     {
01149         QBrush brush = d_data->brush;
01150 
01151         if ( brush.style() == Qt::NoBrush &&
01152             d_data->legendAttributes == 0 )
01153         {
01154             if ( style() != QwtPlotCurve::NoCurve )
01155             {
01156                 brush = QBrush( pen().color() );
01157             }
01158             else if ( d_data->symbol &&
01159                 ( d_data->symbol->style() != QwtSymbol::NoSymbol ) )
01160             {
01161                 brush = QBrush( d_data->symbol->pen().color() );
01162             }
01163         }
01164 
01165         if ( brush.style() != Qt::NoBrush )
01166         {
01167             QRectF r( 0, 0, size.width(), size.height() );
01168             painter.fillRect( r, brush );
01169         }
01170     }
01171 
01172     if ( d_data->legendAttributes & QwtPlotCurve::LegendShowLine )
01173     {
01174         if ( pen() != Qt::NoPen )
01175         {
01176             QPen pn = pen();
01177             pn.setCapStyle( Qt::FlatCap );
01178 
01179             painter.setPen( pn );
01180 
01181             const double y = 0.5 * size.height();
01182             QwtPainter::drawLine( &painter, 0.0, y, size.width(), y );
01183         }
01184     }
01185 
01186     if ( d_data->legendAttributes & QwtPlotCurve::LegendShowSymbol )
01187     {
01188         if ( d_data->symbol )
01189         {
01190             QRectF r( 0, 0, size.width(), size.height() );
01191             d_data->symbol->drawSymbol( &painter, r );
01192         }
01193     }
01194 
01195     return graphic;
01196 }
01197 
01205 void QwtPlotCurve::setSamples( const QVector<QPointF> &samples )
01206 {
01207     setData( new QwtPointSeriesData( samples ) );
01208 }
01209 
01220 void QwtPlotCurve::setSamples( QwtSeriesData<QPointF> *data )
01221 {
01222     setData( data );
01223 }
01224 
01225 #ifndef QWT_NO_COMPAT
01226 
01241 void QwtPlotCurve::setRawSamples( 
01242     const double *xData, const double *yData, int size )
01243 {
01244     setData( new QwtCPointerData( xData, yData, size ) );
01245 }
01246 
01258 void QwtPlotCurve::setSamples( 
01259     const double *xData, const double *yData, int size )
01260 {
01261     setData( new QwtPointArrayData( xData, yData, size ) );
01262 }
01263 
01272 void QwtPlotCurve::setSamples( const QVector<double> &xData,
01273     const QVector<double> &yData )
01274 {
01275     setData( new QwtPointArrayData( xData, yData ) );
01276 }
01277 
01278 #endif // !QWT_NO_COMPAT
01279 


plotjuggler
Author(s): Davide Faconti
autogenerated on Fri Sep 1 2017 02:41:56