qwt_plot_multi_barchart.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_multi_barchart.h"
00011 #include "qwt_scale_map.h"
00012 #include "qwt_column_symbol.h"
00013 #include "qwt_painter.h"
00014 #include <qpainter.h>
00015 #include <qpalette.h>
00016 #include <qmap.h>
00017 
00018 inline static bool qwtIsIncreasing(
00019     const QwtScaleMap &map, const QVector<double> &values )
00020 {
00021     bool isInverting = map.isInverting();
00022 
00023     for ( int i = 0; i < values.size(); i++ )
00024     {
00025         const double y = values[ i ];
00026         if ( y != 0.0 )
00027             return ( map.isInverting() != ( y > 0.0 ) );
00028     }
00029 
00030     return !isInverting;
00031 }
00032 
00033 class QwtPlotMultiBarChart::PrivateData
00034 {
00035 public:
00036     PrivateData():
00037         style( QwtPlotMultiBarChart::Grouped )
00038     {
00039     }
00040 
00041     QwtPlotMultiBarChart::ChartStyle style;
00042     QList<QwtText> barTitles;
00043     QMap<int, QwtColumnSymbol *> symbolMap;
00044 };
00045 
00050 QwtPlotMultiBarChart::QwtPlotMultiBarChart( const QwtText &title ):
00051     QwtPlotAbstractBarChart( title )
00052 {
00053     init();
00054 }
00055 
00060 QwtPlotMultiBarChart::QwtPlotMultiBarChart( const QString &title ):
00061     QwtPlotAbstractBarChart( QwtText( title ) )
00062 {
00063     init();
00064 }
00065 
00067 QwtPlotMultiBarChart::~QwtPlotMultiBarChart()
00068 {
00069     resetSymbolMap();
00070     delete d_data;
00071 }
00072 
00073 void QwtPlotMultiBarChart::init()
00074 {
00075     d_data = new PrivateData;
00076     setData( new QwtSetSeriesData() );
00077 }
00078 
00080 int QwtPlotMultiBarChart::rtti() const
00081 {
00082     return QwtPlotItem::Rtti_PlotMultiBarChart;
00083 }
00084 
00089 void QwtPlotMultiBarChart::setSamples(
00090     const QVector<QwtSetSample> &samples )
00091 {
00092     setData( new QwtSetSeriesData( samples ) );
00093 }
00094 
00099 void QwtPlotMultiBarChart::setSamples(
00100     const QVector< QVector<double> > &samples )
00101 {
00102     QVector<QwtSetSample> s;
00103     for ( int i = 0; i < samples.size(); i++ )
00104         s += QwtSetSample( i, samples[ i ] );
00105 
00106     setData( new QwtSetSeriesData( s ) );
00107 }
00108 
00119 void QwtPlotMultiBarChart::setSamples( 
00120     QwtSeriesData<QwtSetSample> *data )
00121 {       
00122     setData( data );
00123 }       
00124 
00134 void QwtPlotMultiBarChart::setBarTitles( const QList<QwtText> &titles )
00135 {
00136     d_data->barTitles = titles;
00137     itemChanged();
00138 }
00139 
00144 QList<QwtText> QwtPlotMultiBarChart::barTitles() const
00145 {
00146     return d_data->barTitles;
00147 }
00148 
00160 void QwtPlotMultiBarChart::setSymbol( int valueIndex, QwtColumnSymbol *symbol )
00161 {
00162     if ( valueIndex < 0 )
00163         return;
00164 
00165     QMap<int, QwtColumnSymbol *>::iterator it = 
00166         d_data->symbolMap.find(valueIndex);
00167     if ( it == d_data->symbolMap.end() )
00168     {
00169         if ( symbol != NULL )
00170         {
00171             d_data->symbolMap.insert( valueIndex, symbol );
00172 
00173             legendChanged();
00174             itemChanged();
00175         }
00176     }
00177     else
00178     {
00179         if ( symbol != it.value() )
00180         {
00181             delete it.value();
00182 
00183             if ( symbol == NULL )
00184             {
00185                 d_data->symbolMap.remove( valueIndex );
00186             }
00187             else
00188             {
00189                 it.value() = symbol;
00190             }
00191 
00192             legendChanged();
00193             itemChanged();
00194         }
00195     }
00196 }
00197 
00206 const QwtColumnSymbol *QwtPlotMultiBarChart::symbol( int valueIndex ) const
00207 {
00208     QMap<int, QwtColumnSymbol *>::const_iterator it =
00209         d_data->symbolMap.find( valueIndex );
00210 
00211     return ( it == d_data->symbolMap.end() ) ? NULL : it.value();
00212 }
00213 
00222 QwtColumnSymbol *QwtPlotMultiBarChart::symbol( int valueIndex ) 
00223 {
00224     QMap<int, QwtColumnSymbol *>::iterator it =
00225         d_data->symbolMap.find( valueIndex );
00226 
00227     return ( it == d_data->symbolMap.end() ) ? NULL : it.value();
00228 }
00229 
00233 void QwtPlotMultiBarChart::resetSymbolMap()
00234 {
00235     for ( QMap<int, QwtColumnSymbol *>::iterator it 
00236         = d_data->symbolMap.begin(); it != d_data->symbolMap.end(); ++it )
00237     {
00238         delete it.value();
00239     }
00240 
00241     d_data->symbolMap.clear();
00242 }
00243 
00264 QwtColumnSymbol *QwtPlotMultiBarChart::specialSymbol( 
00265     int sampleIndex, int valueIndex ) const
00266 {
00267     Q_UNUSED( sampleIndex );
00268     Q_UNUSED( valueIndex );
00269 
00270     return NULL;
00271 }
00272 
00279 void QwtPlotMultiBarChart::setStyle( ChartStyle style )
00280 {
00281     if ( style != d_data->style )
00282     {
00283         d_data->style = style;
00284 
00285         legendChanged();
00286         itemChanged();
00287     }
00288 }
00289 
00294 QwtPlotMultiBarChart::ChartStyle QwtPlotMultiBarChart::style() const
00295 {
00296     return d_data->style;
00297 }
00298 
00303 QRectF QwtPlotMultiBarChart::boundingRect() const
00304 {
00305     const size_t numSamples = dataSize();
00306 
00307     if ( numSamples == 0 )
00308         return QwtPlotSeriesItem::boundingRect();
00309 
00310     const double baseLine = baseline();
00311 
00312     QRectF rect;
00313 
00314     if ( d_data->style != QwtPlotMultiBarChart::Stacked )
00315     {
00316         rect = QwtPlotSeriesItem::boundingRect();
00317 
00318         if ( rect.height() >= 0 )
00319         {
00320             if ( rect.bottom() < baseLine )
00321                 rect.setBottom( baseLine );
00322             if ( rect.top() > baseLine )
00323                 rect.setTop( baseLine );
00324         }
00325     }
00326     else
00327     {
00328         double xMin, xMax, yMin, yMax;
00329 
00330         xMin = xMax = 0.0;
00331         yMin = yMax = baseLine;
00332 
00333         const QwtSeriesData<QwtSetSample> *series = data();
00334 
00335         for ( size_t i = 0; i < numSamples; i++ )
00336         {
00337             const QwtSetSample sample = series->sample( i );
00338             if ( i == 0 )
00339             {
00340                 xMin = xMax = sample.value;
00341             }
00342             else
00343             {
00344                 xMin = qMin( xMin, sample.value );
00345                 xMax = qMax( xMax, sample.value );
00346             }
00347 
00348             const double y = baseLine + sample.added();
00349 
00350             yMin = qMin( yMin, y );
00351             yMax = qMax( yMax, y );
00352         }
00353         rect.setRect( xMin, yMin, xMax - xMin, yMax - yMin );
00354     }
00355 
00356     if ( orientation() == Qt::Horizontal )
00357         rect.setRect( rect.y(), rect.x(), rect.height(), rect.width() );
00358 
00359     return rect;
00360 }
00361 
00375 void QwtPlotMultiBarChart::drawSeries( QPainter *painter,
00376     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00377     const QRectF &canvasRect, int from, int to ) const
00378 {
00379     if ( to < 0 )
00380         to = dataSize() - 1;
00381 
00382     if ( from < 0 )
00383         from = 0;
00384 
00385     if ( from > to )
00386         return;
00387 
00388 
00389     const QRectF br = data()->boundingRect();
00390     const QwtInterval interval( br.left(), br.right() );
00391 
00392     painter->save();
00393 
00394     for ( int i = from; i <= to; i++ )
00395     {
00396         drawSample( painter, xMap, yMap,
00397             canvasRect, interval, i, sample( i ) );
00398     }
00399 
00400     painter->restore();
00401 }
00402 
00416 void QwtPlotMultiBarChart::drawSample( QPainter *painter,
00417     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00418     const QRectF &canvasRect, const QwtInterval &boundingInterval,
00419     int index, const QwtSetSample& sample ) const
00420 {
00421     if ( sample.set.size() <= 0 )
00422         return;
00423 
00424     double sampleW;
00425 
00426     if ( orientation() == Qt::Horizontal )
00427     {
00428         sampleW = sampleWidth( yMap, canvasRect.height(),
00429             boundingInterval.width(), sample.value );
00430     }
00431     else
00432     {
00433         sampleW = sampleWidth( xMap, canvasRect.width(),
00434             boundingInterval.width(), sample.value );
00435     }
00436 
00437     if ( d_data->style == Stacked )
00438     {
00439         drawStackedBars( painter, xMap, yMap,
00440             canvasRect, index, sampleW, sample );
00441     }
00442     else
00443     {
00444         drawGroupedBars( painter, xMap, yMap,
00445             canvasRect, index, sampleW, sample );
00446     }
00447 }
00448 
00462 void QwtPlotMultiBarChart::drawGroupedBars( QPainter *painter,
00463     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00464     const QRectF &canvasRect, int index, double sampleWidth,
00465     const QwtSetSample& sample ) const
00466 {
00467     Q_UNUSED( canvasRect );
00468 
00469     const int numBars = sample.set.size();
00470     if ( numBars == 0 )
00471         return;
00472 
00473     if ( orientation() == Qt::Vertical )
00474     {
00475         const double barWidth = sampleWidth / numBars;
00476 
00477         const double y1 = yMap.transform( baseline() );
00478         const double x0 = xMap.transform( sample.value ) - 0.5 * sampleWidth;
00479 
00480         for ( int i = 0; i < numBars; i++ )
00481         {
00482             const double x1 = x0 + i * barWidth;
00483             const double x2 = x1 + barWidth;
00484 
00485             const double y2 = yMap.transform( sample.set[i] );
00486 
00487             QwtColumnRect barRect;
00488             barRect.direction = ( y1 < y2 ) ?
00489                 QwtColumnRect::TopToBottom : QwtColumnRect::BottomToTop;
00490 
00491             barRect.hInterval = QwtInterval( x1, x2 ).normalized();
00492             if ( i != 0 )
00493                 barRect.hInterval.setBorderFlags( QwtInterval::ExcludeMinimum );
00494 
00495             barRect.vInterval = QwtInterval( y1, y2 ).normalized();
00496 
00497             drawBar( painter, index, i, barRect );
00498         }
00499     }
00500     else
00501     {
00502         const double barHeight = sampleWidth / numBars;
00503 
00504         const double x1 = xMap.transform( baseline() );
00505         const double y0 = yMap.transform( sample.value ) - 0.5 * sampleWidth;
00506 
00507         for ( int i = 0; i < numBars; i++ )
00508         {
00509             double y1 = y0 + i * barHeight;
00510             double y2 = y1 + barHeight;
00511 
00512             double x2 = xMap.transform( sample.set[i] );
00513 
00514             QwtColumnRect barRect;
00515             barRect.direction = x1 < x2 ?
00516                 QwtColumnRect::LeftToRight : QwtColumnRect::RightToLeft;
00517 
00518             barRect.hInterval = QwtInterval( x1, x2 ).normalized();
00519 
00520             barRect.vInterval = QwtInterval( y1, y2 );
00521             if ( i != 0 )
00522                 barRect.vInterval.setBorderFlags( QwtInterval::ExcludeMinimum );
00523 
00524             drawBar( painter, index, i, barRect );
00525         }
00526     }
00527 }
00528 
00542 void QwtPlotMultiBarChart::drawStackedBars( QPainter *painter,
00543     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00544     const QRectF &canvasRect, int index, 
00545     double sampleWidth, const QwtSetSample& sample ) const
00546 {
00547     Q_UNUSED( canvasRect ); // clipping the bars ?
00548 
00549     const int numBars = sample.set.size();
00550     if ( numBars == 0 )
00551         return;
00552 
00553     QwtInterval::BorderFlag borderFlags = QwtInterval::IncludeBorders;
00554 
00555     if ( orientation() == Qt::Vertical )
00556     {
00557         const double x1 = xMap.transform( sample.value ) - 0.5 * sampleWidth;
00558         const double x2 = x1 + sampleWidth;
00559 
00560         const bool increasing = qwtIsIncreasing( yMap, sample.set );
00561 
00562         QwtColumnRect bar;
00563         bar.direction = increasing ?
00564             QwtColumnRect::TopToBottom : QwtColumnRect::BottomToTop;
00565 
00566         bar.hInterval = QwtInterval( x1, x2 ).normalized();
00567 
00568         double sum = baseline();
00569 
00570         const int numBars = sample.set.size();
00571         for ( int i = 0; i < numBars; i++ )
00572         {
00573             const double si = sample.set[ i ];
00574             if ( si == 0.0 )
00575                 continue;
00576 
00577             const double y1 = yMap.transform( sum );
00578             const double y2 = yMap.transform( sum + si );
00579 
00580             if ( ( y2 > y1 ) != increasing )
00581             {
00582                 // stacked bars need to be in the same direction
00583                 continue;
00584             }
00585 
00586             bar.vInterval = QwtInterval( y1, y2 ).normalized();
00587             bar.vInterval.setBorderFlags( borderFlags );
00588 
00589             drawBar( painter, index, i, bar );
00590 
00591             sum += si;
00592 
00593             if ( increasing )
00594                 borderFlags = QwtInterval::ExcludeMinimum;
00595             else
00596                 borderFlags = QwtInterval::ExcludeMaximum;
00597         }
00598     }
00599     else
00600     {
00601         const double y1 = yMap.transform( sample.value ) - 0.5 * sampleWidth;
00602         const double y2 = y1 + sampleWidth;
00603 
00604         const bool increasing = qwtIsIncreasing( xMap, sample.set );
00605 
00606         QwtColumnRect bar;
00607         bar.direction = increasing ?
00608             QwtColumnRect::LeftToRight : QwtColumnRect::RightToLeft;
00609         bar.vInterval = QwtInterval( y1, y2 ).normalized();
00610 
00611         double sum = baseline();
00612 
00613         for ( int i = 0; i < sample.set.size(); i++ )
00614         {
00615             const double si = sample.set[ i ];
00616             if ( si == 0.0 )
00617                 continue;
00618 
00619             const double x1 = xMap.transform( sum );
00620             const double x2 = xMap.transform( sum + si );
00621 
00622             if ( ( x2 > x1 ) != increasing )
00623             {
00624                 // stacked bars need to be in the same direction
00625                 continue;
00626             }
00627 
00628             bar.hInterval = QwtInterval( x1, x2 ).normalized();
00629             bar.hInterval.setBorderFlags( borderFlags );
00630 
00631             drawBar( painter, index, i, bar );
00632 
00633             sum += si;
00634 
00635             if ( increasing )
00636                 borderFlags = QwtInterval::ExcludeMinimum;
00637             else
00638                 borderFlags = QwtInterval::ExcludeMaximum;
00639         }
00640     }
00641 }
00642 
00654 void QwtPlotMultiBarChart::drawBar( QPainter *painter,
00655     int sampleIndex, int valueIndex, const QwtColumnRect &rect ) const
00656 {
00657     const QwtColumnSymbol *specialSym = NULL;
00658     if ( sampleIndex >= 0 )
00659         specialSym = specialSymbol( sampleIndex, valueIndex );
00660 
00661     const QwtColumnSymbol *sym = specialSym;
00662     if ( sym == NULL )
00663         sym = symbol( valueIndex );
00664 
00665     if ( sym )
00666     {
00667         sym->draw( painter, rect );
00668     }
00669     else
00670     {
00671         // we build a temporary default symbol
00672         QwtColumnSymbol sym( QwtColumnSymbol::Box );
00673         sym.setLineWidth( 1 );
00674         sym.setFrameStyle( QwtColumnSymbol::Plain );
00675         sym.draw( painter, rect );
00676     }
00677 
00678     delete specialSym;
00679 }
00680 
00689 QList<QwtLegendData> QwtPlotMultiBarChart::legendData() const
00690 {
00691     QList<QwtLegendData> list;
00692 
00693     for ( int i = 0; i < d_data->barTitles.size(); i++ )
00694     {
00695         QwtLegendData data;
00696 
00697         QVariant titleValue;
00698         qVariantSetValue( titleValue, d_data->barTitles[i] );
00699         data.setValue( QwtLegendData::TitleRole, titleValue );
00700 
00701         if ( !legendIconSize().isEmpty() )
00702         {
00703             QVariant iconValue;
00704             qVariantSetValue( iconValue, 
00705                 legendIcon( i, legendIconSize() ) );
00706 
00707             data.setValue( QwtLegendData::IconRole, iconValue );
00708         }
00709 
00710         list += data;
00711     }
00712 
00713     return list;
00714 }
00715 
00725 QwtGraphic QwtPlotMultiBarChart::legendIcon( int index,
00726     const QSizeF &size ) const
00727 {
00728     QwtColumnRect column;
00729     column.hInterval = QwtInterval( 0.0, size.width() - 1.0 );
00730     column.vInterval = QwtInterval( 0.0, size.height() - 1.0 );
00731 
00732     QwtGraphic icon;
00733     icon.setDefaultSize( size );
00734     icon.setRenderHint( QwtGraphic::RenderPensUnscaled, true );
00735 
00736     QPainter painter( &icon );
00737     painter.setRenderHint( QPainter::Antialiasing,
00738         testRenderHint( QwtPlotItem::RenderAntialiased ) );
00739 
00740     drawBar( &painter, -1, index, column );
00741 
00742     return icon;
00743 }
00744 


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