00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "KDChartCartesianDiagramDataCompressor_p.h"
00031
00032 #include <QtDebug>
00033 #include <QAbstractItemModel>
00034
00035 #include "KDChartAbstractCartesianDiagram.h"
00036
00037 #include <KDABLibFakes>
00038
00039 using namespace KDChart;
00040 using namespace std;
00041
00042 CartesianDiagramDataCompressor::CartesianDiagramDataCompressor( QObject* parent )
00043 : QObject( parent )
00044 , m_mode( Precise )
00045 , m_xResolution( 0 )
00046 , m_yResolution( 0 )
00047 , m_sampleStep( 0 )
00048 , m_datasetDimension( 1 )
00049 {
00050 calculateSampleStepWidth();
00051 }
00052
00053 QModelIndexList CartesianDiagramDataCompressor::indexesAt( const CachePosition& position ) const
00054 {
00055 if ( isValidCachePosition( position ) ) {
00056 CachePosition posPrev( position );
00057 if( m_datasetDimension == 2 ){
00058 if(posPrev.second)
00059 --posPrev.second;
00060 }else{
00061 if(posPrev.first)
00062 --posPrev.first;
00063 }
00064 const QModelIndexList indPrev = mapToModel( posPrev );
00065 const QModelIndexList indCur = mapToModel( position );
00066
00067 QModelIndexList indexes;
00068 if( m_datasetDimension == 2 )
00069 {
00070 const int iStart = (indPrev.empty() || indPrev==indCur) ? indCur.first().column()
00071 : indPrev.first().column() + 1;
00072 const int iEnd = indCur.last().column();
00073 for( int i=iStart; i<=iEnd; ++i){
00074 indexes << m_model->index( position.first, i, m_rootIndex );
00075 }
00076 }
00077 else
00078 {
00079 const int iStart = (indPrev.empty() || indPrev==indCur) ? indCur.first().row()
00080 : indPrev.first().row() + 1;
00081 const int iEnd = (indCur.isEmpty()) ? iStart : indCur.first().row();
00082
00083 for( int i=iStart; i<=iEnd; ++i){
00084 indexes << m_model->index( i, position.second, m_rootIndex );
00085 }
00086 }
00087 return indexes;
00088 } else {
00089 return QModelIndexList();
00090 }
00091 }
00092
00093
00094 CartesianDiagramDataCompressor::DataValueAttributesList CartesianDiagramDataCompressor::aggregatedAttrs(
00095 AbstractDiagram * diagram,
00096 const QModelIndex & index,
00097 const CachePosition& position ) const
00098 {
00099
00100 DataValueAttributesCache::const_iterator i = m_dataValueAttributesCache.find(position);
00101 if( i != m_dataValueAttributesCache.end() )
00102 return i.value();
00103
00104 CartesianDiagramDataCompressor::DataValueAttributesList allAttrs;
00105 const QModelIndexList indexes( indexesAt( position ) );
00106 KDAB_FOREACH( QModelIndex idx, indexes ) {
00107 DataValueAttributes attrs( diagram->dataValueAttributes( idx ) );
00108 if( attrs.isVisible() ){
00109
00110 bool isDuplicate = false;
00111 CartesianDiagramDataCompressor::DataValueAttributesList::const_iterator i = allAttrs.constBegin();
00112 while (i != allAttrs.constEnd()) {
00113 if( i.value() == attrs ){
00114 isDuplicate = true;
00115 continue;
00116 }
00117 ++i;
00118 }
00119 if( !isDuplicate ){
00120
00121 allAttrs[idx] = attrs;
00122 }
00123 }
00124 }
00125
00126
00127 if( allAttrs.empty() ){
00128 allAttrs[index] = diagram->dataValueAttributes( index );
00129 }
00130
00131 m_dataValueAttributesCache[position] = allAttrs;
00132 return allAttrs;
00133 }
00134
00135
00136 void CartesianDiagramDataCompressor::slotRowsAboutToBeInserted( const QModelIndex& parent, int start, int end )
00137 {
00138 if ( parent != m_rootIndex )
00139 return;
00140 Q_ASSERT( start <= end );
00141
00142 CachePosition startPos = mapToCache( start, 0 );
00143 CachePosition endPos = mapToCache( end, 0 );
00144
00145 static const CachePosition NullPosition( -1, -1 );
00146 if( startPos == NullPosition )
00147 {
00148 rebuildCache();
00149 startPos = mapToCache( start, 0 );
00150 endPos = mapToCache( end, 0 );
00151
00152
00153 if( startPos == NullPosition ) {
00154 return;
00155 }
00156 }
00157
00158 start = startPos.first;
00159 end = endPos.first;
00160
00161 for( int i = 0; i < m_data.size(); ++i )
00162 {
00163 Q_ASSERT( start >= 0 && start <= m_data[ i ].size() );
00164 m_data[ i ].insert( start, end - start + 1, DataPoint() );
00165 }
00166 }
00167
00168 void CartesianDiagramDataCompressor::slotRowsInserted( const QModelIndex& parent, int start, int end )
00169 {
00170 if ( parent != m_rootIndex )
00171 return;
00172 Q_ASSERT( start <= end );
00173
00174 CachePosition startPos = mapToCache( start, 0 );
00175 CachePosition endPos = mapToCache( end, 0 );
00176
00177 static const CachePosition NullPosition( -1, -1 );
00178 if( startPos == NullPosition )
00179 {
00180
00181 rebuildCache();
00182 startPos = mapToCache( start, 0 );
00183 endPos = mapToCache( end, 0 );
00184
00185
00186 if( startPos == NullPosition ) {
00187 return;
00188 }
00189 }
00190
00191 start = startPos.first;
00192 end = endPos.first;
00193
00194 for( int i = 0; i < m_data.size(); ++i )
00195 {
00196 for( int j = start; j < m_data[i].size(); ++j ) {
00197 retrieveModelData( CachePosition( j, i ) );
00198 }
00199 }
00200 }
00201
00202 void CartesianDiagramDataCompressor::slotColumnsAboutToBeInserted( const QModelIndex& parent, int start, int end )
00203 {
00204 if ( parent != m_rootIndex )
00205 return;
00206 Q_ASSERT( start <= end );
00207
00208 CachePosition startPos = mapToCache( 0, start );
00209 CachePosition endPos = mapToCache( 0, end );
00210
00211 static const CachePosition NullPosition( -1, -1 );
00212 if( startPos == NullPosition )
00213 {
00214 rebuildCache();
00215 startPos = mapToCache( 0, start );
00216 endPos = mapToCache( 0, end );
00217
00218
00219 if( startPos == NullPosition ) {
00220 return;
00221 }
00222 }
00223
00224 start = startPos.second;
00225 end = endPos.second;
00226
00227 const int rowCount = qMin( m_model ? m_model->rowCount( m_rootIndex ) : 0, m_xResolution );
00228 Q_ASSERT( start >= 0 && start <= m_data.size() );
00229 m_data.insert( start, end - start + 1, QVector< DataPoint >( rowCount ) );
00230 }
00231
00232 void CartesianDiagramDataCompressor::slotColumnsInserted( const QModelIndex& parent, int start, int end )
00233 {
00234 if ( parent != m_rootIndex )
00235 return;
00236 Q_ASSERT( start <= end );
00237
00238 CachePosition startPos = mapToCache( 0, start );
00239 CachePosition endPos = mapToCache( 0, end );
00240
00241 static const CachePosition NullPosition( -1, -1 );
00242 if( startPos == NullPosition )
00243 {
00244
00245 rebuildCache();
00246 startPos = mapToCache( 0, start );
00247 endPos = mapToCache( 0, end );
00248
00249
00250 if( startPos == NullPosition ) {
00251 return;
00252 }
00253 }
00254
00255 start = startPos.second;
00256 end = endPos.second;
00257
00258 for( int i = start; i < m_data.size(); ++i )
00259 {
00260 for(int j = 0; j < m_data[i].size(); ++j ) {
00261 retrieveModelData( CachePosition( j, i ) );
00262 }
00263 }
00264 }
00265
00266 void CartesianDiagramDataCompressor::slotRowsAboutToBeRemoved( const QModelIndex& parent, int start, int end )
00267 {
00268 if ( parent != m_rootIndex )
00269 return;
00270 Q_ASSERT( start <= end );
00271
00272 CachePosition startPos = mapToCache( start, 0 );
00273 CachePosition endPos = mapToCache( end, 0 );
00274
00275 static const CachePosition NullPosition( -1, -1 );
00276 if( startPos == NullPosition )
00277 {
00278 rebuildCache();
00279 startPos = mapToCache( start, 0 );
00280 endPos = mapToCache( end, 0 );
00281
00282
00283 if( startPos == NullPosition ) {
00284 return;
00285 }
00286 }
00287
00288 start = startPos.first;
00289 end = endPos.first;
00290
00291 for( int i = 0; i < m_data.size(); ++i )
00292 {
00293 m_data[ i ].remove( start, end - start + 1 );
00294 }
00295 }
00296
00297 void CartesianDiagramDataCompressor::slotRowsRemoved( const QModelIndex& parent, int start, int end )
00298 {
00299 if ( parent != m_rootIndex )
00300 return;
00301 Q_ASSERT( start <= end );
00302
00303 CachePosition startPos = mapToCache( start, 0 );
00304 CachePosition endPos = mapToCache( end, 0 );
00305
00306 start = startPos.first;
00307 end = endPos.first;
00308
00309 static const CachePosition NullPosition( -1, -1 );
00310 if( startPos == NullPosition )
00311 {
00312
00313
00314 return;
00315 }
00316
00317 for( int i = 0; i < m_data.size(); ++i ) {
00318 for(int j = start; j < m_data[i].size(); ++j ) {
00319 retrieveModelData( CachePosition( j, i ) );
00320 }
00321 }
00322 }
00323
00324 void CartesianDiagramDataCompressor::slotColumnsAboutToBeRemoved( const QModelIndex& parent, int start, int end )
00325 {
00326 if ( parent != m_rootIndex )
00327 return;
00328 Q_ASSERT( start <= end );
00329
00330 CachePosition startPos = mapToCache( 0, start );
00331 CachePosition endPos = mapToCache( 0, end );
00332
00333 static const CachePosition NullPosition( -1, -1 );
00334 if( startPos == NullPosition )
00335 {
00336 rebuildCache();
00337 startPos = mapToCache( 0, start );
00338 endPos = mapToCache( 0, end );
00339
00340
00341 if( startPos == NullPosition ) {
00342 return;
00343 }
00344 }
00345
00346 start = startPos.second;
00347 end = endPos.second;
00348
00349 m_data.remove( start, end - start + 1 );
00350 }
00351
00352 void CartesianDiagramDataCompressor::slotColumnsRemoved( const QModelIndex& parent, int start, int end )
00353 {
00354 if ( parent != m_rootIndex )
00355 return;
00356 Q_ASSERT( start <= end );
00357
00358 const CachePosition startPos = mapToCache( 0, start );
00359 const CachePosition endPos = mapToCache( 0, end );
00360
00361 start = startPos.second;
00362 end = endPos.second;
00363
00364 static const CachePosition NullPosition( -1, -1 );
00365 if( startPos == NullPosition )
00366 {
00367
00368
00369 return;
00370 }
00371
00372 for( int i = start; i < m_data.size(); ++i ) {
00373 for( int j = 0; j < m_data[i].size(); ++j ) {
00374 retrieveModelData( CachePosition( j, i ) );
00375 }
00376 }
00377 }
00378
00379 void CartesianDiagramDataCompressor::slotModelHeaderDataChanged( Qt::Orientation orientation, int first, int last )
00380 {
00381 if( orientation != Qt::Vertical )
00382 return;
00383
00384 const QModelIndex firstRow = m_model->index( 0, first, m_rootIndex );
00385 const QModelIndex lastRow = m_model->index( m_model->rowCount( m_rootIndex ) - 1, last, m_rootIndex );
00386
00387 slotModelDataChanged( firstRow, lastRow );
00388 }
00389
00390 void CartesianDiagramDataCompressor::slotModelDataChanged(
00391 const QModelIndex& topLeftIndex,
00392 const QModelIndex& bottomRightIndex )
00393 {
00394 if ( topLeftIndex.parent() != m_rootIndex )
00395 return;
00396 Q_ASSERT( topLeftIndex.parent() == bottomRightIndex.parent() );
00397 Q_ASSERT( topLeftIndex.row() <= bottomRightIndex.row() );
00398 Q_ASSERT( topLeftIndex.column() <= bottomRightIndex.column() );
00399 CachePosition topleft = mapToCache( topLeftIndex );
00400 CachePosition bottomright = mapToCache( bottomRightIndex );
00401 for ( int row = topleft.first; row <= bottomright.first; ++row )
00402 for ( int column = topleft.second; column <= bottomright.second; ++column )
00403 invalidate( CachePosition( row, column ) );
00404 }
00405
00406 void CartesianDiagramDataCompressor::slotModelLayoutChanged()
00407 {
00408 rebuildCache();
00409 calculateSampleStepWidth();
00410 }
00411
00412 void CartesianDiagramDataCompressor::slotDiagramLayoutChanged( AbstractDiagram* diagramBase )
00413 {
00414 AbstractCartesianDiagram* diagram = qobject_cast< AbstractCartesianDiagram* >( diagramBase );
00415 Q_ASSERT( diagram );
00416 if ( diagram->datasetDimension() != m_datasetDimension ) {
00417 setDatasetDimension( diagram->datasetDimension() );
00418 }
00419 }
00420
00421 int CartesianDiagramDataCompressor::modelDataColumns() const
00422 {
00423 Q_ASSERT( m_datasetDimension != 0 );
00424
00425 if ( m_model ) {
00426 const int columns = m_model->columnCount( m_rootIndex ) / m_datasetDimension;
00427
00428 if( columns != m_data.size() )
00429 {
00430 rebuildCache();
00431 }
00432
00433 Q_ASSERT( columns == m_data.size() );
00434 return columns;
00435 } else {
00436 return 0;
00437 }
00438 }
00439
00440 int CartesianDiagramDataCompressor::modelDataRows() const
00441 {
00442
00443 if ( m_model && m_model->columnCount( m_rootIndex ) > 0 && m_xResolution > 0 ) {
00444 return m_data.isEmpty() ? 0 : m_data.first().size();
00445 } else {
00446 return 0;
00447 }
00448 }
00449
00450 void CartesianDiagramDataCompressor::setModel( QAbstractItemModel* model )
00451 {
00452 if ( m_model != 0 && m_model != model ) {
00453 disconnect( m_model, SIGNAL( headerDataChanged( Qt::Orientation, int, int ) ),
00454 this, SLOT( slotModelHeaderDataChanged( Qt::Orientation, int, int ) ) );
00455 disconnect( m_model, SIGNAL( dataChanged( QModelIndex, QModelIndex ) ),
00456 this, SLOT( slotModelDataChanged( QModelIndex, QModelIndex ) ) );
00457 disconnect( m_model, SIGNAL( layoutChanged() ),
00458 this, SLOT( slotModelLayoutChanged() ) );
00459 disconnect( m_model, SIGNAL( rowsAboutToBeInserted( QModelIndex, int, int ) ),
00460 this, SLOT( slotRowsAboutToBeInserted( QModelIndex, int, int ) ) );
00461 disconnect( m_model, SIGNAL( rowsInserted( QModelIndex, int, int ) ),
00462 this, SLOT( slotRowsInserted( QModelIndex, int, int ) ) );
00463 disconnect( m_model, SIGNAL( rowsAboutToBeRemoved( QModelIndex, int, int ) ),
00464 this, SLOT( slotRowsAboutToBeRemoved( QModelIndex, int, int ) ) );
00465 disconnect( m_model, SIGNAL( rowsRemoved( QModelIndex, int, int ) ),
00466 this, SLOT( slotRowsRemoved( QModelIndex, int, int ) ) );
00467 disconnect( m_model, SIGNAL( columnsAboutToBeInserted( QModelIndex, int, int ) ),
00468 this, SLOT( slotColumnsAboutToBeInserted( QModelIndex, int, int ) ) );
00469 disconnect( m_model, SIGNAL( columnsInserted( QModelIndex, int, int ) ),
00470 this, SLOT( slotColumnsInserted( QModelIndex, int, int ) ) );
00471 disconnect( m_model, SIGNAL( columnsRemoved( QModelIndex, int, int ) ),
00472 this, SLOT( slotColumnsRemoved( QModelIndex, int, int ) ) );
00473 disconnect( m_model, SIGNAL( columnsAboutToBeRemoved( QModelIndex, int, int ) ),
00474 this, SLOT( slotColumnsAboutToBeRemoved( QModelIndex, int, int ) ) );
00475 disconnect( m_model, SIGNAL( modelReset() ),
00476 this, SLOT( rebuildCache() ) );
00477 m_model = 0;
00478 }
00479
00480 m_modelCache.setModel( model );
00481
00482 if ( model != 0 ) {
00483 m_model = model;
00484 connect( m_model, SIGNAL( headerDataChanged( Qt::Orientation, int, int ) ),
00485 SLOT( slotModelHeaderDataChanged( Qt::Orientation, int, int ) ) );
00486 connect( m_model, SIGNAL( dataChanged( QModelIndex, QModelIndex ) ),
00487 SLOT( slotModelDataChanged( QModelIndex, QModelIndex ) ) );
00488 connect( m_model, SIGNAL( layoutChanged() ),
00489 SLOT( slotModelLayoutChanged() ) );
00490 connect( m_model, SIGNAL( rowsAboutToBeInserted( QModelIndex, int, int ) ),
00491 SLOT( slotRowsAboutToBeInserted( QModelIndex, int, int ) ) );
00492 connect( m_model, SIGNAL( rowsInserted( QModelIndex, int, int ) ),
00493 SLOT( slotRowsInserted( QModelIndex, int, int ) ) );
00494 connect( m_model, SIGNAL( rowsAboutToBeRemoved( QModelIndex, int, int ) ),
00495 SLOT( slotRowsAboutToBeRemoved( QModelIndex, int, int ) ) );
00496 connect( m_model, SIGNAL( rowsRemoved( QModelIndex, int, int ) ),
00497 SLOT( slotRowsRemoved( QModelIndex, int, int ) ) );
00498 connect( m_model, SIGNAL( columnsAboutToBeInserted( QModelIndex, int, int ) ),
00499 SLOT( slotColumnsAboutToBeInserted( QModelIndex, int, int ) ) );
00500 connect( m_model, SIGNAL( columnsInserted( QModelIndex, int, int ) ),
00501 SLOT( slotColumnsInserted( QModelIndex, int, int ) ) );
00502 connect( m_model, SIGNAL( columnsRemoved( QModelIndex, int, int ) ),
00503 SLOT( slotColumnsRemoved( QModelIndex, int, int ) ) );
00504 connect( m_model, SIGNAL( columnsAboutToBeRemoved( QModelIndex, int, int ) ),
00505 SLOT( slotColumnsAboutToBeRemoved( QModelIndex, int, int ) ) );
00506 connect( m_model, SIGNAL( modelReset() ),
00507 this, SLOT( rebuildCache() ) );
00508 }
00509 rebuildCache();
00510 calculateSampleStepWidth();
00511 }
00512
00513 void CartesianDiagramDataCompressor::setRootIndex( const QModelIndex& root )
00514 {
00515 if ( m_rootIndex != root ) {
00516 Q_ASSERT( root.model() == m_model || !root.isValid() );
00517 m_rootIndex = root;
00518 m_modelCache.setRootIndex( root );
00519 rebuildCache();
00520 calculateSampleStepWidth();
00521 }
00522 }
00523 void CartesianDiagramDataCompressor::setResolution( int x, int y )
00524 {
00525 const int oldX = m_xResolution;
00526 const int oldY = m_yResolution;
00527
00528 if( m_datasetDimension != 1 )
00529 {
00530
00531 m_xResolution = m_model == 0 ? 0 : m_model->rowCount( m_rootIndex );
00532 m_yResolution = qMax( 0, y );
00533 }
00534 else if ( x != m_xResolution || y != m_yResolution ) {
00535 m_xResolution = qMax( 0, x );
00536 m_yResolution = qMax( 0, y );
00537 rebuildCache();
00538 calculateSampleStepWidth();
00539 }
00540
00541 if( oldX != m_xResolution || oldY != m_yResolution )
00542 {
00543 rebuildCache();
00544 calculateSampleStepWidth();
00545 }
00546 }
00547
00548 void CartesianDiagramDataCompressor::clearCache()
00549 {
00550 for ( int column = 0; column < m_data.size(); ++column )
00551 m_data[column].fill( DataPoint() );
00552 }
00553
00554 void CartesianDiagramDataCompressor::rebuildCache() const
00555 {
00556 Q_ASSERT( m_datasetDimension != 0 );
00557
00558 m_data.clear();
00559 const int columnCount = m_model ? m_model->columnCount( m_rootIndex ) / m_datasetDimension : 0;
00560 const int rowCount = qMin( m_model ? m_model->rowCount( m_rootIndex ) : 0, m_xResolution );
00561 m_data.resize( columnCount );
00562 for ( int i = 0; i < columnCount; ++i ) {
00563 m_data[i].resize( rowCount );
00564 }
00565
00566 m_dataValueAttributesCache.clear();
00567 }
00568
00569 const CartesianDiagramDataCompressor::DataPoint& CartesianDiagramDataCompressor::data( const CachePosition& position ) const
00570 {
00571 static DataPoint NullDataPoint;
00572 if ( ! isValidCachePosition( position ) ) return NullDataPoint;
00573 if ( ! isCached( position ) ) retrieveModelData( position );
00574 return m_data[ position.second ][ position.first ];
00575 }
00576
00577 void CartesianDiagramDataCompressor::retrieveModelData( const CachePosition& position ) const
00578 {
00579 Q_ASSERT( isValidCachePosition( position ) );
00580 DataPoint result;
00581
00582 switch(m_mode ) {
00583 case Precise:
00584 {
00585 bool forceHidden = false;
00586 result.hidden = true;
00587 const QModelIndexList indexes = mapToModel( position );
00588 if( m_datasetDimension != 1 )
00589 {
00590 Q_ASSERT( indexes.count() == 2 );
00591 const QModelIndex xIndex = indexes.first();
00592 const QModelIndex yIndex = indexes.last();
00593 const double xData = m_modelCache.data( xIndex );
00594 const double yData = m_modelCache.data( yIndex );
00595 result.index = xIndex;
00596 result.key = xData;
00597 result.value = yData;
00598 }
00599 else
00600 {
00601 if ( ! indexes.isEmpty() ) {
00602 result.value = std::numeric_limits< double >::quiet_NaN();
00603 result.key = 0.0;
00604 Q_FOREACH( const QModelIndex& index, indexes ) {
00605 const double value = m_modelCache.data( index );
00606 if( !ISNAN( value ) )
00607 {
00608 result.value = ISNAN( result.value ) ? value : result.value + value;
00609 }
00610 result.key += index.row();
00611 }
00612 result.index = indexes.at( 0 );
00613 result.key /= indexes.size();
00614 result.value /= indexes.size();
00615 }
00616 }
00617 if( !forceHidden )
00618 {
00619 Q_FOREACH( const QModelIndex& index, indexes )
00620 {
00621
00622 if ( qVariantValue<bool>( m_model->data( index, DataHiddenRole ) ) == false ) {
00623 result.hidden = false;
00624 }
00625 }
00626 }
00627 }
00628 break;
00629 case SamplingSeven:
00630 default:
00631 {
00632 }
00633 break;
00634 };
00635
00636 m_data[position.second][position.first] = result;
00637 Q_ASSERT( isCached( position ) );
00638 }
00639
00640 CartesianDiagramDataCompressor::CachePosition CartesianDiagramDataCompressor::mapToCache(
00641 const QModelIndex& index ) const
00642 {
00643 Q_ASSERT( m_datasetDimension != 0 );
00644
00645 static const CachePosition NullPosition( -1, -1 );
00646 if ( ! index.isValid() ) return NullPosition;
00647 return mapToCache( index.row(), index.column() );
00648 }
00649
00650 CartesianDiagramDataCompressor::CachePosition CartesianDiagramDataCompressor::mapToCache(
00651 int row, int column ) const
00652 {
00653 Q_ASSERT( m_datasetDimension != 0 );
00654
00655 if ( m_data.size() == 0 || m_data[0].size() == 0 ) return mapToCache( QModelIndex() );
00656
00657 if ( indexesPerPixel() == 0 ) return mapToCache( QModelIndex() );
00658 return CachePosition( static_cast< int >( ( row ) / indexesPerPixel() ), column / m_datasetDimension );
00659 }
00660
00661 QModelIndexList CartesianDiagramDataCompressor::mapToModel( const CachePosition& position ) const
00662 {
00663 if ( isValidCachePosition( position ) ) {
00664 QModelIndexList indexes;
00665 if( m_datasetDimension == 2 )
00666 {
00667 indexes << m_model->index( position.first, position.second * 2, m_rootIndex );
00668 indexes << m_model->index( position.first, position.second * 2 + 1, m_rootIndex );
00669 }
00670 else
00671 {
00672
00673 const qreal ipp = indexesPerPixel();
00674 for ( int i = 0; i < ipp; ++i ) {
00675 const QModelIndex index = m_model->index( qRound( position.first * ipp ) + i, position.second, m_rootIndex );
00676 if( index.isValid() )
00677 indexes << index;
00678 }
00679 }
00680 return indexes;
00681 } else {
00682 return QModelIndexList();
00683 }
00684 }
00685
00686 qreal CartesianDiagramDataCompressor::indexesPerPixel() const
00687 {
00688 if ( m_data.size() == 0 ) return 0;
00689 if ( m_data[0].size() == 0 ) return 0;
00690 if ( ! m_model ) return 0;
00691 return static_cast< qreal >( m_model->rowCount( m_rootIndex ) ) / static_cast< qreal >( m_data[0].size() );
00692 }
00693
00694 bool CartesianDiagramDataCompressor::isValidCachePosition( const CachePosition& position ) const
00695 {
00696 if ( ! m_model ) return false;
00697 if ( m_data.size() == 0 || m_data[0].size() == 0 ) return false;
00698 if ( position.second < 0 || position.second >= m_data.size() ) return false;
00699 if ( position.first < 0 || position.first >= m_data[0].size() ) return false;
00700 return true;
00701 }
00702
00703 void CartesianDiagramDataCompressor::invalidate( const CachePosition& position )
00704 {
00705 if ( isValidCachePosition( position ) ) {
00706 m_data[position.second][position.first] = DataPoint();
00707
00708
00709
00710 m_dataValueAttributesCache.remove( position );
00711 }
00712 }
00713
00714 bool CartesianDiagramDataCompressor::isCached( const CachePosition& position ) const
00715 {
00716 Q_ASSERT( isValidCachePosition( position ) );
00717 const DataPoint& p = m_data[position.second][position.first];
00718 return p.index.isValid();
00719 }
00720
00721 void CartesianDiagramDataCompressor::calculateSampleStepWidth()
00722 {
00723 if ( m_mode == Precise ) {
00724 m_sampleStep = 1;
00725 return;
00726 }
00727
00728 static unsigned int SomePrimes[] = {
00729 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
00730 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
00731 151, 211, 313, 401, 503, 607, 701, 811, 911, 1009,
00732 10037, 12911, 16001, 20011, 50021,
00733 100003, 137867, 199999, 500009, 707753, 1000003, 0
00734 };
00735
00736
00737 const double WantedSamples = 17;
00738 if ( WantedSamples > indexesPerPixel() ) {
00739 m_sampleStep = 1;
00740 } else {
00741 int i;
00742 for ( i = 0; SomePrimes[i] != 0; ++i ) {
00743 if ( WantedSamples * SomePrimes[i+1] > indexesPerPixel() ) {
00744 break;
00745 }
00746 }
00747 m_sampleStep = SomePrimes[i];
00748 if ( SomePrimes[i] == 0 ) {
00749 m_sampleStep = SomePrimes[i-1];
00750 } else {
00751 m_sampleStep = SomePrimes[i];
00752 }
00753 }
00754 }
00755
00756 void CartesianDiagramDataCompressor::setDatasetDimension( int dimension )
00757 {
00758 if ( dimension != m_datasetDimension ) {
00759 m_datasetDimension = dimension;
00760 rebuildCache();
00761 calculateSampleStepWidth();
00762 }
00763 }