File indexing completed on 2024-12-15 04:02:26

0001 /*
0002  * SPDX-FileCopyrightText: 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
0003  *
0004  * This file is part of the KD Chart library.
0005  *
0006  * SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #include "KChartNormalLineDiagram_p.h"
0010 #include <limits>
0011 
0012 #include <QAbstractItemModel>
0013 
0014 #include "KChartBarDiagram.h"
0015 #include "KChartLineDiagram.h"
0016 #include "KChartTextAttributes.h"
0017 #include "KChartAttributesModel.h"
0018 #include "KChartAbstractCartesianDiagram.h"
0019 #include "PaintingHelpers_p.h"
0020 
0021 using namespace KChart;
0022 using namespace std;
0023 
0024 NormalLineDiagram::NormalLineDiagram( LineDiagram* d )
0025     : LineDiagramType( d )
0026 {
0027 }
0028 
0029 LineDiagram::LineType NormalLineDiagram::type() const
0030 {
0031     return LineDiagram::Normal;
0032 }
0033 
0034 const QPair< QPointF, QPointF > NormalLineDiagram::calculateDataBoundaries() const
0035 {
0036     return compressor().dataBoundaries();
0037 }
0038 
0039 void NormalLineDiagram::paint( PaintContext* ctx )
0040 {
0041     reverseMapper().clear();
0042     Q_ASSERT( dynamic_cast<CartesianCoordinatePlane*>( ctx->coordinatePlane() ) );
0043     CartesianCoordinatePlane* plane = static_cast<CartesianCoordinatePlane*>( ctx->coordinatePlane() );
0044     const int columnCount = compressor().modelDataColumns();
0045     const int rowCount = compressor().modelDataRows();
0046     if ( columnCount == 0 || rowCount == 0 ) return; // maybe blank out the area?
0047 
0048     // Reverse order of data sets?
0049     bool rev = diagram()->reverseDatasetOrder();
0050     LabelPaintCache lpc;
0051     LineAttributesInfoList lineList;
0052 
0053     const int step = rev ? -1 : 1;
0054     const int end = rev ? -1 : columnCount;
0055     for ( int column = rev ? columnCount - 1 : 0; column != end; column += step ) {
0056         LineAttributes laPreviousCell;
0057         CartesianDiagramDataCompressor::DataPoint lastPoint;
0058         qreal lastAreaBoundingValue = 0;
0059 
0060         // Get min. y value, used as lower or upper bounding for area highlighting
0061         const qreal minYValue = qMin(plane->visibleDataRange().bottom(), plane->visibleDataRange().top());
0062 
0063         CartesianDiagramDataCompressor::CachePosition previousCellPosition;
0064         for ( int row = 0; row < rowCount; ++row ) {
0065             const CartesianDiagramDataCompressor::CachePosition position( row, column );
0066             // get where to draw the line from:
0067             CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
0068             if ( point.hidden ) {
0069                 continue;
0070             }
0071 
0072             const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index );
0073 
0074             const LineAttributes laCell = diagram()->lineAttributes( sourceIndex );
0075             const LineAttributes::MissingValuesPolicy policy = laCell.missingValuesPolicy();
0076 
0077             // lower or upper bounding for the highlighted area
0078             qreal areaBoundingValue;
0079             if ( laCell.areaBoundingDataset() != -1 ) {
0080                 const CartesianDiagramDataCompressor::CachePosition areaBoundingCachePosition( row, laCell.areaBoundingDataset() );
0081                 areaBoundingValue = compressor().data( areaBoundingCachePosition ).value;
0082             } else {
0083                 // Use min. y value (i.e. zero line in most cases) if no bounding dataset is set
0084                 areaBoundingValue = minYValue;
0085             }
0086 
0087             if ( ISNAN( point.value ) )
0088             {
0089                 switch ( policy )
0090                 {
0091                 case LineAttributes::MissingValuesAreBridged:
0092                     // we just bridge both values
0093                     continue;
0094                 case LineAttributes::MissingValuesShownAsZero:
0095                     // set it to zero
0096                     point.value = 0.0;
0097                     break;
0098                 case LineAttributes::MissingValuesHideSegments:
0099                     // they're just hidden
0100                     break;
0101                 default:
0102                     break;
0103                     // hm....
0104                 }
0105             }
0106 
0107             if ( !ISNAN( point.value ) ) {
0108                 // area corners, a + b are the line ends:
0109                 const qreal offset = diagram()->centerDataPoints() ? 0.5 : 0;
0110                 const QPointF a( plane->translate( QPointF( lastPoint.key + offset, lastPoint.value ) ) );
0111                 const QPointF b( plane->translate( QPointF( point.key + offset, point.value ) ) );
0112                 const QPointF c( plane->translate( QPointF( lastPoint.key + offset, lastAreaBoundingValue ) ) );
0113                 const QPointF d( plane->translate( QPointF( point.key + offset, areaBoundingValue ) ) );
0114                 const PositionPoints pts = PositionPoints( b, a, d, c );
0115 
0116                 // add label
0117                 m_private->addLabel( &lpc, sourceIndex, &position, pts, Position::NorthWest,
0118                                      Position::NorthWest, point.value );
0119 
0120                 // add line and area, if switched on and we have a current and previous value
0121                 if ( !ISNAN( lastPoint.value ) ) {
0122                     lineList.append( LineAttributesInfo( sourceIndex, a, b ) );
0123 
0124                     if ( laCell.displayArea() ) {
0125                         QList<QPolygonF> areas;
0126                         areas << ( QPolygonF() << a << b << d << c );
0127                         PaintingHelpers::paintAreas( m_private, ctx, attributesModel()->mapToSource( lastPoint.index ),
0128                                                      areas, laCell.transparency() );
0129                     }
0130                 }
0131             }
0132 
0133             previousCellPosition = position;
0134             laPreviousCell = laCell;
0135             lastAreaBoundingValue = areaBoundingValue;
0136             lastPoint = point;
0137         }
0138     }
0139 
0140     // paint the lines
0141     PaintingHelpers::paintElements( m_private, ctx, lpc, lineList );
0142 }