23 #include "KDChartPercentLineDiagram_p.h" 25 #include <QModelIndex> 32 #include "PaintingHelpers_p.h" 38 : LineDiagramType( d )
49 const qreal xMin = 0.0;
50 qreal xMax = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0;
51 if ( !diagram()->centerDataPoints() && diagram()->model() )
53 const qreal yMin = 0.0;
54 const qreal yMax = 100.0;
56 QPointF bottomLeft( QPointF( xMin, yMin ) );
57 QPointF topRight( QPointF( xMax, yMax ) );
63 if ( qFuzzyIsNull( m_private->tension ) ) {
64 paintWithLines( ctx );
67 paintWithSplines( ctx, m_private->tension );
71 void PercentLineDiagram::paintWithLines(
PaintContext* ctx )
73 reverseMapper().clear();
75 const int columnCount = compressor().modelDataColumns();
76 const int rowCount = compressor().modelDataRows();
87 maxFound = columnCount;
89 const int lastVisibleColumn = maxFound - 1;
92 LineAttributesInfoList lineList;
101 for (
int row = 0; row < rowCount; ++row )
103 for (
int col = 0; col < columnCount; ++col )
105 const CartesianDiagramDataCompressor::CachePosition position( row, col );
106 CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
107 const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index );
108 const LineAttributes laCell = diagram()->lineAttributes( sourceIndex );
111 point.value = interpolateMissingValue( position );
112 if ( point.value > 0 )
113 sumValues += point.value;
114 if ( col == lastVisibleColumn )
116 percentSumValues << sumValues ;
123 bool bFirstDataset =
true;
125 for (
int column = 0; column < columnCount; ++column )
129 QModelIndex indexPreviousCell;
133 for (
int row = 0; row < rowCount; ++row )
135 const CartesianDiagramDataCompressor::CachePosition position( row, column );
136 CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
137 const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index );
138 const LineAttributes laCell = diagram()->lineAttributes( sourceIndex );
139 const bool bDisplayCellArea = laCell.
displayArea();
141 qreal stackedValues = 0, nextValues = 0, nextKey = 0;
142 for (
int column2 = column;
146 const CartesianDiagramDataCompressor::CachePosition position( row, column2 );
147 CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
151 point.value = interpolateMissingValue( position );
153 const qreal val = point.value;
155 stackedValues += val;
157 if ( row + 1 < rowCount ) {
158 const CartesianDiagramDataCompressor::CachePosition position( row + 1, column2 );
159 CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
163 point.value = interpolateMissingValue( position );
165 const qreal val = point.value;
171 if ( percentSumValues.at( row ) != 0 )
172 stackedValues = stackedValues / percentSumValues.at( row ) * maxValue;
176 QPointF nextPoint = ctx->
coordinatePlane()->
translate( QPointF( diagram()->centerDataPoints() ? point.key + 0.5 : point.key, stackedValues ) );
179 const QPointF ptNorthWest( nextPoint );
180 const QPointF ptSouthWest(
184 : bottomPoints.at( row )
190 if ( row + 1 < rowCount ) {
191 if ( percentSumValues.at( row + 1 ) != 0 )
192 nextValues = nextValues / percentSumValues.at( row + 1 ) * maxValue;
195 QPointF toPoint = ctx->
coordinatePlane()->
translate( QPointF( diagram()->centerDataPoints() ? nextKey + 0.5 : nextKey, nextValues ) );
196 lineList.append( LineAttributesInfo( sourceIndex, nextPoint, toPoint ) );
197 ptNorthEast = toPoint;
202 : bottomPoints.at( row + 1 )
205 if ( areas.count() && laCell != laPreviousCell ) {
209 if ( bDisplayCellArea ) {
211 poly << ptNorthWest << ptNorthEast << ptSouthEast << ptSouthWest;
213 laPreviousCell = laCell;
214 indexPreviousCell = sourceIndex;
219 ptNorthEast = ptNorthWest;
220 ptSouthEast = ptSouthWest;
223 if ( !ISNAN( point.value ) )
225 const PositionPoints pts( ptNorthWest, ptNorthEast, ptSouthEast, ptSouthWest );
230 if ( areas.count() ) {
234 bottomPoints = points;
235 bFirstDataset =
false;
240 void PercentLineDiagram::paintWithSplines(
PaintContext* ctx, qreal tension )
242 reverseMapper().clear();
244 const int columnCount = compressor().modelDataColumns();
245 const int rowCount = compressor().modelDataRows();
247 Q_ASSERT(dynamic_cast<CartesianCoordinatePlane*>(ctx->
coordinatePlane()));
250 const auto reverseSplineDirection = plane->isHorizontalRangeReversed() ? NormalSplineDirection : ReverseSplineDirection;
261 maxFound = columnCount;
263 const int lastVisibleColumn = maxFound - 1;
266 LineAttributesInfoList lineList;
270 qreal maxValue = 100;
275 for (
int row = 0; row < rowCount; ++row )
277 for (
int col = 0; col < columnCount; ++col )
279 const CartesianDiagramDataCompressor::CachePosition position( row, col );
280 CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
281 const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index );
282 const LineAttributes laCell = diagram()->lineAttributes( sourceIndex );
285 point.value = interpolateMissingValue( position );
286 if ( point.value > 0 )
287 sumValues += point.value;
288 if ( col == lastVisibleColumn )
290 percentSumValues << sumValues ;
296 for (
int column = 0; column < columnCount; ++column )
298 CartesianDiagramDataCompressor::CachePosition previousCellPosition;
302 QModelIndex indexPreviousCell;
305 for (
int row = 0; row < rowCount; ++row ) {
306 const CartesianDiagramDataCompressor::CachePosition position( row, column );
307 CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
308 const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index );
310 const LineAttributes laCell = diagram()->lineAttributes( sourceIndex );
311 const bool bDisplayCellArea = laCell.
displayArea();
321 struct valueAtLambda {
323 : rowCount( rowCount )
330 PercentLineDiagram* _this;
333 qreal operator() (
int row,
int col )
const 335 if ( row < 0 || row >= rowCount ) {
339 const CartesianDiagramDataCompressor::CachePosition position( row, col );
340 const CartesianDiagramDataCompressor::DataPoint point = _this->compressor().data( position );
342 return !ISNAN( point.value ) ? point.value
348 valueAtLambda valueAt( rowCount,
this, policy );
351 struct safeAddLambda {
352 qreal operator() (qreal accumulator, qreal newValue)
const 354 return ISNAN( newValue ) ? accumulator : accumulator + newValue;
357 safeAddLambda safeAdd;
363 for (
int currentRow = 0; currentRow < 4; ++currentRow ) {
364 stackedValuesTop[currentRow] = safeAdd( stackedValuesTop[currentRow], valueAt( row - 1 + currentRow, column ) );
367 for (
int column2 = column - 1; column2 >= 0; --column2 )
369 for (
int currentRow = 0; currentRow < 4; ++currentRow ) {
370 stackedValuesTop[currentRow] = safeAdd( stackedValuesTop[currentRow], valueAt( row - 1 + currentRow, column2 ) );
371 stackedValuesBottom[currentRow] = safeAdd( stackedValuesBottom[currentRow], valueAt( row - 1 + currentRow, column2 ) );
379 struct dataAtLambda {
380 dataAtLambda(
PaintContext* ctx, PercentLineDiagram* _this )
387 PercentLineDiagram* _this;
389 QPointF operator() (
const QVector<qreal>& source, qreal key,
int index, qreal scale )
const 391 return ctx->
coordinatePlane()->
translate( QPointF( _this->diagram()->centerDataPoints() ? key + 0.5 : key, source[index] * scale ) );
394 dataAtLambda dataAt( ctx,
this );
396 const auto scale = qFuzzyIsNull( percentSumValues.at( row ) ) ? 0 : maxValue / percentSumValues.at( row );
397 const QPointF ptNorthWest = dataAt( stackedValuesTop, point.key, 1, scale );
398 const QPointF ptSouthWest =
399 bDisplayCellArea ? dataAt( stackedValuesBottom, point.key, 1, scale )
405 if ( row + 1 < rowCount ) {
406 const auto nextScale = qFuzzyIsNull ( percentSumValues.at( row + 1 ) ) ? 0 : maxValue / percentSumValues.at ( row + 1 );
407 ptNorthEast = dataAt( stackedValuesTop, nextKey, 2, nextScale );
408 lineList.append( LineAttributesInfo( sourceIndex, ptNorthWest, ptNorthEast ) );
410 bDisplayCellArea ? dataAt( stackedValuesBottom, nextKey, 2, nextScale )
413 if ( areas.count() && laCell != laPreviousCell ) {
418 if ( bDisplayCellArea ) {
420 path.moveTo( ptNorthWest );
422 const QPointF ptBeforeNorthWest =
423 row > 0 ? dataAt( stackedValuesTop, point.key - 1, 0, scale )
425 const QPointF ptAfterNorthEast =
426 row < rowCount - 2 ? dataAt( stackedValuesTop, point.key + 2, 3, nextScale )
428 addSplineChunkTo( path, tension, ptBeforeNorthWest, ptNorthWest, ptNorthEast, ptAfterNorthEast, mainSplineDirection );
430 path.lineTo( ptNorthEast );
431 path.lineTo( ptSouthEast );
433 const QPointF ptBeforeSouthWest =
434 row > 0 ? dataAt( stackedValuesBottom, point.key - 1, 0, scale )
436 const QPointF ptAfterSouthEast =
437 row < rowCount - 2 ? dataAt( stackedValuesBottom, point.key + 2, 3, nextScale )
439 addSplineChunkTo( path, tension, ptAfterSouthEast, ptSouthEast, ptSouthWest, ptBeforeSouthWest, reverseSplineDirection );
442 laPreviousCell = laCell;
443 indexPreviousCell = sourceIndex;
448 ptNorthEast = ptNorthWest;
449 ptSouthEast = ptSouthWest;
452 const PositionPoints pts( ptNorthWest, ptNorthEast, ptSouthEast, ptSouthWest );
453 if ( !ISNAN( point.value ) )
457 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