1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include <private/logxypolardomain_p.h>
5#include <private/qabstractaxis_p.h>
6#include <QtCharts/QLogValueAxis>
7#include <QtCore/QtMath>
8#include <cmath>
9
10QT_BEGIN_NAMESPACE
11
12LogXYPolarDomain::LogXYPolarDomain(QObject *parent)
13 : PolarDomain(parent),
14 m_logLeftX(0),
15 m_logRightX(1),
16 m_logBaseX(10)
17{
18}
19
20LogXYPolarDomain::~LogXYPolarDomain()
21{
22}
23
24void LogXYPolarDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY)
25{
26 bool axisXChanged = false;
27 bool axisYChanged = false;
28
29 adjustLogDomainRanges(min&: minX, max&: maxX);
30
31 if (!qFuzzyCompare(p1: m_minX, p2: minX) || !qFuzzyCompare(p1: m_maxX, p2: maxX)) {
32 m_minX = minX;
33 m_maxX = maxX;
34 axisXChanged = true;
35 qreal logMinX = qLn(v: m_minX) / qLn(v: m_logBaseX);
36 qreal logMaxX = qLn(v: m_maxX) / qLn(v: m_logBaseX);
37 m_logLeftX = logMinX < logMaxX ? logMinX : logMaxX;
38 m_logRightX = logMinX > logMaxX ? logMinX : logMaxX;
39 if (!m_signalsBlocked)
40 emit rangeHorizontalChanged(min: m_minX, max: m_maxX);
41 }
42
43 if (!qFuzzyIsNull(d: m_minY - minY) || !qFuzzyIsNull(d: m_maxY - maxY)) {
44 m_minY = minY;
45 m_maxY = maxY;
46 axisYChanged = true;
47 if (!m_signalsBlocked)
48 emit rangeVerticalChanged(min: m_minY, max: m_maxY);
49 }
50
51 if (axisXChanged || axisYChanged)
52 emit updated();
53}
54
55void LogXYPolarDomain::zoomIn(const QRectF &rect)
56{
57 storeZoomReset();
58 qreal logLeftX = rect.left() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX;
59 qreal logRightX = rect.right() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX;
60 qreal leftX = qPow(x: m_logBaseX, y: logLeftX);
61 qreal rightX = qPow(x: m_logBaseX, y: logRightX);
62 qreal minX = leftX < rightX ? leftX : rightX;
63 qreal maxX = leftX > rightX ? leftX : rightX;
64
65 qreal dy = spanY() / m_size.height();
66 qreal minY = m_minY;
67 qreal maxY = m_maxY;
68
69 minY = maxY - dy * rect.bottom();
70 maxY = maxY - dy * rect.top();
71
72 setRange(minX, maxX, minY, maxY);
73}
74
75void LogXYPolarDomain::zoomOut(const QRectF &rect)
76{
77 storeZoomReset();
78 const qreal factorX = m_size.width() / rect.width();
79
80 qreal logLeftX = m_logLeftX + (m_logRightX - m_logLeftX) / 2.0 * (1.0 - factorX);
81 qreal logRIghtX = m_logLeftX + (m_logRightX - m_logLeftX) / 2.0 * (1.0 + factorX);
82 qreal leftX = qPow(x: m_logBaseX, y: logLeftX);
83 qreal rightX = qPow(x: m_logBaseX, y: logRIghtX);
84 qreal minX = leftX < rightX ? leftX : rightX;
85 qreal maxX = leftX > rightX ? leftX : rightX;
86
87 qreal dy = spanY() / rect.height();
88 qreal minY = m_minY;
89 qreal maxY = m_maxY;
90
91 maxY = minY + dy * rect.bottom();
92 minY = maxY - dy * m_size.height();
93
94 setRange(minX, maxX, minY, maxY);
95}
96
97void LogXYPolarDomain::move(qreal dx, qreal dy)
98{
99 qreal stepX = dx * (m_logRightX - m_logLeftX) / m_size.width();
100 qreal leftX = qPow(x: m_logBaseX, y: m_logLeftX + stepX);
101 qreal rightX = qPow(x: m_logBaseX, y: m_logRightX + stepX);
102 qreal minX = leftX < rightX ? leftX : rightX;
103 qreal maxX = leftX > rightX ? leftX : rightX;
104
105 qreal y = spanY() / m_radius;
106 qreal minY = m_minY;
107 qreal maxY = m_maxY;
108
109 if (dy != 0) {
110 minY = minY + y * dy;
111 maxY = maxY + y * dy;
112 }
113 setRange(minX, maxX, minY, maxY);
114}
115
116qreal LogXYPolarDomain::toAngularCoordinate(qreal value, bool &ok) const
117{
118 qreal retVal;
119 if (value <= 0) {
120 ok = false;
121 retVal = 0.0;
122 } else {
123 ok = true;
124 const qreal tickSpan = 360.0 / qAbs(t: m_logRightX - m_logLeftX);
125 const qreal logValue = qLn(v: value) / qLn(v: m_logBaseX);
126 const qreal valueDelta = logValue - m_logLeftX;
127
128 retVal = valueDelta * tickSpan;
129 }
130 return retVal;
131}
132
133qreal LogXYPolarDomain::toRadialCoordinate(qreal value, bool &ok) const
134{
135 ok = true;
136 if (value < m_minY)
137 value = m_minY;
138
139 // Dont limit the max. The drawing should clip the stuff that goes out of the grid
140 qreal f = (value - m_minY) / (m_maxY - m_minY);
141
142 return f * m_radius;
143}
144
145QPointF LogXYPolarDomain::calculateDomainPoint(const QPointF &point) const
146{
147 if (point == m_center)
148 return QPointF(0.0, m_minY);
149
150 QLineF line(m_center, point);
151 qreal a = 90.0 - line.angle();
152 if (a < 0.0)
153 a += 360.0;
154
155 const qreal deltaX = 360.0 / qAbs(t: m_logRightX - m_logLeftX);
156 a = qPow(x: m_logBaseX, y: m_logLeftX + (a / deltaX));
157
158 qreal r = m_minY + ((m_maxY - m_minY) * (line.length() / m_radius));
159
160 return QPointF(a, r);
161}
162
163bool LogXYPolarDomain::attachAxis(QAbstractAxis *axis)
164{
165 AbstractDomain::attachAxis(axis);
166 QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(object: axis);
167
168 if (logAxis && logAxis->orientation() == Qt::Horizontal) {
169 QObject::connect(sender: logAxis, SIGNAL(baseChanged(qreal)), receiver: this, SLOT(handleHorizontalAxisBaseChanged(qreal)));
170 handleHorizontalAxisBaseChanged(baseX: logAxis->base());
171 }
172
173 return true;
174}
175
176bool LogXYPolarDomain::detachAxis(QAbstractAxis *axis)
177{
178 AbstractDomain::detachAxis(axis);
179 QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(object: axis);
180
181 if (logAxis && logAxis->orientation() == Qt::Horizontal)
182 QObject::disconnect(sender: logAxis, SIGNAL(baseChanged(qreal)), receiver: this, SLOT(handleHorizontalAxisBaseChanged(qreal)));
183
184 return true;
185}
186
187void LogXYPolarDomain::handleHorizontalAxisBaseChanged(qreal baseX)
188{
189 m_logBaseX = baseX;
190 qreal logMinX = qLn(v: m_minX) / qLn(v: m_logBaseX);
191 qreal logMaxX = qLn(v: m_maxX) / qLn(v: m_logBaseX);
192 m_logLeftX = logMinX < logMaxX ? logMinX : logMaxX;
193 m_logRightX = logMinX > logMaxX ? logMinX : logMaxX;
194 emit updated();
195}
196
197// operators
198
199bool Q_AUTOTEST_EXPORT operator== (const LogXYPolarDomain &domain1, const LogXYPolarDomain &domain2)
200{
201 return (qFuzzyIsNull(d: domain1.m_maxX - domain2.m_maxX)
202 && qFuzzyIsNull(d: domain1.m_maxY - domain2.m_maxY)
203 && qFuzzyIsNull(d: domain1.m_minX - domain2.m_minX)
204 && qFuzzyIsNull(d: domain1.m_minY - domain2.m_minY));
205}
206
207
208bool Q_AUTOTEST_EXPORT operator!= (const LogXYPolarDomain &domain1, const LogXYPolarDomain &domain2)
209{
210 return !(domain1 == domain2);
211}
212
213
214QDebug Q_AUTOTEST_EXPORT operator<<(QDebug dbg, const LogXYPolarDomain &domain)
215{
216#ifdef QT_NO_TEXTSTREAM
217 Q_UNUSED(domain);
218#else
219 dbg.nospace() << "AbstractDomain(" << domain.m_minX << ',' << domain.m_maxX << ',' << domain.m_minY << ',' << domain.m_maxY << ')' << domain.m_size;
220#endif
221 return dbg.maybeSpace();
222}
223
224QT_END_NAMESPACE
225
226#include "moc_logxypolardomain_p.cpp"
227

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