25 #include "KDChartPlotterDiagramCompressor_p.h" 26 #include <QtCore/QPointF> 29 #include <KDABLibFakes> 41 , m_dataset( dataSet )
63 , m_dataset( dataSet )
66 , m_timeOfCreation( QDateTime::currentDateTime() )
88 if ( m_parent.data()->d->m_timeOfLastInvalidation < m_timeOfCreation )
89 m_parent.data()->d->m_bufferlist[ m_dataset ] = m_buffer;
97 return m_dataset >= 0 && m_index >= 0 && m_parent.data()->rowCount() > m_index;
263 void PlotterDiagramCompressor::Iterator::handleSlopeForward(
const DataPoint &dp )
266 const qreal mergedist = parent->d->m_maxSlopeRadius;
272 if ( m_bufferIndex > 1 )
278 qreal accumulatedDist = qAbs( newSlope - oldSlope );
279 qreal olddist = accumulatedDist;
282 while ( accumulatedDist < mergedist )
285 if ( m_index >= m_parent.data()->rowCount() )
296 newdist = qAbs( newSlope - oldSlope );
297 if ( olddist == newdist )
306 accumulatedDist += newdist;
309 m_buffer.append( newdp );
312 m_buffer.append( dp );
319 const int count = parent->
rowCount();
326 if ( m_index >= count || ( !m_rebuffer && m_bufferIndex == m_buffer.count() ) )
328 if ( m_bufferIndex == m_buffer.count() )
340 if ( m_bufferIndex == m_buffer.count() && m_index >= 0 && m_rebuffer )
343 if ( parent->d->inBoundaries( Qt::Vertical, dp ) && parent->d->inBoundaries( Qt::Horizontal, dp ) )
346 handleSlopeForward( dp );
365 for (
int index = m_index; index + value != m_index; ++( *this ) ) {};
393 Q_ASSERT( m_parent );
394 if ( m_index == m_parent.data()->rowCount() )
395 return m_parent.data()->data(
CachePosition( m_parent.data()->rowCount() - 1 , m_dataset ) );
396 return m_buffer[ m_bufferIndex ];
401 return m_parent.data() == other.m_parent.data() && m_index == other.m_index && m_dataset == other.m_dataset;
406 return ! ( *
this == other );
417 , m_mergeRadius( 0.1 )
418 , m_maxSlopeRadius( 0.1 )
419 , m_boundary( qMakePair( QPointF( std::numeric_limits<qreal>::quiet_NaN(), std::numeric_limits<qreal>::quiet_NaN() )
420 , QPointF( std::numeric_limits<qreal>::quiet_NaN(), std::numeric_limits<qreal>::quiet_NaN() ) ) )
421 , m_forcedXBoundaries( qMakePair( std::numeric_limits<qreal>::quiet_NaN(), std::numeric_limits<qreal>::quiet_NaN() ) )
422 , m_forcedYBoundaries( qMakePair( std::numeric_limits<qreal>::quiet_NaN(), std::numeric_limits<qreal>::quiet_NaN() ) )
428 void PlotterDiagramCompressor::Private::setModelToZero()
435 return bounds.first <= value && value <= bounds.second;
440 if ( orient == Qt::Vertical && forcedBoundaries( Qt::Vertical ) )
444 else if ( forcedBoundaries( Qt::Horizontal ) )
571 void PlotterDiagramCompressor::Private::rowsInserted(
const QModelIndex& ,
int start,
int end )
577 if ( m_bufferlist.count() > 0 && !m_bufferlist[ 0 ].isEmpty() && start < m_bufferlist[ 0 ].count() )
579 calculateDataBoundaries();
585 qreal minX = m_boundary.first.x();
586 qreal minY = m_boundary.first.y();
587 qreal maxX = m_boundary.second.x();
588 qreal maxY = m_boundary.second.y();
589 for (
int dataset = 0; dataset < m_bufferlist.size(); ++dataset )
602 oldSlope =
calculateSlope( m_parent->data( CachePosition( start - 2, dataset ) ), m_parent->data( CachePosition( start - 1, dataset ) ) );
603 olddp = m_parent->data( CachePosition( start - 1, dataset ) );
607 m_bufferlist[ dataset ].append( newdp );
608 minX = qMin( minX, newdp.
key );
609 minY = qMin( minY, newdp.
value );
610 maxX = qMax( newdp.
key, maxX );
611 maxY = qMax( newdp.
value, maxY );
617 for (
int row = start; row <=
end; ++row )
623 newdist = qAbs( newSlope - oldSlope );
624 m_accumulatedDistances[ dataset ] += newdist;
625 const bool checkcur = inBoundaries( Qt::Vertical, curdp ) && inBoundaries( Qt::Horizontal, curdp );
626 const bool checkpred = inBoundaries( Qt::Vertical, predecessor ) && inBoundaries( Qt::Horizontal, predecessor );
627 const bool check = checkcur || checkpred;
629 if ( m_accumulatedDistances[ dataset ] >= m_maxSlopeRadius && check )
631 if ( start > m_bufferlist[ dataset ].count() && !m_bufferlist[ dataset ].isEmpty() )
633 m_bufferlist[ dataset ].append( curdp );
635 else if ( !m_bufferlist[ dataset ].isEmpty() )
637 m_bufferlist[ dataset ].insert( row, curdp );
640 m_accumulatedDistances[ dataset ] = 0;
642 minX = qMin( minX, curdp.
key );
643 minY = qMin( minY, curdp.
value );
644 maxX = qMax( curdp.
key, maxX );
645 maxY = qMax( curdp.
value, maxY );
649 if ( olddist == newdist )
657 m_bufferlist[ dataset ].append( curdp );
659 m_accumulatedDistances[ dataset ] = 0;
663 setBoundaries( qMakePair( QPointF( minX, minY ), QPointF( maxX, maxY ) ) );
669 for (
int row = start; row <=
end; ++row )
672 const bool checkcur = inBoundaries( Qt::Vertical, curdp ) && inBoundaries( Qt::Horizontal, curdp );
673 const bool checkpred = inBoundaries( Qt::Vertical, predecessor ) && inBoundaries( Qt::Horizontal, predecessor );
674 const bool check = checkcur || checkpred;
675 if ( predecessor.
distance( curdp ) > m_mergeRadius && check )
677 if ( start > m_bufferlist[ dataset ].count() && !m_bufferlist[ dataset ].isEmpty() )
679 m_bufferlist[ dataset ].append( curdp );
681 else if ( !m_bufferlist[ dataset ].isEmpty() )
683 m_bufferlist[ dataset ].insert( row, curdp );
686 qreal minX = qMin( curdp.
key, m_boundary.first.x() );
687 qreal minY = qMin( curdp.
value, m_boundary.first.y() );
688 qreal maxX = qMax( curdp.
key, m_boundary.second.x() );
689 qreal maxY = qMax( curdp.
value, m_boundary.second.y() );
690 setBoundaries( qMakePair( QPointF( minX, minY ), QPointF( maxX, maxY ) ) );
695 emit m_parent->rowCountChanged();
702 if (
d->m_mode != value )
710 void PlotterDiagramCompressor::Private::setBoundaries(
const Boundaries & bound )
712 if ( bound != m_boundary )
715 emit m_parent->boundariesChanged();
719 void PlotterDiagramCompressor::Private::calculateDataBoundaries()
721 if ( !forcedBoundaries( Qt::Vertical ) || !forcedBoundaries( Qt::Horizontal ) )
723 qreal minX = std::numeric_limits<qreal>::quiet_NaN();
724 qreal minY = std::numeric_limits<qreal>::quiet_NaN();
725 qreal maxX = std::numeric_limits<qreal>::quiet_NaN();
726 qreal maxY = std::numeric_limits<qreal>::quiet_NaN();
727 for (
int dataset = 0; dataset < m_parent->datasetCount(); ++dataset )
729 for (
int row = 0; row < m_parent->rowCount(); ++ row )
732 minX = qMin( minX, dp.
key );
733 minY = qMin( minY, dp.
value );
734 maxX = qMax( dp.
key, maxX );
735 maxY = qMax( dp.
value, maxY );
736 Q_ASSERT( !ISNAN( minX ) );
737 Q_ASSERT( !ISNAN( minY ) );
738 Q_ASSERT( !ISNAN( maxX ) );
739 Q_ASSERT( !ISNAN( maxY ) );
742 if ( forcedBoundaries( Qt::Vertical ) )
744 minY = m_forcedYBoundaries.first;
745 maxY = m_forcedYBoundaries.second;
747 if ( forcedBoundaries( Qt::Horizontal ) )
749 minX = m_forcedXBoundaries.first;
750 maxX = m_forcedXBoundaries.second;
752 setBoundaries( qMakePair( QPointF( minX, minY ), QPointF( maxX, maxY ) ) );
756 QModelIndexList PlotterDiagramCompressor::Private::mapToModel(
const CachePosition &pos )
758 QModelIndexList indexes;
760 index = m_model->index( pos.
first, pos.
second * 2, QModelIndex() );
761 Q_ASSERT( index.isValid() );
763 index = m_model->index( pos.
first, pos.
second * 2 + 1, QModelIndex() );
764 Q_ASSERT( index.isValid() );
769 bool PlotterDiagramCompressor::Private::forcedBoundaries( Qt::Orientation orient )
const 771 if ( orient == Qt::Vertical )
772 return !ISNAN( m_forcedYBoundaries.first ) && !ISNAN( m_forcedYBoundaries.second );
774 return !ISNAN( m_forcedXBoundaries.first ) && !ISNAN( m_forcedXBoundaries.second );
777 void PlotterDiagramCompressor::Private::clearBuffer()
782 m_bufferlist.clear();
783 m_bufferlist.resize( m_parent->datasetCount() );
784 m_accumulatedDistances.clear();
785 m_accumulatedDistances.resize( m_parent->datasetCount() );
786 m_timeOfLastInvalidation = QDateTime::currentDateTime();
791 ,
d( new Private( this ) )
803 if ( direction == Qt::Vertical )
805 d->m_forcedYBoundaries = bounds;
809 d->m_forcedXBoundaries = bounds;
826 d->m_model->disconnect(
this );
827 d->m_model->disconnect(
d );
834 d->calculateDataBoundaries();
835 connect(
d->m_model, SIGNAL( rowsInserted ( QModelIndex,
int,
int ) ),
d, SLOT( rowsInserted( QModelIndex,
int,
int ) ) );
836 connect(
d->m_model, SIGNAL( modelReset() ),
d, SLOT( clearBuffer() ) );
837 connect(
d->m_model, SIGNAL( destroyed(
QObject* ) ),
d, SLOT( setModelToZero() ) );
844 QModelIndexList indexes =
d->mapToModel( pos );
845 Q_ASSERT( indexes.count() == 2 );
846 QVariant yValue =
d->m_model->data( indexes.last() );
847 QVariant xValue =
d->m_model->data( indexes.first() );
848 Q_ASSERT( xValue.isValid() );
849 Q_ASSERT( yValue.isValid() );
851 point.
key = xValue.toReal( &ok );
854 point.
value = yValue.toReal( &ok );
856 point.
index = indexes.first();
862 if (
d->m_mergeRadius != radius )
864 d->m_mergeRadius = radius;
872 if (
d->m_maxSlopeRadius != value )
874 d->m_maxSlopeRadius = value;
881 return d->m_maxSlopeRadius;
887 const qreal width = radius * ( bounds.second.x() - bounds.first.x() );
888 const qreal height = radius * ( bounds.second.y() - bounds.first.y() );
889 const qreal realRadius = std::sqrt( width * height );
895 return d->m_model ?
d->m_model->rowCount() : 0;
905 if (
d->m_model &&
d->m_model->columnCount() == 0 )
907 return d->m_model ? (
d->m_model->columnCount() + 1 ) / 2 : 0;
912 Boundaries bounds =
d->m_boundary;
913 if (
d->forcedBoundaries( Qt::Vertical ) )
915 bounds.first.setY(
d->m_forcedYBoundaries.first );
916 bounds.second.setY(
d->m_forcedYBoundaries.second );
918 if (
d->forcedBoundaries( Qt::Horizontal ) )
920 bounds.first.setX(
d->m_forcedXBoundaries.first );
921 bounds.second.setX(
d->m_forcedXBoundaries.second );
928 Q_ASSERT( dataSet >= 0 && dataSet < d->m_bufferlist.count() );
929 return Iterator( dataSet,
this,
d->m_bufferlist[ dataSet ] );
qreal distance(const DataPoint &other)
void setModel(QAbstractItemModel *model)
void setMergeRadiusPercentage(qreal radius)
DataPoint data(const CachePosition &pos) const
bool inBoundary(const QPair< qreal, qreal > &bounds, qreal value)
Iterator end(int dataSet)
PlotterDiagramCompressor(QObject *parent=0)
Iterator & operator+=(int value)
void setMaxSlopeChange(qreal value)
bool operator==(const Iterator &other) const
QAbstractItemModel * model() const
void setMergeRadius(qreal radius)
void setCompressionModel(CompressionMode value)
Iterator & operator-=(int value)
~PlotterDiagramCompressor() override
QPair< QPointF, QPointF > dataBoundaries() const
qreal calculateSlope(const PlotterDiagramCompressor::DataPoint &lhs, const PlotterDiagramCompressor::DataPoint &rhs)
Class only listed here to document inheritance of some KDChart classes.
Iterator(int dataSet, PlotterDiagramCompressor *parent)
void setForcedDataBoundaries(const QPair< qreal, qreal > &bounds, Qt::Orientation direction)
Iterator begin(int dataSet)
bool operator!=(const Iterator &other) const
qreal maxSlopeChange() const