qwt_plot_histogram.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_histogram.h"
00011 #include "qwt_plot.h"
00012 #include "qwt_painter.h"
00013 #include "qwt_column_symbol.h"
00014 #include "qwt_scale_map.h"
00015 #include <qstring.h>
00016 #include <qpainter.h>
00017 
00018 static inline bool qwtIsCombinable( const QwtInterval &d1,
00019     const QwtInterval &d2 )
00020 {
00021     if ( d1.isValid() && d2.isValid() )
00022     {
00023         if ( d1.maxValue() == d2.minValue() )
00024         {
00025             if ( !( d1.borderFlags() & QwtInterval::ExcludeMaximum
00026                 && d2.borderFlags() & QwtInterval::ExcludeMinimum ) )
00027             {
00028                 return true;
00029             }
00030         }
00031     }
00032 
00033     return false;
00034 }
00035 
00036 class QwtPlotHistogram::PrivateData
00037 {
00038 public:
00039     PrivateData():
00040         baseline( 0.0 ),
00041         style( Columns ),
00042         symbol( NULL )
00043     {
00044     }
00045 
00046     ~PrivateData()
00047     {
00048         delete symbol;
00049     }
00050 
00051     double baseline;
00052 
00053     QPen pen;
00054     QBrush brush;
00055     QwtPlotHistogram::HistogramStyle style;
00056     const QwtColumnSymbol *symbol;
00057 };
00058 
00063 QwtPlotHistogram::QwtPlotHistogram( const QwtText &title ):
00064     QwtPlotSeriesItem( title )
00065 {
00066     init();
00067 }
00068 
00073 QwtPlotHistogram::QwtPlotHistogram( const QString &title ):
00074     QwtPlotSeriesItem( title )
00075 {
00076     init();
00077 }
00078 
00080 QwtPlotHistogram::~QwtPlotHistogram()
00081 {
00082     delete d_data;
00083 }
00084 
00086 void QwtPlotHistogram::init()
00087 {
00088     d_data = new PrivateData();
00089     setData( new QwtIntervalSeriesData() );
00090 
00091     setItemAttribute( QwtPlotItem::AutoScale, true );
00092     setItemAttribute( QwtPlotItem::Legend, true );
00093 
00094     setZ( 20.0 );
00095 }
00096 
00103 void QwtPlotHistogram::setStyle( HistogramStyle style )
00104 {
00105     if ( style != d_data->style )
00106     {
00107         d_data->style = style;
00108 
00109         legendChanged();
00110         itemChanged();
00111     }
00112 }
00113 
00118 QwtPlotHistogram::HistogramStyle QwtPlotHistogram::style() const
00119 {
00120     return d_data->style;
00121 }
00122 
00136 void QwtPlotHistogram::setPen( const QColor &color, qreal width, Qt::PenStyle style )
00137 {   
00138     setPen( QPen( color, width, style ) );
00139 }   
00140 
00147 void QwtPlotHistogram::setPen( const QPen &pen )
00148 {
00149     if ( pen != d_data->pen )
00150     {
00151         d_data->pen = pen;
00152 
00153         legendChanged();
00154         itemChanged();
00155     }
00156 }
00157 
00162 const QPen &QwtPlotHistogram::pen() const
00163 {
00164     return d_data->pen;
00165 }
00166 
00173 void QwtPlotHistogram::setBrush( const QBrush &brush )
00174 {
00175     if ( brush != d_data->brush )
00176     {
00177         d_data->brush = brush;
00178 
00179         legendChanged();
00180         itemChanged();
00181     }
00182 }
00183 
00188 const QBrush &QwtPlotHistogram::brush() const
00189 {
00190     return d_data->brush;
00191 }
00192 
00207 void QwtPlotHistogram::setSymbol( const QwtColumnSymbol *symbol )
00208 {
00209     if ( symbol != d_data->symbol )
00210     {
00211         delete d_data->symbol;
00212         d_data->symbol = symbol;
00213 
00214         legendChanged();
00215         itemChanged();
00216     }
00217 }
00218 
00223 const QwtColumnSymbol *QwtPlotHistogram::symbol() const
00224 {
00225     return d_data->symbol;
00226 }
00227 
00239 void QwtPlotHistogram::setBaseline( double value )
00240 {
00241     if ( d_data->baseline != value )
00242     {
00243         d_data->baseline = value;
00244         itemChanged();
00245     }
00246 }
00247 
00252 double QwtPlotHistogram::baseline() const
00253 {
00254     return d_data->baseline;
00255 }
00256 
00261 QRectF QwtPlotHistogram::boundingRect() const
00262 {
00263     QRectF rect = data()->boundingRect();
00264     if ( !rect.isValid() )
00265         return rect;
00266 
00267     if ( orientation() == Qt::Horizontal )
00268     {
00269         rect = QRectF( rect.y(), rect.x(),
00270             rect.height(), rect.width() );
00271 
00272         if ( rect.left() > d_data->baseline )
00273             rect.setLeft( d_data->baseline );
00274         else if ( rect.right() < d_data->baseline )
00275             rect.setRight( d_data->baseline );
00276     }
00277     else
00278     {
00279         if ( rect.bottom() < d_data->baseline )
00280             rect.setBottom( d_data->baseline );
00281         else if ( rect.top() > d_data->baseline )
00282             rect.setTop( d_data->baseline );
00283     }
00284 
00285     return rect;
00286 }
00287 
00289 int QwtPlotHistogram::rtti() const
00290 {
00291     return QwtPlotItem::Rtti_PlotHistogram;
00292 }
00293 
00298 void QwtPlotHistogram::setSamples(
00299     const QVector<QwtIntervalSample> &samples )
00300 {
00301     setData( new QwtIntervalSeriesData( samples ) );
00302 }
00303 
00314 void QwtPlotHistogram::setSamples( 
00315     QwtSeriesData<QwtIntervalSample> *data )
00316 {
00317     setData( data );
00318 }
00319 
00333 void QwtPlotHistogram::drawSeries( QPainter *painter,
00334     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00335     const QRectF &, int from, int to ) const
00336 {
00337     if ( !painter || dataSize() <= 0 )
00338         return;
00339 
00340     if ( to < 0 )
00341         to = dataSize() - 1;
00342 
00343     switch ( d_data->style )
00344     {
00345         case Outline:
00346             drawOutline( painter, xMap, yMap, from, to );
00347             break;
00348         case Lines:
00349             drawLines( painter, xMap, yMap, from, to );
00350             break;
00351         case Columns:
00352             drawColumns( painter, xMap, yMap, from, to );
00353             break;
00354         default:
00355             break;
00356     }
00357 }
00358 
00373 void QwtPlotHistogram::drawOutline( QPainter *painter,
00374     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00375     int from, int to ) const
00376 {
00377     const bool doAlign = QwtPainter::roundingAlignment( painter );
00378 
00379     double v0 = ( orientation() == Qt::Horizontal ) ?
00380         xMap.transform( baseline() ) : yMap.transform( baseline() );
00381     if ( doAlign )
00382         v0 = qRound( v0 );
00383 
00384     QwtIntervalSample previous;
00385 
00386     QPolygonF polygon;
00387     for ( int i = from; i <= to; i++ )
00388     {
00389         const QwtIntervalSample sample = this->sample( i );
00390 
00391         if ( !sample.interval.isValid() )
00392         {
00393             flushPolygon( painter, v0, polygon );
00394             previous = sample;
00395             continue;
00396         }
00397 
00398         if ( previous.interval.isValid() )
00399         {
00400             if ( !qwtIsCombinable( previous.interval, sample.interval ) )
00401                 flushPolygon( painter, v0, polygon );
00402         }
00403 
00404         if ( orientation() == Qt::Vertical )
00405         {
00406             double x1 = xMap.transform( sample.interval.minValue() );
00407             double x2 = xMap.transform( sample.interval.maxValue() );
00408             double y = yMap.transform( sample.value );
00409             if ( doAlign )
00410             {
00411                 x1 = qRound( x1 );
00412                 x2 = qRound( x2 );
00413                 y = qRound( y );
00414             }
00415 
00416             if ( polygon.size() == 0 )
00417                 polygon += QPointF( x1, v0 );
00418 
00419             polygon += QPointF( x1, y );
00420             polygon += QPointF( x2, y );
00421         }
00422         else
00423         {
00424             double y1 = yMap.transform( sample.interval.minValue() );
00425             double y2 = yMap.transform( sample.interval.maxValue() );
00426             double x = xMap.transform( sample.value );
00427             if ( doAlign )
00428             {
00429                 y1 = qRound( y1 );
00430                 y2 = qRound( y2 );
00431                 x = qRound( x );
00432             }
00433 
00434             if ( polygon.size() == 0 )
00435                 polygon += QPointF( v0, y1 );
00436 
00437             polygon += QPointF( x, y1 );
00438             polygon += QPointF( x, y2 );
00439         }
00440         previous = sample;
00441     }
00442 
00443     flushPolygon( painter, v0, polygon );
00444 }
00445 
00458 void QwtPlotHistogram::drawColumns( QPainter *painter,
00459     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00460     int from, int to ) const
00461 {
00462     painter->setPen( d_data->pen );
00463     painter->setBrush( d_data->brush );
00464 
00465     const QwtSeriesData<QwtIntervalSample> *series = data();
00466 
00467     for ( int i = from; i <= to; i++ )
00468     {
00469         const QwtIntervalSample sample = series->sample( i );
00470         if ( !sample.interval.isNull() )
00471         {
00472             const QwtColumnRect rect = columnRect( sample, xMap, yMap );
00473             drawColumn( painter, rect, sample );
00474         }
00475     }
00476 }
00477 
00490 void QwtPlotHistogram::drawLines( QPainter *painter,
00491     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00492     int from, int to ) const
00493 {
00494     const bool doAlign = QwtPainter::roundingAlignment( painter );
00495 
00496     painter->setPen( d_data->pen );
00497     painter->setBrush( Qt::NoBrush );
00498 
00499     const QwtSeriesData<QwtIntervalSample> *series = data();
00500 
00501     for ( int i = from; i <= to; i++ )
00502     {
00503         const QwtIntervalSample sample = series->sample( i );
00504         if ( !sample.interval.isNull() )
00505         {
00506             const QwtColumnRect rect = columnRect( sample, xMap, yMap );
00507 
00508             QRectF r = rect.toRect();
00509             if ( doAlign )
00510             {
00511                 r.setLeft( qRound( r.left() ) );
00512                 r.setRight( qRound( r.right() ) );
00513                 r.setTop( qRound( r.top() ) );
00514                 r.setBottom( qRound( r.bottom() ) );
00515             }
00516 
00517             switch ( rect.direction )
00518             {
00519                 case QwtColumnRect::LeftToRight:
00520                 {
00521                     QwtPainter::drawLine( painter,
00522                         r.topRight(), r.bottomRight() );
00523                     break;
00524                 }
00525                 case QwtColumnRect::RightToLeft:
00526                 {
00527                     QwtPainter::drawLine( painter,
00528                         r.topLeft(), r.bottomLeft() );
00529                     break;
00530                 }
00531                 case QwtColumnRect::TopToBottom:
00532                 {
00533                     QwtPainter::drawLine( painter,
00534                         r.bottomRight(), r.bottomLeft() );
00535                     break;
00536                 }
00537                 case QwtColumnRect::BottomToTop:
00538                 {
00539                     QwtPainter::drawLine( painter,
00540                         r.topRight(), r.topLeft() );
00541                     break;
00542                 }
00543             }
00544         }
00545     }
00546 }
00547 
00549 void QwtPlotHistogram::flushPolygon( QPainter *painter,
00550     double baseLine, QPolygonF &polygon ) const
00551 {
00552     if ( polygon.size() == 0 )
00553         return;
00554 
00555     if ( orientation() == Qt::Horizontal )
00556         polygon += QPointF( baseLine, polygon.last().y() );
00557     else
00558         polygon += QPointF( polygon.last().x(), baseLine );
00559 
00560     if ( d_data->brush.style() != Qt::NoBrush )
00561     {
00562         painter->setPen( Qt::NoPen );
00563         painter->setBrush( d_data->brush );
00564 
00565         if ( orientation() == Qt::Horizontal )
00566         {
00567             polygon += QPointF( polygon.last().x(), baseLine );
00568             polygon += QPointF( polygon.first().x(), baseLine );
00569         }
00570         else
00571         {
00572             polygon += QPointF( baseLine, polygon.last().y() );
00573             polygon += QPointF( baseLine, polygon.first().y() );
00574         }
00575 
00576         QwtPainter::drawPolygon( painter, polygon );
00577 
00578         polygon.pop_back();
00579         polygon.pop_back();
00580     }
00581     if ( d_data->pen.style() != Qt::NoPen )
00582     {
00583         painter->setBrush( Qt::NoBrush );
00584         painter->setPen( d_data->pen );
00585         QwtPainter::drawPolyline( painter, polygon );
00586     }
00587     polygon.clear();
00588 }
00589 
00599 QwtColumnRect QwtPlotHistogram::columnRect( const QwtIntervalSample &sample,
00600     const QwtScaleMap &xMap, const QwtScaleMap &yMap ) const
00601 {
00602     QwtColumnRect rect;
00603 
00604     const QwtInterval &iv = sample.interval;
00605     if ( !iv.isValid() )
00606         return rect;
00607 
00608     if ( orientation() == Qt::Horizontal )
00609     {
00610         const double x0 = xMap.transform( baseline() );
00611         const double x  = xMap.transform( sample.value );
00612         const double y1 = yMap.transform( iv.minValue() );
00613         const double y2 = yMap.transform( iv.maxValue() );
00614 
00615         rect.hInterval.setInterval( x0, x );
00616         rect.vInterval.setInterval( y1, y2, iv.borderFlags() );
00617         rect.direction = ( x < x0 ) ? QwtColumnRect::RightToLeft :
00618                          QwtColumnRect::LeftToRight;
00619     }
00620     else
00621     {
00622         const double x1 = xMap.transform( iv.minValue() );
00623         const double x2 = xMap.transform( iv.maxValue() );
00624         const double y0 = yMap.transform( baseline() );
00625         const double y = yMap.transform( sample.value );
00626 
00627         rect.hInterval.setInterval( x1, x2, iv.borderFlags() );
00628         rect.vInterval.setInterval( y0, y );
00629         rect.direction = ( y < y0 ) ? QwtColumnRect::BottomToTop :
00630             QwtColumnRect::TopToBottom;
00631     }
00632 
00633     return rect;
00634 }
00635 
00650 void QwtPlotHistogram::drawColumn( QPainter *painter,
00651     const QwtColumnRect &rect, const QwtIntervalSample &sample ) const
00652 {
00653     Q_UNUSED( sample );
00654 
00655     if ( d_data->symbol &&
00656         ( d_data->symbol->style() != QwtColumnSymbol::NoStyle ) )
00657     {
00658         d_data->symbol->draw( painter, rect );
00659     }
00660     else
00661     {
00662         QRectF r = rect.toRect();
00663         if ( QwtPainter::roundingAlignment( painter ) )
00664         {
00665             r.setLeft( qRound( r.left() ) );
00666             r.setRight( qRound( r.right() ) );
00667             r.setTop( qRound( r.top() ) );
00668             r.setBottom( qRound( r.bottom() ) );
00669         }
00670 
00671         QwtPainter::drawRect( painter, r );
00672     }
00673 }
00674 
00685 QwtGraphic QwtPlotHistogram::legendIcon( int index,
00686     const QSizeF &size ) const
00687 {
00688     Q_UNUSED( index );
00689     return defaultIcon( d_data->brush, size );
00690 }


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