00001
00002
00003
00004
00005
00006
00007
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 );
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
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
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
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