1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Charts module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 or (at your option) any later version
20** approved by the KDE Free Qt Foundation. The licenses are as published by
21** the Free Software Foundation and appearing in the file LICENSE.GPL3
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30#include <private/xlogydomain_p.h>
31#include <private/qabstractaxis_p.h>
32#include <QtCharts/QLogValueAxis>
33#include <QtCore/QtMath>
34#include <cmath>
35
36QT_CHARTS_BEGIN_NAMESPACE
37
38XLogYDomain::XLogYDomain(QObject *parent)
39 : AbstractDomain(parent),
40 m_logLeftY(0),
41 m_logRightY(1),
42 m_logBaseY(10)
43{
44}
45
46XLogYDomain::~XLogYDomain()
47{
48}
49
50void XLogYDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY)
51{
52 bool axisXChanged = false;
53 bool axisYChanged = false;
54
55 adjustLogDomainRanges(min&: minY, max&: maxY);
56
57 if (!qFuzzyIsNull(d: m_minX - minX) || !qFuzzyIsNull(d: m_maxX - maxX)) {
58 m_minX = minX;
59 m_maxX = maxX;
60 axisXChanged = true;
61 if(!m_signalsBlocked)
62 emit rangeHorizontalChanged(min: m_minX, max: m_maxX);
63 }
64
65 if (!qFuzzyIsNull(d: m_minY - minY) || !qFuzzyIsNull(d: m_maxY - maxY)) {
66 m_minY = minY;
67 m_maxY = maxY;
68 axisYChanged = true;
69 qreal logMinY = std::log10(x: m_minY) / std::log10(x: m_logBaseY);
70 qreal logMaxY = std::log10(x: m_maxY) / std::log10(x: m_logBaseY);
71 m_logLeftY = logMinY < logMaxY ? logMinY : logMaxY;
72 m_logRightY = logMinY > logMaxY ? logMinY : logMaxY;
73 if (!m_signalsBlocked)
74 emit rangeVerticalChanged(min: m_minY, max: m_maxY);
75 }
76
77 if (axisXChanged || axisYChanged)
78 emit updated();
79}
80
81void XLogYDomain::zoomIn(const QRectF &rect)
82{
83 storeZoomReset();
84 QRectF fixedRect = fixZoomRect(rect);
85 qreal dx = spanX() / m_size.width();
86 qreal maxX = m_maxX;
87 qreal minX = m_minX;
88
89 maxX = minX + dx * fixedRect.right();
90 minX = minX + dx * fixedRect.left();
91
92 qreal logLeftY = m_logRightY - fixedRect.bottom() * (m_logRightY - m_logLeftY) / m_size.height();
93 qreal logRightY = m_logRightY - fixedRect.top() * (m_logRightY - m_logLeftY) / m_size.height();
94 qreal leftY = qPow(x: m_logBaseY, y: logLeftY);
95 qreal rightY = qPow(x: m_logBaseY, y: logRightY);
96 qreal minY = leftY < rightY ? leftY : rightY;
97 qreal maxY = leftY > rightY ? leftY : rightY;
98
99 setRange(minX, maxX, minY, maxY);
100}
101
102void XLogYDomain::zoomOut(const QRectF &rect)
103{
104 storeZoomReset();
105 QRectF fixedRect = fixZoomRect(rect);
106 qreal dx = spanX() / fixedRect.width();
107 qreal maxX = m_maxX;
108 qreal minX = m_minX;
109
110 minX = maxX - dx * fixedRect.right();
111 maxX = minX + dx * m_size.width();
112
113 const qreal factorY = m_size.height() / fixedRect.height();
114 qreal newLogMinY = m_logLeftY + (m_logRightY - m_logLeftY) / 2 * (1 - factorY);
115 qreal newLogMaxY = m_logLeftY + (m_logRightY - m_logLeftY) / 2 * (1 + factorY);
116 qreal leftY = qPow(x: m_logBaseY, y: newLogMinY);
117 qreal rightY = qPow(x: m_logBaseY, y: newLogMaxY);
118 qreal minY = leftY < rightY ? leftY : rightY;
119 qreal maxY = leftY > rightY ? leftY : rightY;
120
121 if (newLogMaxY > m_size.height())
122 return;
123
124 if (qIsInf(d: maxY))
125 return;
126
127 setRange(minX, maxX, minY, maxY);
128}
129
130void XLogYDomain::move(qreal dx, qreal dy)
131{
132 if (m_reverseX)
133 dx = -dx;
134 if (m_reverseY)
135 dy = -dy;
136
137 qreal x = spanX() / m_size.width();
138 qreal maxX = m_maxX;
139 qreal minX = m_minX;
140
141 if (dx != 0) {
142 minX = minX + x * dx;
143 maxX = maxX + x * dx;
144 }
145
146 qreal stepY = dy * (m_logRightY - m_logLeftY) / m_size.height();
147 qreal leftY = qPow(x: m_logBaseY, y: m_logLeftY + stepY);
148 qreal rightY = qPow(x: m_logBaseY, y: m_logRightY + stepY);
149 qreal minY = leftY < rightY ? leftY : rightY;
150 qreal maxY = leftY > rightY ? leftY : rightY;
151
152 setRange(minX, maxX, minY, maxY);
153}
154
155QPointF XLogYDomain::calculateGeometryPoint(const QPointF &point, bool &ok) const
156{
157 const qreal deltaX = m_size.width() / (m_maxX - m_minX);
158 const qreal deltaY = m_size.height() / qAbs(t: m_logRightY - m_logLeftY);
159
160 qreal x = (point.x() - m_minX) * deltaX;
161 if (m_reverseX)
162 x = m_size.width() - x;
163 qreal y(0);
164 if (point.y() > 0) {
165 y = ((std::log10(x: point.y()) / std::log10(x: m_logBaseY)) - m_logLeftY) * deltaY;
166 if (!m_reverseY)
167 y = m_size.height() - y;
168 ok = true;
169 } else {
170 y = m_size.height();
171 qWarning() << "Logarithms of zero and negative values are undefined.";
172 ok = false;
173 }
174 return QPointF(x, y);
175}
176
177QVector<QPointF> XLogYDomain::calculateGeometryPoints(const QVector<QPointF> &vector) const
178{
179 const qreal deltaX = m_size.width() / (m_maxX - m_minX);
180 const qreal deltaY = m_size.height() / qAbs(t: m_logRightY - m_logLeftY);
181
182 QVector<QPointF> result;
183 result.resize(size: vector.count());
184
185 for (int i = 0; i < vector.count(); ++i) {
186 if (vector[i].y() > 0) {
187 qreal x = (vector[i].x() - m_minX) * deltaX;
188 if (m_reverseX)
189 x = m_size.width() - x;
190 qreal y = ((std::log10(x: vector[i].y()) / std::log10(x: m_logBaseY)) - m_logLeftY) * deltaY;
191 if (!m_reverseY)
192 y = m_size.height() - y;
193 result[i].setX(x);
194 result[i].setY(y);
195 } else {
196 qWarning() << "Logarithms of zero and negative values are undefined.";
197 return QVector<QPointF>();
198 }
199 }
200 return result;
201}
202
203QPointF XLogYDomain::calculateDomainPoint(const QPointF &point) const
204{
205 const qreal deltaX = m_size.width() / (m_maxX - m_minX);
206 const qreal deltaY = m_size.height() / qAbs(t: m_logRightY - m_logLeftY);
207 qreal x = m_reverseX ? (m_size.width() - point.x()) : point.x();
208 x /= deltaX;
209 x += m_minX;
210 qreal y = m_reverseY ? point.y() : (m_size.height() - point.y());
211 y = qPow(x: m_logBaseY, y: m_logLeftY + y / deltaY);
212 return QPointF(x, y);
213}
214
215bool XLogYDomain::attachAxis(QAbstractAxis *axis)
216{
217 QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(object: axis);
218
219 if (logAxis && logAxis->orientation() == Qt::Vertical) {
220 QObject::connect(sender: logAxis, SIGNAL(baseChanged(qreal)), receiver: this, SLOT(handleVerticalAxisBaseChanged(qreal)));
221 handleVerticalAxisBaseChanged(baseY: logAxis->base());
222 }
223 return AbstractDomain::attachAxis(axis);
224}
225
226bool XLogYDomain::detachAxis(QAbstractAxis *axis)
227{
228 QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(object: axis);
229
230 if (logAxis && logAxis->orientation() == Qt::Vertical)
231 QObject::disconnect(sender: logAxis, SIGNAL(baseChanged(qreal)), receiver: this, SLOT(handleVerticalAxisBaseChanged(qreal)));
232
233 return AbstractDomain::detachAxis(axis);
234}
235
236void XLogYDomain::handleVerticalAxisBaseChanged(qreal baseY)
237{
238 m_logBaseY = baseY;
239 qreal logMinY = std::log10(x: m_minY) / std::log10(x: m_logBaseY);
240 qreal logMaxY = std::log10(x: m_maxY) / std::log10(x: m_logBaseY);
241 m_logLeftY = logMinY < logMaxY ? logMinY : logMaxY;
242 m_logRightY = logMinY > logMaxY ? logMinY : logMaxY;
243 emit updated();
244}
245
246// operators
247
248bool Q_AUTOTEST_EXPORT operator== (const XLogYDomain &domain1, const XLogYDomain &domain2)
249{
250 return (qFuzzyIsNull(d: domain1.m_maxX - domain2.m_maxX)
251 && qFuzzyIsNull(d: domain1.m_maxY - domain2.m_maxY)
252 && qFuzzyIsNull(d: domain1.m_minX - domain2.m_minX)
253 && qFuzzyIsNull(d: domain1.m_minY - domain2.m_minY));
254}
255
256
257bool Q_AUTOTEST_EXPORT operator!= (const XLogYDomain &domain1, const XLogYDomain &domain2)
258{
259 return !(domain1 == domain2);
260}
261
262
263QDebug Q_AUTOTEST_EXPORT operator<<(QDebug dbg, const XLogYDomain &domain)
264{
265#ifdef QT_NO_TEXTSTREAM
266 Q_UNUSED(domain)
267#else
268 dbg.nospace() << "AbstractDomain(" << domain.m_minX << ',' << domain.m_maxX << ',' << domain.m_minY << ',' << domain.m_maxY << ')' << domain.m_size;
269#endif
270 return dbg.maybeSpace();
271}
272
273QT_CHARTS_END_NAMESPACE
274
275#include "moc_xlogydomain_p.cpp"
276

source code of qtcharts/src/charts/domain/xlogydomain.cpp