KChart

KChartPolarDiagram.cpp
1 /*
2  * Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
3  *
4  * This file is part of the KD Chart library.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 #include "KChartPolarDiagram.h"
21 #include "KChartPolarDiagram_p.h"
22 
23 #include "KChartPaintContext.h"
24 #include "KChartPainterSaver_p.h"
25 #include "KChartMath_p.h"
26 
27 #include <QPainter>
28 
29 using namespace KChart;
30 
31 PolarDiagram::Private::Private() :
32  rotateCircularLabels( false ),
33  closeDatasets( false )
34 {
35 }
36 
37 PolarDiagram::Private::~Private() {}
38 
39 #define d d_func()
40 
41 PolarDiagram::PolarDiagram( QWidget* parent, PolarCoordinatePlane* plane ) :
42  AbstractPolarDiagram( new Private( ), parent, plane )
43 {
44  //init();
45 }
46 
47 PolarDiagram::~PolarDiagram()
48 {
49 }
50 
51 
52 void PolarDiagram::init()
53 {
54  setShowDelimitersAtPosition( Position::Unknown, false );
55  setShowDelimitersAtPosition( Position::Center, false );
56  setShowDelimitersAtPosition( Position::NorthWest, false );
57  setShowDelimitersAtPosition( Position::North, true );
58  setShowDelimitersAtPosition( Position::NorthEast, false );
59  setShowDelimitersAtPosition( Position::West, false );
60  setShowDelimitersAtPosition( Position::East, false );
61  setShowDelimitersAtPosition( Position::SouthWest, false );
62  setShowDelimitersAtPosition( Position::South, true );
63  setShowDelimitersAtPosition( Position::SouthEast, false );
64  setShowDelimitersAtPosition( Position::Floating, false );
65 
66  setShowLabelsAtPosition( Position::Unknown, false );
67  setShowLabelsAtPosition( Position::Center, false );
68  setShowLabelsAtPosition( Position::NorthWest, false );
69  setShowLabelsAtPosition( Position::North, true );
70  setShowLabelsAtPosition( Position::NorthEast, false );
71  setShowLabelsAtPosition( Position::West, false );
72  setShowLabelsAtPosition( Position::East, false );
73  setShowLabelsAtPosition( Position::SouthWest, false );
74  setShowLabelsAtPosition( Position::South, true );
75  setShowLabelsAtPosition( Position::SouthEast, false );
76  setShowLabelsAtPosition( Position::Floating, false );
77 }
78 
80 {
81  PolarDiagram* newDiagram = new PolarDiagram( new Private( *d ) );
82  // This needs to be copied after the fact
83  newDiagram->d->showDelimitersAtPosition = d->showDelimitersAtPosition;
84  newDiagram->d->showLabelsAtPosition = d->showLabelsAtPosition;
85  newDiagram->d->rotateCircularLabels = d->rotateCircularLabels;
86  newDiagram->d->closeDatasets = d->closeDatasets;
87  return newDiagram;
88 }
89 
91 {
92  if ( !checkInvariants(true) ) return QPair<QPointF, QPointF>( QPointF( 0, 0 ), QPointF( 0, 0 ) );
93  const int rowCount = model()->rowCount(rootIndex());
94  const int colCount = model()->columnCount(rootIndex());
95  qreal xMin = 0.0;
96  qreal xMax = colCount;
97  qreal yMin = 0, yMax = 0;
98  for ( int iCol=0; iCol<colCount; ++iCol ) {
99  for ( int iRow=0; iRow< rowCount; ++iRow ) {
100  qreal value = model()->data( model()->index( iRow, iCol, rootIndex() ) ).toReal(); // checked
101  yMax = qMax( yMax, value );
102  yMin = qMin( yMin, value );
103  }
104  }
105  QPointF bottomLeft ( QPointF( xMin, yMin ) );
106  QPointF topRight ( QPointF( xMax, yMax ) );
107  return QPair<QPointF, QPointF> ( bottomLeft, topRight );
108 }
109 
110 
111 
112 void PolarDiagram::paintEvent ( QPaintEvent*)
113 {
114  QPainter painter ( viewport() );
115  PaintContext ctx;
116  ctx.setPainter ( &painter );
117  ctx.setRectangle( QRectF ( 0, 0, width(), height() ) );
118  paint ( &ctx );
119 }
120 
121 void PolarDiagram::resizeEvent ( QResizeEvent*)
122 {
123 }
124 
125 void PolarDiagram::paintPolarMarkers( PaintContext* ctx, const QPolygonF& polygon )
126 {
127  Q_UNUSED(ctx);
128  Q_UNUSED(polygon);
129  // obsolete, since we are using real markers now!
130 }
131 
133 {
134  qreal dummy1, dummy2;
135  paint( ctx, true, dummy1, dummy2 );
136  paint( ctx, false, dummy1, dummy2 );
137 }
138 
140  bool calculateListAndReturnScale,
141  qreal& newZoomX, qreal& newZoomY )
142 {
143  // note: Not having any data model assigned is no bug
144  // but we can not draw a diagram then either.
145  if ( !checkInvariants(true) )
146  return;
147  d->reverseMapper.clear();
148 
149  const int rowCount = model()->rowCount( rootIndex() );
150  const int colCount = model()->columnCount( rootIndex() );
151 
152  if ( calculateListAndReturnScale ) {
153  // Check if all of the data value texts / data comments fit into the available space...
154  d->labelPaintCache.clear();
155 
156  for ( int iCol = 0; iCol < colCount; ++iCol ) {
157  for ( int iRow=0; iRow < rowCount; ++iRow ) {
158  QModelIndex index = model()->index( iRow, iCol, rootIndex() ); // checked
159  const qreal value = model()->data( index ).toReal();
160  QPointF point = coordinatePlane()->translate(
161  QPointF( value, iRow ) ) + ctx->rectangle().topLeft();
162  //qDebug() << point;
163  d->addLabel( &d->labelPaintCache, index, nullptr, PositionPoints( point ),
164  Position::Center, Position::Center, value );
165  }
166  }
167 
168  newZoomX = coordinatePlane()->zoomFactorX();
169  newZoomY = coordinatePlane()->zoomFactorY();
170 
171  if ( d->labelPaintCache.paintReplay.count() ) {
172  // ...and zoom out if necessary
173  const qreal oldZoomX = newZoomX;
174  const qreal oldZoomY = newZoomY;
175 
176  QRectF txtRectF;
177  d->paintDataValueTextsAndMarkers( ctx, d->labelPaintCache, true, true, &txtRectF );
178  const QRect txtRect = txtRectF.toRect();
179  const QRect curRect = coordinatePlane()->geometry();
180  const qreal gapX = qMin( txtRect.left() - curRect.left(), curRect.right() - txtRect.right() );
181  const qreal gapY = qMin( txtRect.top() - curRect.top(), curRect.bottom() - txtRect.bottom() );
182  if ( gapX < 0.0 ) {
183  newZoomX = oldZoomX * ( 1.0 + ( gapX - 1.0 ) / curRect.width() );
184  }
185  if ( gapY < 0.0 ) {
186  newZoomY = oldZoomY * ( 1.0 + ( gapY - 1.0 ) / curRect.height() );
187  }
188  }
189  } else {
190  // Paint the data sets
191  for ( int iCol = 0; iCol < colCount; ++iCol ) {
192  //TODO(khz): As of yet PolarDiagram can not show per-segment line attributes
193  // but it draws every polyline in one go - using one color.
194  // This needs to be enhanced to allow for cell-specific settings
195  // in the same way as LineDiagram does it.
196  QBrush brush = d->datasetAttrs( iCol, KChart::DatasetBrushRole ).value<QBrush>();
197  QPolygonF polygon;
198  for ( int iRow = 0; iRow < rowCount; ++iRow ) {
199  QModelIndex index = model()->index( iRow, iCol, rootIndex() ); // checked
200  const qreal value = model()->data( index ).toReal();
201  QPointF point = coordinatePlane()->translate( QPointF( value, iRow ) )
202  + ctx->rectangle().topLeft();
203  polygon.append( point );
204  //qDebug() << point;
205  }
206  if ( closeDatasets() && !polygon.isEmpty() ) {
207  // close the circle by connecting the last data point to the first
208  polygon.append( polygon.first() );
209  }
210 
211  PainterSaver painterSaver( ctx->painter() );
212  ctx->painter()->setRenderHint ( QPainter::Antialiasing );
213  ctx->painter()->setBrush( brush );
214  QPen p = d->datasetAttrs( iCol, KChart::DatasetPenRole ).value< QPen >();
215  if ( p.style() != Qt::NoPen )
216  {
217  ctx->painter()->setPen( PrintingParameters::scalePen( p ) );
218  ctx->painter()->drawPolyline( polygon );
219  }
220  }
221  d->paintDataValueTextsAndMarkers( ctx, d->labelPaintCache, true );
222  }
223 }
224 
225 void PolarDiagram::resize ( const QSizeF& size )
226 {
228 }
229 
230 /*virtual*/
232 {
233  return model()->rowCount(rootIndex());
234 }
235 
236 /*virtual*/
238 {
239  return model() ? model()->rowCount(rootIndex()) : 0.0;
240 }
241 
242 /*virtual*/
244 {
245  return 5; // FIXME
246 }
247 
249 {
250  Q_UNUSED( degrees );
251  qWarning() << "Deprecated PolarDiagram::setZeroDegreePosition() called, setting ignored.";
252 }
253 
255 {
256  qWarning() << "Deprecated PolarDiagram::zeroDegreePosition() called.";
257  return 0;
258 }
259 
260 void PolarDiagram::setRotateCircularLabels( bool rotateCircularLabels )
261 {
262  d->rotateCircularLabels = rotateCircularLabels;
263 }
264 
265 bool PolarDiagram::rotateCircularLabels() const
266 {
267  return d->rotateCircularLabels;
268 }
269 
270 void PolarDiagram::setCloseDatasets( bool closeDatasets )
271 {
272  d->closeDatasets = closeDatasets;
273 }
274 
275 bool PolarDiagram::closeDatasets() const
276 {
277  return d->closeDatasets;
278 }
279 
280 void PolarDiagram::setShowDelimitersAtPosition( Position position,
281  bool showDelimiters )
282 {
283  d->showDelimitersAtPosition[position.value()] = showDelimiters;
284 }
285 
286 void PolarDiagram::setShowLabelsAtPosition( Position position,
287  bool showLabels )
288 {
289  d->showLabelsAtPosition[position.value()] = showLabels;
290 }
291 
292 bool PolarDiagram::showDelimitersAtPosition( Position position ) const
293 {
294  return d->showDelimitersAtPosition[position.value()];
295 }
296 
297 bool PolarDiagram::showLabelsAtPosition( Position position ) const
298 {
299  return d->showLabelsAtPosition[position.value()];
300 }
301 
302 
303 
KChartEnums::PositionValue value() const
Returns an integer value corresponding to this Position.
Class only listed here to document inheritance of some KChart classes.
Qt::PenStyle style() const const
QRect toRect() const const
void resize(const QSizeF &area) override
void paint(PaintContext *paintContext) override
void setRenderHint(QPainter::RenderHint hint, bool on)
int right() const const
void drawPolyline(const QPointF *points, int pointCount)
Defines a position, using compass terminology.
void setCloseDatasets(bool closeDatasets)
Close each of the data series by connecting the last point to its respective start point...
qreal valueTotals() const override
int height() const const
void paint(QPainter *) override
reimpl
void setZeroDegreePosition(int degrees)
Stores the absolute target points of a Position.
Stores information about painting diagrams.
int top() const const
void setPen(const QColor &color)
int left() const const
QPointF topLeft() const const
void setBrush(const QBrush &brush)
qreal numberOfValuesPerDataset() const override
qreal numberOfGridRings() const override
virtual void resize(const QSizeF &area)
Called by the widget&#39;s sizeEvent.
int width() const const
QVariant data(int role) const const
const QPair< QPointF, QPointF > calculateDataBoundaries() const override
int bottom() const const
Base class for diagrams based on a polar coordinate system.
qreal toReal(bool *ok) const const
Global namespace.
virtual PolarDiagram * clone() const
Creates an exact copy of this diagram.
PolarDiagram defines a common polar diagram.
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Thu Sep 17 2020 22:36:40 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.