23 #include "KDChartStackedLineDiagram_p.h" 25 #include <QAbstractItemModel> 32 #include "PaintingHelpers_p.h" 38 : LineDiagramType( d )
49 const int rowCount = compressor().modelDataRows();
50 const int colCount = compressor().modelDataColumns();
52 qreal xMax = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0;
53 if ( !diagram()->centerDataPoints() && diagram()->model() )
55 qreal yMin = 0, yMax = 0;
57 bool bStarting =
true;
58 for (
int row = 0; row < rowCount; ++row )
61 qreal stackedValues = 0.0;
62 qreal negativeStackedValues = 0.0;
63 for (
int col = datasetDimension() - 1; col < colCount; col += datasetDimension() ) {
64 const CartesianDiagramDataCompressor::CachePosition position( row, col );
65 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
67 if ( ISNAN( point.value ) )
70 if ( point.value >= 0.0 )
71 stackedValues += point.value;
73 negativeStackedValues += point.value;
82 yMin = qMin( qMin( yMin, negativeStackedValues ), stackedValues );
83 yMax = qMax( qMax( yMax, negativeStackedValues ), stackedValues );
87 const QPointF bottomLeft( xMin, yMin );
88 const QPointF topRight( xMax, yMax );
95 if ( qFuzzyIsNull( m_private->tension ) ) {
96 paintWithLines( ctx );
99 paintWithSplines( ctx, m_private->tension );
103 void StackedLineDiagram::paintWithLines(
PaintContext* ctx )
105 reverseMapper().clear();
107 const int columnCount = compressor().modelDataColumns();
108 const int rowCount = compressor().modelDataRows();
123 LineAttributesInfoList lineList;
128 bool bFirstDataset =
true;
130 for (
int column = 0; column < columnCount; ++column )
132 CartesianDiagramDataCompressor::CachePosition previousCellPosition;
136 QModelIndex indexPreviousCell;
140 for (
int row = 0; row < rowCount; ++row ) {
141 const CartesianDiagramDataCompressor::CachePosition position( row, column );
142 CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
143 const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index );
145 const LineAttributes laCell = diagram()->lineAttributes( sourceIndex );
146 const bool bDisplayCellArea = laCell.
displayArea();
153 qreal stackedValues = 0, nextValues = 0, nextKey = 0;
154 for (
int column2 = column; column2 >= 0; --column2 )
156 const CartesianDiagramDataCompressor::CachePosition position( row, column2 );
157 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
158 if ( !ISNAN( point.value ) )
160 stackedValues += point.value;
164 const qreal interpolation = interpolateMissingValue( position );
165 if ( !ISNAN( interpolation ) )
166 stackedValues += interpolation;
170 if ( row + 1 < rowCount ) {
171 const CartesianDiagramDataCompressor::CachePosition position( row + 1, column2 );
172 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
173 if ( !ISNAN( point.value ) )
175 nextValues += point.value;
179 const qreal interpolation = interpolateMissingValue( position );
180 if ( !ISNAN( interpolation ) )
181 nextValues += interpolation;
187 const QPointF nextPoint = ctx->
coordinatePlane()->
translate( QPointF( diagram()->centerDataPoints() ? point.key + 0.5 : point.key, stackedValues ) );
190 const QPointF ptNorthWest( nextPoint );
191 const QPointF ptSouthWest(
195 : bottomPoints.at( row )
201 if ( row + 1 < rowCount ) {
202 QPointF toPoint = ctx->
coordinatePlane()->
translate( QPointF( diagram()->centerDataPoints() ? nextKey + 0.5 : nextKey, nextValues ) );
203 lineList.append( LineAttributesInfo( sourceIndex, nextPoint, toPoint ) );
204 ptNorthEast = toPoint;
209 : bottomPoints.at( row + 1 )
212 if ( areas.count() && laCell != laPreviousCell ) {
216 if ( bDisplayCellArea ) {
218 poly << ptNorthWest << ptNorthEast << ptSouthEast << ptSouthWest;
220 laPreviousCell = laCell;
221 indexPreviousCell = sourceIndex;
226 ptNorthEast = ptNorthWest;
227 ptSouthEast = ptSouthWest;
230 const PositionPoints pts( ptNorthWest, ptNorthEast, ptSouthEast, ptSouthWest );
231 if ( !ISNAN( point.value ) )
235 if ( areas.count() ) {
239 bottomPoints = points;
240 bFirstDataset =
false;
245 void StackedLineDiagram::paintWithSplines(
PaintContext* ctx, qreal tension )
247 reverseMapper().clear();
249 const int columnCount = compressor().modelDataColumns();
250 const int rowCount = compressor().modelDataRows();
252 Q_ASSERT(dynamic_cast<CartesianCoordinatePlane*>(ctx->
coordinatePlane()));
255 const auto reverseSplineDirection = plane->isHorizontalRangeReversed() ? NormalSplineDirection : ReverseSplineDirection;
270 LineAttributesInfoList lineList;
274 for (
int column = 0; column < columnCount; ++column )
276 CartesianDiagramDataCompressor::CachePosition previousCellPosition;
280 QModelIndex indexPreviousCell;
283 for (
int row = 0; row < rowCount; ++row ) {
284 const CartesianDiagramDataCompressor::CachePosition position( row, column );
285 CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
286 const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index );
288 const LineAttributes laCell = diagram()->lineAttributes( sourceIndex );
289 const bool bDisplayCellArea = laCell.
displayArea();
314 struct valueAtLambda {
316 : rowCount( rowCount )
323 StackedLineDiagram* _this;
326 qreal operator() (
int row,
int col )
const 328 if ( row < 0 || row >= rowCount ) {
332 const CartesianDiagramDataCompressor::CachePosition position( row, col );
333 const CartesianDiagramDataCompressor::DataPoint point = _this->compressor().data( position );
335 return !ISNAN( point.value ) ? point.value
341 valueAtLambda valueAt( rowCount,
this, policy );
344 struct safeAddLambda {
345 qreal operator() (qreal accumulator, qreal newValue)
const 347 return ISNAN( newValue ) ? accumulator : accumulator + newValue;
350 safeAddLambda safeAdd;
356 for (
int currentRow = 0; currentRow < 4; ++currentRow ) {
357 stackedValuesTop[currentRow] = safeAdd( stackedValuesTop[currentRow], valueAt( row - 1 + currentRow, column ) );
360 for (
int column2 = column - 1; column2 >= 0; --column2 )
362 for (
int currentRow = 0; currentRow < 4; ++currentRow ) {
363 stackedValuesTop[currentRow] = safeAdd( stackedValuesTop[currentRow], valueAt( row - 1 + currentRow, column2 ) );
364 stackedValuesBottom[currentRow] = safeAdd( stackedValuesBottom[currentRow], valueAt( row - 1 + currentRow, column2 ) );
374 struct dataAtLambda {
375 dataAtLambda(
PaintContext* ctx, StackedLineDiagram* _this )
382 StackedLineDiagram* _this;
384 QPointF operator() (
const QVector<qreal>& source, qreal key,
int index )
const 386 return ctx->
coordinatePlane()->
translate( QPointF( _this->diagram()->centerDataPoints() ? key + 0.5 : key, source[index] ) );
389 dataAtLambda dataAt( ctx,
this );
391 const QPointF ptNorthWest = dataAt( stackedValuesTop, point.key, 1 );
392 const QPointF ptSouthWest =
393 bDisplayCellArea ? dataAt( stackedValuesBottom, point.key, 1 )
399 if ( row + 1 < rowCount ) {
400 ptNorthEast = dataAt( stackedValuesTop, nextKey, 2 );
401 lineList.append( LineAttributesInfo( sourceIndex, ptNorthWest, ptNorthEast ) );
403 bDisplayCellArea ? dataAt( stackedValuesBottom, nextKey, 2 )
406 if ( areas.count() && laCell != laPreviousCell ) {
411 if ( bDisplayCellArea ) {
413 path.moveTo( ptNorthWest );
415 const QPointF ptBeforeNorthWest =
416 row > 0 ? dataAt( stackedValuesTop, point.key - 1, 0 )
418 const QPointF ptAfterNorthEast =
419 row < rowCount - 2 ? dataAt( stackedValuesTop, point.key + 2, 3 )
421 addSplineChunkTo( path, tension, ptBeforeNorthWest, ptNorthWest, ptNorthEast, ptAfterNorthEast, mainSplineDirection );
423 path.lineTo( ptNorthEast );
424 path.lineTo( ptSouthEast );
426 const QPointF ptBeforeSouthWest =
427 row > 0 ? dataAt( stackedValuesBottom, point.key - 1, 0 )
429 const QPointF ptAfterSouthEast =
430 row < rowCount - 2 ? dataAt( stackedValuesBottom, point.key + 2, 3 )
432 addSplineChunkTo( path, tension, ptAfterSouthEast, ptSouthEast, ptSouthWest, ptBeforeSouthWest, reverseSplineDirection );
435 laPreviousCell = laCell;
436 indexPreviousCell = sourceIndex;
441 ptNorthEast = ptNorthWest;
442 ptSouthEast = ptSouthWest;
445 const PositionPoints pts( ptNorthWest, ptNorthEast, ptSouthEast, ptSouthWest );
446 if ( !ISNAN( point.value ) )
450 if ( areas.count() ) {
KDChartEnums::PositionValue value() const
Returns an integer value corresponding to this Position.
void paintElements(AbstractDiagram::Private *diagramPrivate, PaintContext *ctx, const LabelPaintCache &lpc, const LineAttributesInfoList &lineList)
virtual const QPointF translate(const QPointF &diagramPoint) const =0
Translate the given point in value space coordinates to a position in pixel space.
AbstractCoordinatePlane * coordinatePlane() const
Set of attributes for changing the appearance of line charts.
bool isHorizontalRangeReversed() const
void paintAreas(AbstractDiagram::Private *diagramPrivate, PaintContext *ctx, const QModelIndex &index, const QList< QPolygonF > &areas, uint opacity)
static const Position & NorthWest
LineDiagram defines a common line diagram.
Stores information about painting diagrams.
Stores the absolute target points of a Position.
MissingValuesPolicy
MissingValuesPolicy specifies how a missing value will be shown in a line diagram.
Cartesian coordinate plane.
uint transparency() const
MissingValuesPolicy missingValuesPolicy() const