File indexing completed on 2024-06-09 04:18:33

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 "KChartTernaryLineDiagram.h"
0010 #include "KChartTernaryLineDiagram_p.h"
0011 
0012 #include <limits>
0013 
0014 #include <QPainter>
0015 
0016 #include <KChartPaintContext.h>
0017 
0018 #include "KChartLineAttributes.h"
0019 #include "KChartDataValueAttributes.h"
0020 #include "KChartMarkerAttributes.h"
0021 #include "TernaryPoint.h"
0022 #include "TernaryConstants.h"
0023 #include "KChartPainterSaver_p.h"
0024 
0025 using namespace KChart;
0026 
0027 #define d d_func()
0028 
0029 TernaryLineDiagram::Private::Private()
0030     : AbstractTernaryDiagram::Private()
0031 {
0032 }
0033 
0034 TernaryLineDiagram::TernaryLineDiagram ( QWidget* parent,
0035                                          TernaryCoordinatePlane* plane )
0036     : AbstractTernaryDiagram( new Private(), parent, plane )
0037 {
0038     init();
0039     setDatasetDimensionInternal( 3 ); // the third column is implicit
0040 
0041     DataValueAttributes dataValueAttributes;
0042     dataValueAttributes.setVisible( true );
0043     MarkerAttributes markerAttributes;
0044     markerAttributes.setMarkerStyle( MarkerAttributes::MarkerCircle );
0045     markerAttributes.setVisible( true );
0046     dataValueAttributes.setMarkerAttributes( markerAttributes );
0047     attributesModel()->setDefaultForRole(
0048         KChart::DataValueLabelAttributesRole,
0049         QVariant::fromValue( dataValueAttributes ) );
0050 }
0051 
0052 TernaryLineDiagram::~TernaryLineDiagram()
0053 {
0054 }
0055 
0056 void TernaryLineDiagram::init()
0057 {
0058 }
0059 
0060 void  TernaryLineDiagram::resize (const QSizeF& area)
0061 {
0062     AbstractTernaryDiagram::resize( area );
0063 }
0064 
0065 void  TernaryLineDiagram::paint (PaintContext *paintContext)
0066 {
0067     d->reverseMapper.clear();
0068 
0069     d->paint( paintContext );
0070     // sanity checks:
0071     if ( model() == nullptr ) return;
0072 
0073     QPainter* p = paintContext->painter();
0074     PainterSaver s( p );
0075 
0076     TernaryCoordinatePlane* plane =
0077         (TernaryCoordinatePlane*) paintContext->coordinatePlane();
0078     Q_ASSERT( plane );
0079 
0080     qreal x, y, z;
0081 
0082     // for some reason(?) TernaryPointDiagram is using per-diagram DVAs only:
0083     const DataValueAttributes attrs( dataValueAttributes() );
0084 
0085     d->forgetAlreadyPaintedDataValues();
0086 
0087     int columnCount = model()->columnCount( rootIndex() );
0088     QPointF start;
0089     for (int column=0; column<columnCount; column+=datasetDimension() )
0090     {
0091         int numrows = model()->rowCount( rootIndex() );
0092         for ( int row = 0; row < numrows; row++ )
0093         {
0094             // see if there is data otherwise skip
0095             QModelIndex base = model()->index( row, column ); // checked
0096             if ( ! model()->data( base ).isNull() )
0097             {
0098                 p->setPen( PrintingParameters::scalePen( pen( base ) ) );
0099                 p->setBrush( brush( base ) );
0100 
0101                 // retrieve data
0102                 x = qMax<qreal>( model()->data( model()->index( row, column, rootIndex() ) ).toReal(), // checked
0103                           0.0 );
0104                 y = qMax<qreal>( model()->data( model()->index( row, column+1, rootIndex() ) ).toReal(), // checked
0105                           0.0 );
0106                 z = qMax<qreal>( model()->data( model()->index( row, column+2, rootIndex() ) ).toReal(), // checked
0107                           0.0 );
0108 
0109                 qreal total = x + y + z;
0110                 if ( fabs( total ) > 3 * std::numeric_limits<qreal>::epsilon() ) {
0111                     TernaryPoint tPunkt( x / total, y / total );
0112                     QPointF diagramLocation = translate( tPunkt );
0113                     QPointF widgetLocation = plane->translate( diagramLocation );
0114 
0115                     if ( row > 0 ) {
0116                         p->drawLine( start, widgetLocation );
0117                     }
0118                     paintMarker( p, model()->index( row, column, rootIndex() ), widgetLocation ); // checked
0119                     start = widgetLocation;
0120                     // retrieve text and data value attributes
0121                     // FIXME use data model DisplayRole text
0122                     QString text = tr( "(%1, %2, %3)", "(x, y, z) values of the data point" )
0123                                    .arg( x * 100, 0, 'f', 0 )
0124                                    .arg( y * 100, 0, 'f', 0 )
0125                                    .arg( z * 100, 0, 'f', 0 );
0126                     d->paintDataValueText( p, attrs, widgetLocation, true, text, true );
0127                 } else {
0128                     // ignore and do not paint this point, garbage data
0129                     qDebug() << "TernaryPointDiagram::paint: data point x/y/z:"
0130                              << x << "/" << y << "/" << z << "ignored, unusable.";
0131                 }
0132             }
0133         }
0134     }
0135 }
0136 
0137 const QPair< QPointF, QPointF >  TernaryLineDiagram::calculateDataBoundaries () const
0138 {
0139     // this is a constant, because we defined it to be one:
0140     static QPair<QPointF, QPointF> Boundaries(
0141         TriangleBottomLeft,
0142         QPointF( TriangleBottomRight.x(), TriangleHeight ) );
0143     return Boundaries;
0144 }