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 }