1/* -*- C++ -*-
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2005 Andreas Nicolai <Andreas.Nicolai@gmx.net>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "kplotaxis.h"
9
10#include <math.h> //for log10(), pow(), modf()
11
12class KPlotAxis::Private
13{
14public:
15 Private(KPlotAxis *qq)
16 : q(qq)
17 , m_visible(true)
18 , m_showTickLabels(false)
19 , m_labelFmt('g')
20 , m_labelFieldWidth(0)
21 , m_labelPrec(-1)
22 {
23 }
24
25 KPlotAxis *q;
26
27 bool m_visible : 1; // Property "visible" defines if Axis is drawn or not.
28 bool m_showTickLabels : 1;
29 char m_labelFmt; // Number format for number labels, see QString::arg()
30 QString m_label; // The label of the axis.
31 int m_labelFieldWidth; // Field width for number labels, see QString::arg()
32 int m_labelPrec; // Number precision for number labels, see QString::arg()
33 QList<double> m_MajorTickMarks, m_MinorTickMarks;
34};
35
36KPlotAxis::KPlotAxis(const QString &label)
37 : d(new Private(this))
38{
39 d->m_label = label;
40}
41
42KPlotAxis::~KPlotAxis() = default;
43
44bool KPlotAxis::isVisible() const
45{
46 return d->m_visible;
47}
48
49void KPlotAxis::setVisible(bool visible)
50{
51 d->m_visible = visible;
52}
53
54bool KPlotAxis::areTickLabelsShown() const
55{
56 return d->m_showTickLabels;
57}
58
59void KPlotAxis::setTickLabelsShown(bool b)
60{
61 d->m_showTickLabels = b;
62}
63
64void KPlotAxis::setLabel(const QString &label)
65{
66 d->m_label = label;
67}
68
69QString KPlotAxis::label() const
70{
71 return d->m_label;
72}
73
74void KPlotAxis::setTickLabelFormat(char format, int fieldWidth, int precision)
75{
76 d->m_labelFieldWidth = fieldWidth;
77 d->m_labelFmt = format;
78 d->m_labelPrec = precision;
79}
80
81int KPlotAxis::tickLabelWidth() const
82{
83 return d->m_labelFieldWidth;
84}
85
86char KPlotAxis::tickLabelFormat() const
87{
88 return d->m_labelFmt;
89}
90
91int KPlotAxis::tickLabelPrecision() const
92{
93 return d->m_labelPrec;
94}
95
96void KPlotAxis::setTickMarks(double x0, double length)
97{
98 d->m_MajorTickMarks.clear();
99 d->m_MinorTickMarks.clear();
100
101 // s is the power-of-ten factor of length:
102 // length = t * s; s = 10^(pwr). e.g., length=350.0 then t=3.5, s = 100.0; pwr = 2.0
103 double pwr = 0.0;
104 modf(x: log10(x: length), iptr: &pwr);
105 double s = pow(x: 10.0, y: pwr);
106 double t = length / s;
107
108 double TickDistance = 0.0; // The distance between major tickmarks
109 int NumMajorTicks = 0; // will be between 3 and 5
110 int NumMinorTicks = 0; // The number of minor ticks between major ticks (will be 4 or 5)
111
112 // adjust s and t such that t is between 3 and 5:
113 if (t < 3.0) {
114 t *= 10.0;
115 s /= 10.0;
116 // t is now between 3 and 30
117 }
118
119 if (t < 6.0) { // accept current values
120 TickDistance = s;
121 NumMajorTicks = int(t);
122 NumMinorTicks = 5;
123 } else if (t < 10.0) { // adjust by a factor of 2
124 TickDistance = s * 2.0;
125 NumMajorTicks = int(t / 2.0);
126 NumMinorTicks = 4;
127 } else if (t < 20.0) { // adjust by a factor of 4
128 TickDistance = s * 4.0;
129 NumMajorTicks = int(t / 4.0);
130 NumMinorTicks = 4;
131 } else { // adjust by a factor of 5
132 TickDistance = s * 5.0;
133 NumMajorTicks = int(t / 5.0);
134 NumMinorTicks = 5;
135 }
136
137 // We have determined the number of tickmarks and their separation
138 // Now we determine their positions in the Data space.
139
140 // Tick0 is the position of a "virtual" tickmark; the first major tickmark
141 // position beyond the "minimum" edge of the data range.
142 double Tick0 = x0 - fmod(x: x0, y: TickDistance);
143 if (x0 < 0.0) {
144 Tick0 -= TickDistance;
145 NumMajorTicks++;
146 }
147
148 for (int i = 0; i < NumMajorTicks + 2; i++) {
149 double xmaj = Tick0 + i * TickDistance;
150 if (xmaj >= x0 && xmaj <= x0 + length) {
151 d->m_MajorTickMarks.append(t: xmaj);
152 }
153
154 for (int j = 1; j < NumMinorTicks; j++) {
155 double xmin = xmaj + TickDistance * j / NumMinorTicks;
156 if (xmin >= x0 && xmin <= x0 + length) {
157 d->m_MinorTickMarks.append(t: xmin);
158 }
159 }
160 }
161}
162
163QString KPlotAxis::tickLabel(double val) const
164{
165 if (d->m_labelFmt == 't') {
166 while (val < 0.0) {
167 val += 24.0;
168 }
169 while (val >= 24.0) {
170 val -= 24.0;
171 }
172
173 int h = int(val);
174 int m = int(60. * (val - h));
175 return QStringLiteral("%1:%2").arg(a: h, fieldWidth: 2, base: 10, fillChar: QLatin1Char('0')).arg(a: m, fieldWidth: 2, base: 10, fillChar: QLatin1Char('0'));
176 }
177
178 return QStringLiteral("%1").arg(a: val, fieldWidth: d->m_labelFieldWidth, format: d->m_labelFmt, precision: d->m_labelPrec);
179}
180
181QList<double> KPlotAxis::majorTickMarks() const
182{
183 return d->m_MajorTickMarks;
184}
185
186QList<double> KPlotAxis::minorTickMarks() const
187{
188 return d->m_MinorTickMarks;
189}
190

source code of kplotting/src/kplotaxis.cpp