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 "KChartNormalPlotter_p.h"
0010 #include "KChartPlotter.h"
0011 #include "PaintingHelpers_p.h"
0012 
0013 #include <limits>
0014 
0015 using namespace KChart;
0016 using namespace std;
0017 
0018 NormalPlotter::NormalPlotter( Plotter* d )
0019     : PlotterType( d )
0020 {
0021 }
0022 
0023 Plotter::PlotType NormalPlotter::type() const
0024 {
0025     return Plotter::Normal;
0026 }
0027 
0028 const QPair< QPointF, QPointF > NormalPlotter::calculateDataBoundaries() const
0029 {
0030     if ( diagram()->useDataCompression() != Plotter::NONE )
0031         return plotterCompressor().dataBoundaries();
0032     else
0033         return compressor().dataBoundaries();
0034 }
0035 
0036 void NormalPlotter::paint( PaintContext* ctx )
0037 {
0038     reverseMapper().clear();
0039 
0040     Q_ASSERT( dynamic_cast< CartesianCoordinatePlane* >( ctx->coordinatePlane() ) );
0041     const CartesianCoordinatePlane* const plane = static_cast< CartesianCoordinatePlane* >( ctx->coordinatePlane() );
0042     const int colCount = compressor().modelDataColumns();
0043     const int rowCount = compressor().modelDataRows();    
0044 
0045     LabelPaintCache lpc;
0046 
0047     if ( diagram()->useDataCompression() != Plotter::NONE )
0048     {
0049         for ( int dataset = 0; dataset < plotterCompressor().datasetCount(); ++dataset )
0050         {
0051             LineAttributesInfoList lineList;
0052             PlotterDiagramCompressor::DataPoint lastPoint;
0053             for ( PlotterDiagramCompressor::Iterator it = plotterCompressor().begin( dataset ); it != plotterCompressor().end( dataset ); ++ it )
0054             {
0055                 const PlotterDiagramCompressor::DataPoint point = *it;
0056 
0057                 const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index );
0058                 LineAttributes laCell = diagram()->lineAttributes( sourceIndex );
0059                 const LineAttributes::MissingValuesPolicy policy = laCell.missingValuesPolicy();
0060 
0061                 if ( ISNAN( point.key ) || ISNAN( point.value ) )
0062                 {
0063                     switch ( policy )
0064                     {
0065                     case LineAttributes::MissingValuesAreBridged: // we just bridge both values
0066                         continue;
0067                     case LineAttributes::MissingValuesShownAsZero: // fall-through since that attribute makes no sense for the plotter
0068                     case LineAttributes::MissingValuesHideSegments: // fall-through since they're just hidden
0069                     default:
0070                         lastPoint = PlotterDiagramCompressor::DataPoint();
0071                         continue;
0072                     }
0073                 }
0074 
0075                 // data area painting: a and b are prev / current data points, c and d are on the null line
0076                 const QPointF b( plane->translate( QPointF( point.key, point.value ) ) );
0077 
0078                 if ( !point.hidden && PaintingHelpers::isFinite( b )  ) {
0079                     const QPointF a( plane->translate( QPointF( lastPoint.key, lastPoint.value ) ) );
0080                     const QPointF c( plane->translate( QPointF( lastPoint.key, 0.0 ) ) );
0081                     const QPointF d( plane->translate( QPointF( point.key, 0.0 ) ) );
0082 
0083                     // data point label
0084                     const PositionPoints pts = PositionPoints( b, a, d, c );
0085                     m_private->addLabel( &lpc, sourceIndex, nullptr, pts, Position::NorthWest,
0086                                          Position::NorthWest, point.value );
0087 
0088                     const bool lineValid = a.toPoint() != b.toPoint() && PaintingHelpers::isFinite( a );
0089                     if ( lineValid ) {
0090                         // data line
0091                         lineList.append( LineAttributesInfo( sourceIndex, a, b ) );
0092 
0093                         if ( laCell.displayArea() ) {
0094                             // data area
0095                             QList<QPolygonF> areas;
0096                             QPolygonF polygon;
0097                             polygon << a << b << d << c;
0098                             areas << polygon;
0099                             PaintingHelpers::paintAreas( m_private, ctx,
0100                                                          attributesModel()->mapToSource( lastPoint.index ),
0101                                                          areas, laCell.transparency() );
0102                         }
0103                     }
0104                 }
0105 
0106                 lastPoint = point;
0107             }
0108             PaintingHelpers::paintElements( m_private, ctx, lpc, lineList );
0109         }
0110     }
0111     else
0112     {
0113         if ( colCount == 0 || rowCount == 0 )
0114             return;
0115         for ( int column = 0; column < colCount; ++column )
0116         {
0117             LineAttributesInfoList lineList;
0118             CartesianDiagramDataCompressor::DataPoint lastPoint;
0119 
0120             for ( int row = 0; row < rowCount; ++row )
0121             {
0122                 const CartesianDiagramDataCompressor::CachePosition position( row, column );
0123                 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
0124 
0125                 const QModelIndex sourceIndex = attributesModel()->mapToSource( point.index );
0126                 LineAttributes laCell = diagram()->lineAttributes( sourceIndex );
0127                 const LineAttributes::MissingValuesPolicy policy = laCell.missingValuesPolicy();
0128 
0129                 if ( ISNAN( point.key ) || ISNAN( point.value ) )
0130                 {
0131                     switch ( policy )
0132                     {
0133                     case LineAttributes::MissingValuesAreBridged: // we just bridge both values
0134                         continue;
0135                     case LineAttributes::MissingValuesShownAsZero: // fall-through since that attribute makes no sense for the plotter
0136                     case LineAttributes::MissingValuesHideSegments: // fall-through since they're just hidden
0137                     default:
0138                         lastPoint = CartesianDiagramDataCompressor::DataPoint();
0139                         continue;
0140                     }
0141                 }
0142 
0143                 // data area painting: a and b are prev / current data points, c and d are on the null line
0144                 const QPointF b( plane->translate( QPointF( point.key, point.value ) ) );
0145 
0146                 if ( !point.hidden && PaintingHelpers::isFinite( b )  ) {
0147                     const QPointF a( plane->translate( QPointF( lastPoint.key, lastPoint.value ) ) );
0148                     const QPointF c( plane->translate( QPointF( lastPoint.key, 0.0 ) ) );
0149                     const QPointF d( plane->translate( QPointF( point.key, 0.0 ) ) );
0150 
0151                     // data point label
0152                     const PositionPoints pts = PositionPoints( b, a, d, c );
0153                     m_private->addLabel( &lpc, sourceIndex, nullptr, pts, Position::NorthWest,
0154                                          Position::NorthWest, point.value );
0155 
0156                     const bool lineValid = a.toPoint() != b.toPoint() && PaintingHelpers::isFinite( a );
0157                     if ( lineValid ) {
0158                         // data line
0159                         lineList.append( LineAttributesInfo( sourceIndex, a, b ) );
0160 
0161                         if ( laCell.displayArea() ) {
0162                             // data area
0163                             QList<QPolygonF> areas;
0164                             QPolygonF polygon;
0165                             polygon << a << b << d << c;
0166                             areas << polygon;
0167                             PaintingHelpers::paintAreas( m_private, ctx,
0168                                                          attributesModel()->mapToSource( lastPoint.index ),
0169                                                          areas, laCell.transparency() );
0170                         }
0171                     }
0172                 }
0173 
0174                 lastPoint = point;
0175             }
0176             PaintingHelpers::paintElements( m_private, ctx, lpc, lineList );
0177         }
0178     }
0179 }