KD Chart API Documentation 3.1
Loading...
Searching...
No Matches
KDChartTernaryGrid.cpp
Go to the documentation of this file.
1/****************************************************************************
2**
3** This file is part of the KD Chart library.
4**
5** SPDX-FileCopyrightText: 2001 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
6**
7** SPDX-License-Identifier: MIT
8**
9****************************************************************************/
10
11#include "KDChartTernaryGrid.h"
12
13#include <cmath>
14
15#include <algorithm>
16#include <limits>
17
18#include <QApplication>
19#include <QtDebug>
20
21#include "KDChartPaintContext.h"
22#include "KDChartPainterSaver_p.h"
25#include "TernaryConstants.h"
26#include "TernaryPoint.h"
27
28using namespace KDChart;
29
30TickInfo::TickInfo(qreal _percentage, int _depth)
31 : percentage(_percentage)
32 , depth(_depth)
33{
34}
35
36bool KDChart::operator==(const TickInfo &left, const TickInfo &right)
37{
38 return fabs(left.percentage - right.percentage)
39 <= std::numeric_limits<qreal>::epsilon()
40 && left.depth == right.depth;
41}
42
47
51
53{
54 static const int GridLineDistanceTreshold = 20; // <Threshold> pixels between each grid line
55
56 QPainter &painter = *context->painter(); // recover from pointer madness
57 PainterSaver s(&painter); // can i have a reference based version of that?
58 auto *plane = dynamic_cast<TernaryCoordinatePlane *>(context->coordinatePlane());
59 Q_ASSERT_X(plane, "TernaryGrid::drawGrid",
60 "Bad function call: PaintContext::coodinatePlane() NOT a ternary plane.");
61
62 // translate the points and see how many grid lines we can draw:
63 const int MaxDepth = 3;
64 qreal xPixels = plane->translate(TriangleBottomRight).x() - plane->translate(TriangleBottomLeft).x();
65 int granularity = 20;
66 if (xPixels > 10 * GridLineDistanceTreshold)
67 granularity = 10;
68 if (xPixels > 20 * GridLineDistanceTreshold)
69 granularity = 5;
70
71 m_tickInfo.clear();
72 for (int i = granularity; i < 100; i += granularity) {
73 TickInfo tick((1.0 * i) / 100.0, 2);
74 if (i % 10 == 0)
75 tick.depth = 1;
76 if (i % 20 == 0)
77 tick.depth = 0;
78 m_tickInfo.append(tick);
79 }
80
81 QVector<QLineF> lines[MaxDepth];
82 {
83 for (const TickInfo &tick : qAsConst(m_tickInfo)) {
84 const qreal &percent = tick.percentage;
85 { // draw parallels to B
86 TernaryPoint ternaryStart(percent, 1.0 - percent);
87 TernaryPoint ternaryEnd(0.0, 1.0 - percent);
88 QPointF start(translate(ternaryStart));
89 QPointF end(translate(ternaryEnd));
90 lines[tick.depth].append(QLineF(plane->translate(start),
91 plane->translate(end)));
92 }
93 { // draw parallels to C
94 TernaryPoint ternaryStart(percent, 0.0);
95 TernaryPoint ternaryEnd(0.0, percent);
96 QPointF start(translate(ternaryStart));
97 QPointF end(translate(ternaryEnd));
98 lines[tick.depth].append(QLineF(plane->translate(start),
99 plane->translate(end)));
100 }
101 { // draw parallels to A
102 TernaryPoint ternaryStart(percent, 1.0 - percent);
103 TernaryPoint ternaryEnd(percent, 0.0);
104 QPointF start(translate(ternaryStart));
105 QPointF end(translate(ternaryEnd));
106 lines[tick.depth].append(QLineF(plane->translate(start),
107 plane->translate(end)));
108 }
109 }
110 }
111
112 // now draw the lines:
113 painter.setPen(PrintingParameters::scalePen(QPen(QColor("lightgray"), 1)));
114 painter.setBrush(QColor("lightgray"));
115 painter.drawLines(lines[2]);
116 painter.setPen(PrintingParameters::scalePen(QPen(QColor("gray"), 1)));
117 painter.setBrush(QColor("gray"));
118 painter.drawLines(lines[1]);
119 painter.setPen(PrintingParameters::scalePen(QPen(QColor("darkslategray"), 1)));
120 painter.setBrush(QColor("darkslategray"));
121 painter.drawLines(lines[0]);
122
123 // now draw the triangle (this could be part of the axis, in fact):
125 // make sure this does not fill, otherwise it wipes the contents
126 // of the triangle (doh!):
127 painter.setBrush(Qt::NoBrush);
128 QPolygonF points;
129 points << plane->translate(TriangleBottomLeft)
130 << plane->translate(TriangleBottomRight)
131 << plane->translate(TriangleTop);
132 painter.drawPolygon(points);
133
134 // now draw the ticks:
136 painter.setBrush(Qt::black);
137
138 QVector<QLineF> ticks;
139 // prepare list of percentages, then calculate lines:
140 QVector<TickInfo> percentages(m_tickInfo);
141 // I have commented those out, I think it looks ugly if they are
142 // enabled:
143 // percentages.prepend( 0.0 );
144 // percentages.append( 1.0 );
145
146 // FIXME this may need a predicate that takes eplison into account
147 // (but it does not hurt, since it will not make the painter
148 // paint two lines):
149 percentages.erase(std::unique(percentages.begin(), percentages.end()),
150 percentages.end());
151
152 {
153 for (const TickInfo &tick : percentages) {
154 const qreal &percent = tick.percentage;
155 { // BC axis markers:
156 const QPointF markerDistance(FullMarkerDistanceBC
157 / (tick.depth + 1));
158 QPointF start(percent, 0.0);
159 ticks.append(QLineF(plane->translate(start),
160 plane->translate(start - markerDistance)));
161 }
162 { // AC axis markers:
163 const QPointF markerDistance(FullMarkerDistanceAC
164 / (tick.depth + 1));
165 const QPointF start(TriangleBottomRight + percent * AxisVector_C_A);
166 const QPointF end(start + markerDistance);
167 ticks.append(QLineF(plane->translate(start),
168 plane->translate(end)));
169 }
170 {
171 // AB axis markers:
172 const QPointF markerDistance(FullMarkerDistanceBA
173 / (tick.depth + 1));
174 const QPointF start(percent * AxisVector_B_A);
175 const QPointF end(start + markerDistance);
176 ticks.append(QLineF(plane->translate(start),
177 plane->translate(end)));
178 }
179 }
180 }
181 painter.drawLines(ticks);
182}
183
188
190{
191 // qreal topMargin = ( FullMarkerDistanceBA * RelMarkerLength ).x();
192 qreal topMargin = 0.0; // no markers on tip of triangle
193 qreal leftMargin = fabs(FullMarkerDistanceBA.x());
194 qreal bottomMargin = fabs(FullMarkerDistanceBC.y());
195 // qDebug() << "TernaryGrid::requiredMargins: leftMargin:" << leftMargin
196 // << ", bottomMargin:" << bottomMargin
197 // << ", topMargin:" << topMargin
198 // << ", FullMarkerDistanceBC:" << FullMarkerDistanceBC
199 // << ", FullMarkerDistanceBA:" << FullMarkerDistanceBA
200 // << ", FullMarkerDistanceAC:" << FullMarkerDistanceAC
201 // << ", RelMarkerLength:" << RelMarkerLength;
202 return QPair<QSizeF, QSizeF>(QSizeF(leftMargin, topMargin),
203 QSizeF(leftMargin, bottomMargin));
204}
205
207{
208 return m_tickInfo;
209}
const QPointF TriangleBottomLeft(0.0, 0.0)
const QPointF TriangleBottomRight(1.0, 0.0)
const QPointF AxisVector_B_A(TriangleTop)
const QPointF TriangleTop(0.5, TriangleHeight)
const QPointF FullMarkerDistanceBA
const QPointF FullMarkerDistanceAC
const QPointF FullMarkerDistanceBC
const QPointF AxisVector_C_A
QPointF translate(const TernaryPoint &point)
Stores information about painting diagrams.
AbstractCoordinatePlane * coordinatePlane() const
static QPen scalePen(const QPen &pen)
void drawGrid(PaintContext *context) override
QPair< QSizeF, QSizeF > requiredMargins() const
DataDimensionsList calculateGrid(const DataDimensionsList &rawDataDimensions) const override
Calculates the grid start/end/step width values.
const QVector< TickInfo > & tickInfo() const
TernaryPoint defines a point within a ternary coordinate plane.
bool operator==(const TickInfo &, const TickInfo &)
QList< DataDimension > DataDimensionsList
void drawLines(const QLineF *lines, int lineCount)
void drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule)
void setBrush(const QBrush &brush)
void setPen(const QColor &color)
qreal x() const const
qreal y() const const
void translate(qreal dx, qreal dy)
void append(const T &value)
QVector::iterator begin()
QVector::iterator end()
QVector::iterator erase(QVector::iterator begin, QVector::iterator end)
TickInfo(qreal percentage=0, int depth=0)

© 2001 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/
Generated on Wed May 1 2024 00:01:10 for KD Chart API Documentation by doxygen 1.9.8