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     s.reserve( samples.size() );
00104 
00105     for ( int i = 0; i < samples.size(); i++ )
00106         s += QwtSetSample( i, samples[ i ] );
00107 
00108     setData( new QwtSetSeriesData( s ) );
00109 }
00110 
00121 void QwtPlotMultiBarChart::setSamples( 
00122     QwtSeriesData<QwtSetSample> *data )
00123 {       
00124     setData( data );
00125 }       
00126 
00136 void QwtPlotMultiBarChart::setBarTitles( const QList<QwtText> &titles )
00137 {
00138     d_data->barTitles = titles;
00139     itemChanged();
00140 }
00141 
00146 QList<QwtText> QwtPlotMultiBarChart::barTitles() const
00147 {
00148     return d_data->barTitles;
00149 }
00150 
00162 void QwtPlotMultiBarChart::setSymbol( int valueIndex, QwtColumnSymbol *symbol )
00163 {
00164     if ( valueIndex < 0 )
00165         return;
00166 
00167     QMap<int, QwtColumnSymbol *>::iterator it = 
00168         d_data->symbolMap.find(valueIndex);
00169     if ( it == d_data->symbolMap.end() )
00170     {
00171         if ( symbol != NULL )
00172         {
00173             d_data->symbolMap.insert( valueIndex, symbol );
00174 
00175             legendChanged();
00176             itemChanged();
00177         }
00178     }
00179     else
00180     {
00181         if ( symbol != it.value() )
00182         {
00183             delete it.value();
00184 
00185             if ( symbol == NULL )
00186             {
00187                 d_data->symbolMap.remove( valueIndex );
00188             }
00189             else
00190             {
00191                 it.value() = symbol;
00192             }
00193 
00194             legendChanged();
00195             itemChanged();
00196         }
00197     }
00198 }
00199 
00208 const QwtColumnSymbol *QwtPlotMultiBarChart::symbol( int valueIndex ) const
00209 {
00210     QMap<int, QwtColumnSymbol *>::const_iterator it =
00211         d_data->symbolMap.constFind( valueIndex );
00212 
00213     return ( it == d_data->symbolMap.constEnd() ) ? NULL : it.value();
00214 }
00215 
00224 QwtColumnSymbol *QwtPlotMultiBarChart::symbol( int valueIndex ) 
00225 {
00226     QMap<int, QwtColumnSymbol *>::const_iterator it =
00227         d_data->symbolMap.constFind( valueIndex );
00228 
00229     return ( it == d_data->symbolMap.constEnd() ) ? NULL : it.value();
00230 }
00231 
00235 void QwtPlotMultiBarChart::resetSymbolMap()
00236 {
00237     qDeleteAll( d_data->symbolMap );
00238     d_data->symbolMap.clear();
00239 }
00240 
00261 QwtColumnSymbol *QwtPlotMultiBarChart::specialSymbol( 
00262     int sampleIndex, int valueIndex ) const
00263 {
00264     Q_UNUSED( sampleIndex );
00265     Q_UNUSED( valueIndex );
00266 
00267     return NULL;
00268 }
00269 
00276 void QwtPlotMultiBarChart::setStyle( ChartStyle style )
00277 {
00278     if ( style != d_data->style )
00279     {
00280         d_data->style = style;
00281 
00282         legendChanged();
00283         itemChanged();
00284     }
00285 }
00286 
00291 QwtPlotMultiBarChart::ChartStyle QwtPlotMultiBarChart::style() const
00292 {
00293     return d_data->style;
00294 }
00295 
00300 QRectF QwtPlotMultiBarChart::boundingRect() const
00301 {
00302     const size_t numSamples = dataSize();
00303 
00304     if ( numSamples == 0 )
00305         return QwtPlotSeriesItem::boundingRect();
00306 
00307     const double baseLine = baseline();
00308 
00309     QRectF rect;
00310 
00311     if ( d_data->style != QwtPlotMultiBarChart::Stacked )
00312     {
00313         rect = QwtPlotSeriesItem::boundingRect();
00314 
00315         if ( rect.height() >= 0 )
00316         {
00317             if ( rect.bottom() < baseLine )
00318                 rect.setBottom( baseLine );
00319             if ( rect.top() > baseLine )
00320                 rect.setTop( baseLine );
00321         }
00322     }
00323     else
00324     {
00325         double xMin, xMax, yMin, yMax;
00326 
00327         xMin = xMax = 0.0;
00328         yMin = yMax = baseLine;
00329 
00330         const QwtSeriesData<QwtSetSample> *series = data();
00331 
00332         for ( size_t i = 0; i < numSamples; i++ )
00333         {
00334             const QwtSetSample sample = series->sample( i );
00335             if ( i == 0 )
00336             {
00337                 xMin = xMax = sample.value;
00338             }
00339             else
00340             {
00341                 xMin = qMin( xMin, sample.value );
00342                 xMax = qMax( xMax, sample.value );
00343             }
00344 
00345             const double y = baseLine + sample.added();
00346 
00347             yMin = qMin( yMin, y );
00348             yMax = qMax( yMax, y );
00349         }
00350         rect.setRect( xMin, yMin, xMax - xMin, yMax - yMin );
00351     }
00352 
00353     if ( orientation() == Qt::Horizontal )
00354         rect.setRect( rect.y(), rect.x(), rect.height(), rect.width() );
00355 
00356     return rect;
00357 }
00358 
00372 void QwtPlotMultiBarChart::drawSeries( QPainter *painter,
00373     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00374     const QRectF &canvasRect, int from, int to ) const
00375 {
00376     if ( to < 0 )
00377         to = dataSize() - 1;
00378 
00379     if ( from < 0 )
00380         from = 0;
00381 
00382     if ( from > to )
00383         return;
00384 
00385 
00386     const QRectF br = data()->boundingRect();
00387     const QwtInterval interval( br.left(), br.right() );
00388 
00389     painter->save();
00390 
00391     for ( int i = from; i <= to; i++ )
00392     {
00393         drawSample( painter, xMap, yMap,
00394             canvasRect, interval, i, sample( i ) );
00395     }
00396 
00397     painter->restore();
00398 }
00399 
00413 void QwtPlotMultiBarChart::drawSample( QPainter *painter,
00414     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00415     const QRectF &canvasRect, const QwtInterval &boundingInterval,
00416     int index, const QwtSetSample& sample ) const
00417 {
00418     if ( sample.set.size() <= 0 )
00419         return;
00420 
00421     double sampleW;
00422 
00423     if ( orientation() == Qt::Horizontal )
00424     {
00425         sampleW = sampleWidth( yMap, canvasRect.height(),
00426             boundingInterval.width(), sample.value );
00427     }
00428     else
00429     {
00430         sampleW = sampleWidth( xMap, canvasRect.width(),
00431             boundingInterval.width(), sample.value );
00432     }
00433 
00434     if ( d_data->style == Stacked )
00435     {
00436         drawStackedBars( painter, xMap, yMap,
00437             canvasRect, index, sampleW, sample );
00438     }
00439     else
00440     {
00441         drawGroupedBars( painter, xMap, yMap,
00442             canvasRect, index, sampleW, sample );
00443     }
00444 }
00445 
00459 void QwtPlotMultiBarChart::drawGroupedBars( QPainter *painter,
00460     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00461     const QRectF &canvasRect, int index, double sampleWidth,
00462     const QwtSetSample& sample ) const
00463 {
00464     Q_UNUSED( canvasRect );
00465 
00466     const int numBars = sample.set.size();
00467     if ( numBars == 0 )
00468         return;
00469 
00470     if ( orientation() == Qt::Vertical )
00471     {
00472         const double barWidth = sampleWidth / numBars;
00473 
00474         const double y1 = yMap.transform( baseline() );
00475         const double x0 = xMap.transform( sample.value ) - 0.5 * sampleWidth;
00476 
00477         for ( int i = 0; i < numBars; i++ )
00478         {
00479             const double x1 = x0 + i * barWidth;
00480             const double x2 = x1 + barWidth;
00481 
00482             const double y2 = yMap.transform( sample.set[i] );
00483 
00484             QwtColumnRect barRect;
00485             barRect.direction = ( y1 < y2 ) ?
00486                 QwtColumnRect::TopToBottom : QwtColumnRect::BottomToTop;
00487 
00488             barRect.hInterval = QwtInterval( x1, x2 ).normalized();
00489             if ( i != 0 )
00490                 barRect.hInterval.setBorderFlags( QwtInterval::ExcludeMinimum );
00491 
00492             barRect.vInterval = QwtInterval( y1, y2 ).normalized();
00493 
00494             drawBar( painter, index, i, barRect );
00495         }
00496     }
00497     else
00498     {
00499         const double barHeight = sampleWidth / numBars;
00500 
00501         const double x1 = xMap.transform( baseline() );
00502         const double y0 = yMap.transform( sample.value ) - 0.5 * sampleWidth;
00503 
00504         for ( int i = 0; i < numBars; i++ )
00505         {
00506             double y1 = y0 + i * barHeight;
00507             double y2 = y1 + barHeight;
00508 
00509             double x2 = xMap.transform( sample.set[i] );
00510 
00511             QwtColumnRect barRect;
00512             barRect.direction = x1 < x2 ?
00513                 QwtColumnRect::LeftToRight : QwtColumnRect::RightToLeft;
00514 
00515             barRect.hInterval = QwtInterval( x1, x2 ).normalized();
00516 
00517             barRect.vInterval = QwtInterval( y1, y2 );
00518             if ( i != 0 )
00519                 barRect.vInterval.setBorderFlags( QwtInterval::ExcludeMinimum );
00520 
00521             drawBar( painter, index, i, barRect );
00522         }
00523     }
00524 }
00525 
00539 void QwtPlotMultiBarChart::drawStackedBars( QPainter *painter,
00540     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00541     const QRectF &canvasRect, int index, 
00542     double sampleWidth, const QwtSetSample& sample ) const
00543 {
00544     Q_UNUSED( canvasRect ); // clipping the bars ?
00545 
00546     const int numBars = sample.set.size();
00547     if ( numBars == 0 )
00548         return;
00549 
00550     QwtInterval::BorderFlag borderFlags = QwtInterval::IncludeBorders;
00551 
00552     if ( orientation() == Qt::Vertical )
00553     {
00554         const double x1 = xMap.transform( sample.value ) - 0.5 * sampleWidth;
00555         const double x2 = x1 + sampleWidth;
00556 
00557         const bool increasing = qwtIsIncreasing( yMap, sample.set );
00558 
00559         QwtColumnRect bar;
00560         bar.direction = increasing ?
00561             QwtColumnRect::TopToBottom : QwtColumnRect::BottomToTop;
00562 
00563         bar.hInterval = QwtInterval( x1, x2 ).normalized();
00564 
00565         double sum = baseline();
00566 
00567         const int numBars = sample.set.size();
00568         for ( int i = 0; i < numBars; i++ )
00569         {
00570             const double si = sample.set[ i ];
00571             if ( si == 0.0 )
00572                 continue;
00573 
00574             const double y1 = yMap.transform( sum );
00575             const double y2 = yMap.transform( sum + si );
00576 
00577             if ( ( y2 > y1 ) != increasing )
00578             {
00579                 // stacked bars need to be in the same direction
00580                 continue;
00581             }
00582 
00583             bar.vInterval = QwtInterval( y1, y2 ).normalized();
00584             bar.vInterval.setBorderFlags( borderFlags );
00585 
00586             drawBar( painter, index, i, bar );
00587 
00588             sum += si;
00589 
00590             if ( increasing )
00591                 borderFlags = QwtInterval::ExcludeMinimum;
00592             else
00593                 borderFlags = QwtInterval::ExcludeMaximum;
00594         }
00595     }
00596     else
00597     {
00598         const double y1 = yMap.transform( sample.value ) - 0.5 * sampleWidth;
00599         const double y2 = y1 + sampleWidth;
00600 
00601         const bool increasing = qwtIsIncreasing( xMap, sample.set );
00602 
00603         QwtColumnRect bar;
00604         bar.direction = increasing ?
00605             QwtColumnRect::LeftToRight : QwtColumnRect::RightToLeft;
00606         bar.vInterval = QwtInterval( y1, y2 ).normalized();
00607 
00608         double sum = baseline();
00609 
00610         for ( int i = 0; i < sample.set.size(); i++ )
00611         {
00612             const double si = sample.set[ i ];
00613             if ( si == 0.0 )
00614                 continue;
00615 
00616             const double x1 = xMap.transform( sum );
00617             const double x2 = xMap.transform( sum + si );
00618 
00619             if ( ( x2 > x1 ) != increasing )
00620             {
00621                 // stacked bars need to be in the same direction
00622                 continue;
00623             }
00624 
00625             bar.hInterval = QwtInterval( x1, x2 ).normalized();
00626             bar.hInterval.setBorderFlags( borderFlags );
00627 
00628             drawBar( painter, index, i, bar );
00629 
00630             sum += si;
00631 
00632             if ( increasing )
00633                 borderFlags = QwtInterval::ExcludeMinimum;
00634             else
00635                 borderFlags = QwtInterval::ExcludeMaximum;
00636         }
00637     }
00638 }
00639 
00651 void QwtPlotMultiBarChart::drawBar( QPainter *painter,
00652     int sampleIndex, int valueIndex, const QwtColumnRect &rect ) const
00653 {
00654     const QwtColumnSymbol *specialSym = NULL;
00655     if ( sampleIndex >= 0 )
00656         specialSym = specialSymbol( sampleIndex, valueIndex );
00657 
00658     const QwtColumnSymbol *sym = specialSym;
00659     if ( sym == NULL )
00660         sym = symbol( valueIndex );
00661 
00662     if ( sym )
00663     {
00664         sym->draw( painter, rect );
00665     }
00666     else
00667     {
00668         // we build a temporary default symbol
00669         QwtColumnSymbol sym( QwtColumnSymbol::Box );
00670         sym.setLineWidth( 1 );
00671         sym.setFrameStyle( QwtColumnSymbol::Plain );
00672         sym.draw( painter, rect );
00673     }
00674 
00675     delete specialSym;
00676 }
00677 
00686 QList<QwtLegendData> QwtPlotMultiBarChart::legendData() const
00687 {
00688     QList<QwtLegendData> list;
00689 #if QT_VERSION >= 0x040700
00690     list.reserve( d_data->barTitles.size() );
00691 #endif
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 Wed Jul 3 2019 19:28:05