KChart

KChartRadarGrid.cpp
1/*
2 * SPDX-FileCopyrightText: 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
3 *
4 * This file is part of the KD Chart library.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9#include "KChartRadarGrid.h"
10
11#include "KChartPaintContext.h"
12#include "KChartRadarDiagram.h"
13#include "KChartPieDiagram.h"
14#include "KChartPrintingParameters.h"
15#include "KChartMath_p.h"
16
17#include <QPainter>
18
19
20using namespace KChart;
21
22
23DataDimensionsList RadarGrid::calculateGrid(
24 const DataDimensionsList& rawDataDimensions ) const
25{
26 qDebug("Calling PolarGrid::calculateGrid()");
28
29 //FIXME(khz): do the real calculation
30
31 l = rawDataDimensions;
32
33 return l;
34}
35
36static qreal fitFontSizeToGeometry( const QString& text, const QFont& font, const QRectF& geometry, const TextAttributes& ta )
37{
38 QFont f = font;
39 const qreal origResult = f.pointSizeF();
40 qreal result = origResult;
41 const QSizeF mySize = geometry.size();
42 if ( mySize.isNull() )
43 return result;
44
45 const QString t = text;
46 QFontMetrics fm( f );
47 while ( true )
48 {
49 const QSizeF textSize = rotatedRect( fm.boundingRect( t ), ta.rotation() ).normalized().size();
50
51 if ( textSize.height() <= mySize.height() && textSize.width() <= mySize.width() )
52 return result;
53
54 result -= 0.5;
55 if ( result <= 0.0 )
56 return origResult;
57 f.setPointSizeF( result );
58 fm = QFontMetrics( f );
59 }
60}
61
62QPointF scaleToRealPosition( const QPointF& origin, const QRectF& sourceRect, const QRectF& destRect, const AbstractCoordinatePlane& plane )
63{
64 QPointF result = plane.translate( origin );
65 result -= sourceRect.topLeft();
66 result.setX( result.x() / sourceRect.width() * destRect.width() );
67 result.setY( result.y() / sourceRect.height() * destRect.height() );
68 result += destRect.topLeft();
69 return result;
70}
71
72QPointF scaleToRect( const QPointF& origin, const QRectF& sourceRect, const QRectF& destRect )
73{
74 QPointF result( origin );
75 result -= sourceRect.topLeft();
76 result.setX( result.x() / sourceRect.width() * destRect.width() );
77 result.setY( result.y() / sourceRect.height() * destRect.height() );
78 result += destRect.topLeft();
79 return result;
80}
81
83{
84 const QBrush backupBrush( context->painter()->brush() );
85 context->painter()->setBrush( QBrush() );
86 RadarCoordinatePlane* plane = dynamic_cast< RadarCoordinatePlane* >( context->coordinatePlane() );
87 Q_ASSERT( plane );
88 Q_ASSERT( plane->diagram() );
89 QPair< QPointF, QPointF > boundaries = plane->diagram()->dataBoundaries();
90 Q_ASSERT_X ( plane, "PolarGrid::drawGrid",
91 "Bad function call: PaintContext::coodinatePlane() NOT a polar plane." );
92
93 const GridAttributes gridAttrsCircular( plane->gridAttributes( true ) );
94 const GridAttributes gridAttrsSagittal( plane->gridAttributes( false ) );
95
96 //qDebug() << "OK:";
97 if ( !gridAttrsCircular.isGridVisible() && !gridAttrsSagittal.isGridVisible() ) return;
98 //qDebug() << "A";
99
100 // FIXME: we paint the rulers to the settings of the first diagram for now:
101 AbstractPolarDiagram* dgr = dynamic_cast<AbstractPolarDiagram*> (plane->diagrams().first() );
102 Q_ASSERT ( dgr ); // only polar diagrams are allowed here
103
104
105 // Do not draw a grid for pie diagrams
106 if ( dynamic_cast<PieDiagram*> (plane->diagrams().first() ) ) return;
107
108
109 context->painter()->setPen ( PrintingParameters::scalePen( QColor ( Qt::lightGray ) ) );
110 const qreal min = dgr->dataBoundaries().first.y();
111 QPointF origin = plane->translate( QPointF( min, 0 ) ) + context->rectangle().topLeft();
112 //qDebug() << "origin" << origin;
113
114 const qreal r = qAbs( min ) + dgr->dataBoundaries().second.y(); // use the full extents
115
116 // distance between two axis lines
117 const qreal step = ( r - qAbs( min ) ) / ( dgr->numberOfGridRings() );
118
119 // calculate the height needed for text to be displayed at the bottom and top of the chart
120 QPointF topLeft = context->rectangle().topLeft();
121 Q_ASSERT( plane->diagram()->model() );
122 TextAttributes ta = plane->textAttributes();
123 const int numberOfSpokes = ( int ) ( 360 / plane->angleUnit() );
124 const qreal stepWidth = boundaries.second.y() / ( dgr->numberOfGridRings() );
125 QRectF destRect = context->rectangle();
126 if (ta.isVisible() )
127 {
128 QAbstractItemModel* model = plane->diagram()->model();
129 QRectF fontRect = context->rectangle();
130 fontRect.setSize( QSizeF( fontRect.width(), step / 2.0 ) );
131 const qreal labelFontSize = fitFontSizeToGeometry( QString::fromLatin1( "TestXYWQgqy" ), ta.font(), fontRect, ta );
132 QFont labelFont = ta.font();
133 context->painter()->setPen( ta.pen() );
134 labelFont.setPointSizeF( labelFontSize );
135 const QFontMetricsF metric( labelFont );
136 const qreal labelHeight = metric.height();
137 QPointF offset;
138 destRect.setY( destRect.y() + 2 * labelHeight );
139 destRect.setHeight( destRect.height() - 4 * labelHeight );
140 offset.setY( labelHeight );
141 offset.setX( 0 );
142 topLeft += offset;
143 origin += offset;
144 origin = scaleToRealPosition( QPointF( min, 0 ), context->rectangle(), destRect, *plane );
145
146 const qreal aWidth = metric.boundingRect( QString::fromLatin1( "A" ) ).width();
147 const QLineF startLine( origin, scaleToRealPosition( QPointF( r - qAbs( min ), 0 ), context->rectangle(), destRect, *plane ) );
148 for ( int i = 0; i < model->rowCount(); ++i )
149 {
150 const QLineF currentLine( origin, scaleToRealPosition( QPointF( r - qAbs( min ), i ), context->rectangle(), destRect, *plane ) );
151 const int angle = ( int ) startLine.angleTo( currentLine ) % 360;
152 const qreal angleTest = qAbs( angle - 180 );
153 const QString data = model->headerData( i, Qt::Vertical ).toString();
154 const qreal xOffset = metric.boundingRect( data ).width() / 2.0;
155 if ( angleTest < 5.0 )
156 context->painter()->drawText( currentLine.pointAt( 1 ) + QPointF( -xOffset, labelHeight + qAbs( min ) ) , data );
157 else if ( qAbs( angleTest - 180 ) < 5.0 )
158 context->painter()->drawText( currentLine.pointAt( 1 ) - QPointF( xOffset, labelHeight + qAbs( min ) ) , data );
159 else if ( angle < 175 && angle > 5 )
160 context->painter()->drawText( currentLine.pointAt( 1 ) - QPointF( xOffset * 2 + qAbs( min ) + aWidth, -labelHeight/ 2.0 + qAbs( min ) ) , data );
161 else if ( angle < 355 && angle > 185 )
162 context->painter()->drawText( currentLine.pointAt( 1 ) + QPointF( qAbs( min ) + aWidth, labelHeight/ 2.0 + qAbs( min ) ) , data );
163
164 }
165 }
166 context->painter()->setPen ( PrintingParameters::scalePen( QColor ( Qt::lightGray ) ) );
167 if ( plane->globalGridAttributes().isGridVisible() )
168 {
169 for ( int j = 1; j < dgr->numberOfGridRings() + 1; ++j )
170 {
171 QPointF oldPoint( scaleToRealPosition( QPointF( j * step - qAbs( min ), numberOfSpokes - 1 ), context->rectangle(), destRect, *plane ) );
172 for ( int i = 0; i < numberOfSpokes ; ++i ) {
173 const QPointF newPoint = scaleToRealPosition( QPointF( j * step - qAbs( min ), i ), context->rectangle(), destRect, *plane );
174 context->painter()->drawLine( oldPoint, newPoint );
175 oldPoint = newPoint;
176
177 context->painter()->drawLine( origin, newPoint );
178 }
179 }
180 context->painter()->setPen( ta.pen() );
181 qreal fontSize = 0;
182 for ( int i = 0; i < dgr->numberOfGridRings() + 1; ++i )
183 {
184 const QString text = QString::number( i * stepWidth );
185 const QPointF translatedPoint = scaleToRealPosition( QPointF( i * step - qAbs( min ), 0 ), context->rectangle(), destRect, *plane );
186 const QFontMetrics metric( ta.font()/*QFont( "Arial", 10 )*/ );
187 const qreal textLength = metric.boundingRect( text ).width();
188 const qreal textHeight = metric.height() / 2.0;
189 QPointF textOffset( textLength, -textHeight );
190 textOffset = scaleToRect( textOffset, context->rectangle(), destRect );
191 QPointF _topLeft = topLeft;
192 _topLeft.setY( translatedPoint.y() );
193 QRectF boundary( _topLeft, ( translatedPoint + QPointF( 0, step / 2.0 ) ) );
194 const qreal calcFontSize = fitFontSizeToGeometry( text, ta.font(), boundary, ta );
195 if ( fontSize != calcFontSize )
196 {
197 QFont paintFont( ta.font() );
198 paintFont.setPointSizeF( calcFontSize );
199 ta.setFont( paintFont );
200 ta.setFontSize( calcFontSize );
201 const qreal textHeight2 = QFontMetricsF( paintFont ).height() / 2.0;
202 textOffset.setY( - textHeight2 );
203 textOffset = scaleToRect( textOffset, context->rectangle(), destRect );
204 context->painter()->setFont( paintFont );
205 fontSize = calcFontSize;
206 }
207 context->painter()->drawText( translatedPoint + destRect.topLeft() - textOffset, text );
208
209 }
210 }
211 plane->setTextAttributes( ta );
212 context->painter()->setPen ( PrintingParameters::scalePen( QColor ( Qt::lightGray ) ) );
213 context->painter()->setBrush( backupBrush );
214}
Base class common for all coordinate planes, CartesianCoordinatePlane, PolarCoordinatePlane,...
virtual const QPointF translate(const QPointF &diagramPoint) const =0
Translate the given point in value space coordinates to a position in pixel space.
const QPair< QPointF, QPointF > dataBoundaries() const
Return the bottom left and top right data point, that the diagram will display (unless the grid adjus...
Base class for diagrams based on a polar coordinate system.
A set of attributes controlling the appearance of grids.
Stores information about painting diagrams.
PieDiagram defines a common pie diagram.
const GridAttributes gridAttributes(bool circular) const
const QPointF translate(const QPointF &diagramPoint) const override
Translate the given point in value space coordinates to a position in pixel space.
void setTextAttributes(const TextAttributes &attr)
Set the attributes to be used for axis captions.
const TextAttributes textAttributes() const
void drawGrid(PaintContext *context) override
Doing the actual drawing.
A set of text attributes.
void setFontSize(const Measure &measure)
Set the size of the font used for rendering text.
void setFont(const QFont &font)
Set the font to be used for rendering the text.
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const const
virtual int rowCount(const QModelIndex &parent) const const=0
QAbstractItemModel * model() const const
qreal pointSizeF() const const
void setPointSizeF(qreal pointSize)
QRect boundingRect(QChar ch) const const
int height() const const
QRectF boundingRect(QChar ch) const const
qreal height() const const
qreal angleTo(const QLineF &line) const const
QPointF pointAt(qreal t) const const
T & first()
const QBrush & brush() const const
void drawLine(const QLine &line)
void drawText(const QPoint &position, const QString &text)
void setBrush(Qt::BrushStyle style)
void setFont(const QFont &font)
void setPen(Qt::PenStyle style)
void setX(qreal x)
void setY(qreal y)
qreal x() const const
qreal y() const const
int width() const const
qreal height() const const
QRectF normalized() const const
void setHeight(qreal height)
void setSize(const QSizeF &size)
void setY(qreal y)
QSizeF size() const const
QPointF topLeft() const const
qreal width() const const
qreal y() const const
qreal height() const const
bool isNull() const const
qreal width() const const
QString fromLatin1(QByteArrayView str)
QString number(double n, char format, int precision)
lightGray
Vertical
QString toString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:51:58 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.