KD Chart 2  [rev.2.7]
KDChartTernaryCoordinatePlane.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 ** Copyright (C) 2001-2020 Klaralvdalens Datakonsult AB. All rights reserved.
3 **
4 ** This file is part of the KD Chart library.
5 **
6 ** Licensees holding valid commercial KD Chart licenses may use this file in
7 ** accordance with the KD Chart Commercial License Agreement provided with
8 ** the Software.
9 **
10 **
11 ** This file may be distributed and/or modified under the terms of the
12 ** GNU General Public License version 2 and version 3 as published by the
13 ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
14 **
15 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 **
18 ** Contact info@kdab.com if any conditions of this licensing are not
19 ** clear to you.
20 **
21 **********************************************************************/
22 
24 #include "KDChartTernaryCoordinatePlane_p.h"
25 
26 #include <QtDebug>
27 #include <QPainter>
28 
29 #include "KDChartPaintContext.h"
30 #include "KDChartPainterSaver_p.h"
31 #include "KDChartTernaryAxis.h"
33 
34 #include "TernaryConstants.h"
35 
36 using namespace KDChart;
37 
38 #define d d_func()
39 
40 TernaryCoordinatePlane::Private::Private()
41  : AbstractCoordinatePlane::Private()
42 {
43 }
44 
45 TernaryCoordinatePlane::TernaryCoordinatePlane( Chart* parent )
46  : AbstractCoordinatePlane( new Private(), parent )
47 {
48 }
49 
51 {
52 }
53 
54 void TernaryCoordinatePlane::init()
55 {
56 }
57 
59 {
60  Q_ASSERT_X ( dynamic_cast<AbstractTernaryDiagram*>( diagram ),
61  "TernaryCoordinatePlane::addDiagram", "Only ternary "
62  "diagrams can be added to a ternary coordinate plane!" );
64 }
65 
67 { // this is our "resize event":
68  // all diagrams always take the same space, nothing to be done here
69  // the "inner" margin (adjustments to diagram coordinates)
70  QRectF diagramNativeRectangle ( QPointF( 0.0, 0.0 ),
71  QSizeF( TriangleWidth, TriangleHeight ) );
72  QPair<QSizeF, QSizeF> margins = grid()->requiredMargins();
73  d->diagramRect = areaGeometry();
74  diagramNativeRectangle.adjust
75  (-margins.first.width(), -margins.first.height(),
76  margins.second.width(), margins.second.height() );
77 
78  // the "outer" margin (distance between diagram contents and area,
79  // determined by axis label overlap
80  {
81  QSizeF topleft( 0.0, 0.0 );
82  QSizeF bottomRight( 0.0, 0.0 );
83  Q_FOREACH( AbstractDiagram* abstractDiagram, diagrams() ) {
85  qobject_cast<AbstractTernaryDiagram*>( abstractDiagram );
86  Q_ASSERT( diagram );
87  Q_FOREACH( TernaryAxis* axis, diagram->axes() ) {
88  QPair<QSizeF, QSizeF> margin = axis->requiredMargins();
89  topleft = topleft.expandedTo( margin.first );
90  bottomRight = bottomRight.expandedTo( margin.second );
91  }
92  }
93  d->diagramRectContainer =
94  d->diagramRect.adjusted( topleft.width(),
95  topleft.height(),
96  -bottomRight.width(),
97  -bottomRight.height() );
98  }
99 
100  // now calculate isometric projection, x and y widget coordinate
101  // units, and location of (0.0, 0.0) in diagram coordinates
102  QPointF zeroZeroPoint = d->diagramRectContainer.bottomLeft();
103  qreal w = d->diagramRectContainer.width();
104  qreal h = d->diagramRectContainer.height();
105  qreal usableWidth;
106  qreal usableHeight;
107 
108  if ( TriangleHeight * w > h ) {
109  // shorten width:
110  usableWidth = h / diagramNativeRectangle.height();
111  usableHeight = h;
112  zeroZeroPoint.setX( zeroZeroPoint.x() + ( w - usableWidth ) / 2 );
113  } else {
114  // reduce height:
115  usableWidth = w;
116  usableHeight = diagramNativeRectangle.height() * w;
117  zeroZeroPoint.setY( zeroZeroPoint.y() - ( h - usableHeight ) / 2 );
118  }
119  // the rectangle has 1 as it's width, and TriangleHeight as it's
120  // height - so this is how we translate that to widget coordinates:
121  d->xUnit = usableWidth / diagramNativeRectangle.width(); // only because we normalize the values to [0..1]
122  d->yUnit = -usableHeight / diagramNativeRectangle.height();
123 
124  // now move zeroZeroPoint so that it does not include the tick marks
125  {
126  qreal descent = diagramNativeRectangle.height() - TriangleHeight;
127  qreal rightShift = -diagramNativeRectangle.x();
128  zeroZeroPoint += QPointF( rightShift * d->xUnit, descent * d->yUnit );
129  }
130 
131  d->diagramRect.setBottomLeft( zeroZeroPoint );
132  d->diagramRect.setTopRight( QPointF( usableWidth, -usableHeight ) + zeroZeroPoint );
133 }
134 
135 const QPointF TernaryCoordinatePlane::translate( const QPointF& point ) const
136 {
137  return QPointF( d->diagramRect.bottomLeft().x() + point.x() * d->xUnit,
138  d->diagramRect.bottomLeft().y() + point.y() * d->yUnit );
139 }
140 
142 {
143  // FIXME temp
144  return QSize();
145 }
146 
148 {
149  return QSizePolicy( QSizePolicy::MinimumExpanding,
150  QSizePolicy::MinimumExpanding );
151 }
152 
153 void TernaryCoordinatePlane::paint( QPainter* painter )
154 {
155  PainterSaver s( painter );
156  // FIXME: this is not a good location for that:
157  painter->setRenderHint(QPainter::Antialiasing, true );
158 
159  AbstractDiagramList diags = diagrams();
160  if ( !diags.isEmpty() )
161  {
162  PaintContext ctx;
163  ctx.setPainter ( painter );
164  ctx.setCoordinatePlane ( this );
165  const QRectF drawArea( areaGeometry() );
166  ctx.setRectangle ( drawArea );
167 
168  // paint the coordinate system rulers:
169  Q_ASSERT( d->grid != 0 );
170  d->grid->drawGrid( &ctx );
171 
172  // paint the diagrams:
173  for ( int i = 0; i < diags.size(); i++ )
174  {
175  PainterSaver diagramPainterSaver( painter );
176  diags[i]->paint ( &ctx );
177  }
178  }
179 }
180 
182 { // not needed
183  return DataDimensionsList();
184 }
185 
186 TernaryGrid* TernaryCoordinatePlane::grid() const
187 {
188  TernaryGrid* ternaryGrid = static_cast<TernaryGrid*>( d->grid );
189  Q_ASSERT( dynamic_cast<TernaryGrid*>( d->grid ) );
190  return ternaryGrid;
191 }
192 
193 #undef d
Base class common for all coordinate planes, CartesianCoordinatePlane, PolarCoordinatePlane, TernaryCoordinatePlane.
void setPainter(QPainter *painter)
A chart with one or more diagrams.
Definition: KDChartChart.h:98
const qreal TriangleHeight
QSize minimumSizeHint() const
[reimplemented]
AbstractDiagram defines the interface for diagram classes.
The class for ternary axes.
void addDiagram(AbstractDiagram *diagram) override
Adds a diagram to this coordinate plane.
QSizePolicy sizePolicy() const
[reimplemented]
QList< DataDimension > DataDimensionsList
Stores information about painting diagrams.
Base class for diagrams based on a ternary coordinate plane.
DataDimensionsList getDataDimensionsList() const override
QPair< QSizeF, QSizeF > requiredMargins() const
void setCoordinatePlane(AbstractCoordinatePlane *plane)
void setRectangle(const QRectF &rect)
virtual void addDiagram(AbstractDiagram *diagram)
Adds a diagram to this coordinate plane.
void layoutDiagrams() override
Distribute the available space among the diagrams and axes.
QRect areaGeometry() const override
const qreal TriangleWidth
const QPointF translate(const QPointF &diagramPoint) const override
Translate the given point in value space coordinates to a position in pixel space.

Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/

https://www.kdab.com/development-resources/qt-tools/kd-chart/