KChart

KChartTernaryCoordinatePlane.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 "KChartTernaryCoordinatePlane.h"
21 #include "KChartTernaryCoordinatePlane_p.h"
22 
23 #include <QtDebug>
24 #include <QPainter>
25 
26 #include "KChartPaintContext.h"
27 #include "KChartPainterSaver_p.h"
28 #include "KChartTernaryAxis.h"
29 #include "KChartAbstractTernaryDiagram.h"
30 
31 #include "TernaryConstants.h"
32 
33 using namespace KChart;
34 
35 #define d d_func()
36 
37 TernaryCoordinatePlane::Private::Private()
38  : AbstractCoordinatePlane::Private()
39 {
40 }
41 
42 TernaryCoordinatePlane::TernaryCoordinatePlane( Chart* parent )
43  : AbstractCoordinatePlane( new Private(), parent )
44 {
45 }
46 
47 TernaryCoordinatePlane::~TernaryCoordinatePlane()
48 {
49 }
50 
51 void TernaryCoordinatePlane::init()
52 {
53 }
54 
56 {
57  Q_ASSERT_X ( dynamic_cast<AbstractTernaryDiagram*>( diagram ),
58  "TernaryCoordinatePlane::addDiagram", "Only ternary "
59  "diagrams can be added to a ternary coordinate plane!" );
61 }
62 
64 { // this is our "resize event":
65  // all diagrams always take the same space, nothing to be done here
66  // the "inner" margin (adjustments to diagram coordinates)
67  QRectF diagramNativeRectangle ( QPointF( 0.0, 0.0 ),
68  QSizeF( TriangleWidth, TriangleHeight ) );
69  QPair<QSizeF, QSizeF> margins = grid()->requiredMargins();
70  d->diagramRect = areaGeometry();
71  diagramNativeRectangle.adjust
72  (-margins.first.width(), -margins.first.height(),
73  margins.second.width(), margins.second.height() );
74 
75  // the "outer" margin (distance between diagram contents and area,
76  // determined by axis label overlap
77  {
78  QSizeF topleft( 0.0, 0.0 );
79  QSizeF bottomRight( 0.0, 0.0 );
80  const auto ds = diagrams();
81  for ( AbstractDiagram* abstractDiagram : ds ) {
82  AbstractTernaryDiagram* diagram =
83  qobject_cast<AbstractTernaryDiagram*>( abstractDiagram );
84  Q_ASSERT( diagram );
85  Q_FOREACH( TernaryAxis* axis, diagram->axes() ) {
86  QPair<QSizeF, QSizeF> margin = axis->requiredMargins();
87  topleft = topleft.expandedTo( margin.first );
88  bottomRight = bottomRight.expandedTo( margin.second );
89  }
90  }
91  d->diagramRectContainer =
92  d->diagramRect.adjusted( topleft.width(),
93  topleft.height(),
94  -bottomRight.width(),
95  -bottomRight.height() );
96  }
97 
98  // now calculate isometric projection, x and y widget coordinate
99  // units, and location of (0.0, 0.0) in diagram coordinates
100  QPointF zeroZeroPoint = d->diagramRectContainer.bottomLeft();
101  qreal w = d->diagramRectContainer.width();
102  qreal h = d->diagramRectContainer.height();
103  qreal usableWidth;
104  qreal usableHeight;
105 
106  if ( TriangleHeight * w > h ) {
107  // shorten width:
108  usableWidth = h / diagramNativeRectangle.height();
109  usableHeight = h;
110  zeroZeroPoint.setX( zeroZeroPoint.x() + ( w - usableWidth ) / 2 );
111  } else {
112  // reduce height:
113  usableWidth = w;
114  usableHeight = diagramNativeRectangle.height() * w;
115  zeroZeroPoint.setY( zeroZeroPoint.y() - ( h - usableHeight ) / 2 );
116  }
117  // the rectangle has 1 as it's width, and TriangleHeight as it's
118  // height - so this is how we translate that to widget coordinates:
119  d->xUnit = usableWidth / diagramNativeRectangle.width(); // only because we normalize the values to [0..1]
120  d->yUnit = -usableHeight / diagramNativeRectangle.height();
121 
122  // now move zeroZeroPoint so that it does not include the tick marks
123  {
124  qreal descent = diagramNativeRectangle.height() - TriangleHeight;
125  qreal rightShift = -diagramNativeRectangle.x();
126  zeroZeroPoint += QPointF( rightShift * d->xUnit, descent * d->yUnit );
127  }
128 
129  d->diagramRect.setBottomLeft( zeroZeroPoint );
130  d->diagramRect.setTopRight( QPointF( usableWidth, -usableHeight ) + zeroZeroPoint );
131 }
132 
134 {
135  return QPointF( d->diagramRect.bottomLeft().x() + point.x() * d->xUnit,
136  d->diagramRect.bottomLeft().y() + point.y() * d->yUnit );
137 }
138 
140 {
141  // FIXME temp
142  return QSize();
143 }
144 
146 {
149 }
150 
151 void TernaryCoordinatePlane::paint( QPainter* painter )
152 {
153  PainterSaver s( painter );
154  // FIXME: this is not a good location for that:
155  painter->setRenderHint(QPainter::Antialiasing, true );
156 
157  AbstractDiagramList diags = diagrams();
158  if ( !diags.isEmpty() )
159  {
160  PaintContext ctx;
161  ctx.setPainter ( painter );
162  ctx.setCoordinatePlane ( this );
163  const QRectF drawArea( areaGeometry() );
164  ctx.setRectangle ( drawArea );
165 
166  // paint the coordinate system rulers:
167  Q_ASSERT( d->grid != nullptr );
168  d->grid->drawGrid( &ctx );
169 
170  // paint the diagrams:
171  for ( int i = 0; i < diags.size(); i++ )
172  {
173  PainterSaver diagramPainterSaver( painter );
174  diags[i]->paint ( &ctx );
175  }
176  }
177 }
178 
179 DataDimensionsList TernaryCoordinatePlane::getDataDimensionsList() const
180 { // not needed
181  return DataDimensionsList();
182 }
183 
184 TernaryGrid* TernaryCoordinatePlane::grid() const
185 {
186  TernaryGrid* ternaryGrid = static_cast<TernaryGrid*>( d->grid );
187  Q_ASSERT( dynamic_cast<TernaryGrid*>( d->grid ) );
188  return ternaryGrid;
189 }
190 
191 #undef d
void addDiagram(AbstractDiagram *diagram) override
Adds a diagram to this coordinate plane.
AbstractDiagram defines the interface for diagram classes.
void setRenderHint(QPainter::RenderHint hint, bool on)
qreal x() const const
QRect areaGeometry() const override
QSizeF expandedTo(const QSizeF &otherSize) const const
const QPointF translate(const QPointF &diagramPoint) const override
Translate the given point in value space coordinates to a position in pixel space.
void layoutDiagrams() override
Distribute the available space among the diagrams and axes.
void adjust(qreal dx1, qreal dy1, qreal dx2, qreal dy2)
int size() const const
qreal x() const const
qreal y() const const
Stores information about painting diagrams.
bool isEmpty() const const
Base class common for all coordinate planes, CartesianCoordinatePlane, PolarCoordinatePlane, TernaryCoordinatePlane.
Base class for diagrams based on a ternary coordinate plane.
virtual void addDiagram(AbstractDiagram *diagram)
Adds a diagram to this coordinate plane.
qreal width() const const
void setX(qreal x)
void setY(qreal y)
qreal height() const const
A chart with one or more diagrams.
Definition: KChartChart.h:95
qreal height() const const
Global namespace.
T qobject_cast(QObject *object)
QObject * parent() const const
The class for ternary axes.
qreal width() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sat Sep 19 2020 22:36:26 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.