File indexing completed on 2024-04-28 15:29:29
0001 /* -*- C++ -*- 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2005 Andreas Nicolai <Andreas.Nicolai@gmx.net> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "kplotaxis.h" 0009 0010 #include <math.h> //for log10(), pow(), modf() 0011 0012 class KPlotAxis::Private 0013 { 0014 public: 0015 Private(KPlotAxis *qq) 0016 : q(qq) 0017 , m_visible(true) 0018 , m_showTickLabels(false) 0019 , m_labelFmt('g') 0020 , m_labelFieldWidth(0) 0021 , m_labelPrec(-1) 0022 { 0023 } 0024 0025 KPlotAxis *q; 0026 0027 bool m_visible : 1; // Property "visible" defines if Axis is drawn or not. 0028 bool m_showTickLabels : 1; 0029 char m_labelFmt; // Number format for number labels, see QString::arg() 0030 QString m_label; // The label of the axis. 0031 int m_labelFieldWidth; // Field width for number labels, see QString::arg() 0032 int m_labelPrec; // Number precision for number labels, see QString::arg() 0033 QList<double> m_MajorTickMarks, m_MinorTickMarks; 0034 }; 0035 0036 KPlotAxis::KPlotAxis(const QString &label) 0037 : d(new Private(this)) 0038 { 0039 d->m_label = label; 0040 } 0041 0042 KPlotAxis::~KPlotAxis() 0043 { 0044 delete d; 0045 } 0046 0047 bool KPlotAxis::isVisible() const 0048 { 0049 return d->m_visible; 0050 } 0051 0052 void KPlotAxis::setVisible(bool visible) 0053 { 0054 d->m_visible = visible; 0055 } 0056 0057 bool KPlotAxis::areTickLabelsShown() const 0058 { 0059 return d->m_showTickLabels; 0060 } 0061 0062 void KPlotAxis::setTickLabelsShown(bool b) 0063 { 0064 d->m_showTickLabels = b; 0065 } 0066 0067 void KPlotAxis::setLabel(const QString &label) 0068 { 0069 d->m_label = label; 0070 } 0071 0072 QString KPlotAxis::label() const 0073 { 0074 return d->m_label; 0075 } 0076 0077 void KPlotAxis::setTickLabelFormat(char format, int fieldWidth, int precision) 0078 { 0079 d->m_labelFieldWidth = fieldWidth; 0080 d->m_labelFmt = format; 0081 d->m_labelPrec = precision; 0082 } 0083 0084 int KPlotAxis::tickLabelWidth() const 0085 { 0086 return d->m_labelFieldWidth; 0087 } 0088 0089 char KPlotAxis::tickLabelFormat() const 0090 { 0091 return d->m_labelFmt; 0092 } 0093 0094 int KPlotAxis::tickLabelPrecision() const 0095 { 0096 return d->m_labelPrec; 0097 } 0098 0099 void KPlotAxis::setTickMarks(double x0, double length) 0100 { 0101 d->m_MajorTickMarks.clear(); 0102 d->m_MinorTickMarks.clear(); 0103 0104 // s is the power-of-ten factor of length: 0105 // length = t * s; s = 10^(pwr). e.g., length=350.0 then t=3.5, s = 100.0; pwr = 2.0 0106 double pwr = 0.0; 0107 modf(log10(length), &pwr); 0108 double s = pow(10.0, pwr); 0109 double t = length / s; 0110 0111 double TickDistance = 0.0; // The distance between major tickmarks 0112 int NumMajorTicks = 0; // will be between 3 and 5 0113 int NumMinorTicks = 0; // The number of minor ticks between major ticks (will be 4 or 5) 0114 0115 // adjust s and t such that t is between 3 and 5: 0116 if (t < 3.0) { 0117 t *= 10.0; 0118 s /= 10.0; 0119 // t is now between 3 and 30 0120 } 0121 0122 if (t < 6.0) { // accept current values 0123 TickDistance = s; 0124 NumMajorTicks = int(t); 0125 NumMinorTicks = 5; 0126 } else if (t < 10.0) { // adjust by a factor of 2 0127 TickDistance = s * 2.0; 0128 NumMajorTicks = int(t / 2.0); 0129 NumMinorTicks = 4; 0130 } else if (t < 20.0) { // adjust by a factor of 4 0131 TickDistance = s * 4.0; 0132 NumMajorTicks = int(t / 4.0); 0133 NumMinorTicks = 4; 0134 } else { // adjust by a factor of 5 0135 TickDistance = s * 5.0; 0136 NumMajorTicks = int(t / 5.0); 0137 NumMinorTicks = 5; 0138 } 0139 0140 // We have determined the number of tickmarks and their separation 0141 // Now we determine their positions in the Data space. 0142 0143 // Tick0 is the position of a "virtual" tickmark; the first major tickmark 0144 // position beyond the "minimum" edge of the data range. 0145 double Tick0 = x0 - fmod(x0, TickDistance); 0146 if (x0 < 0.0) { 0147 Tick0 -= TickDistance; 0148 NumMajorTicks++; 0149 } 0150 0151 for (int i = 0; i < NumMajorTicks + 2; i++) { 0152 double xmaj = Tick0 + i * TickDistance; 0153 if (xmaj >= x0 && xmaj <= x0 + length) { 0154 d->m_MajorTickMarks.append(xmaj); 0155 } 0156 0157 for (int j = 1; j < NumMinorTicks; j++) { 0158 double xmin = xmaj + TickDistance * j / NumMinorTicks; 0159 if (xmin >= x0 && xmin <= x0 + length) { 0160 d->m_MinorTickMarks.append(xmin); 0161 } 0162 } 0163 } 0164 } 0165 0166 QString KPlotAxis::tickLabel(double val) const 0167 { 0168 if (d->m_labelFmt == 't') { 0169 while (val < 0.0) { 0170 val += 24.0; 0171 } 0172 while (val >= 24.0) { 0173 val -= 24.0; 0174 } 0175 0176 int h = int(val); 0177 int m = int(60. * (val - h)); 0178 return QStringLiteral("%1:%2").arg(h, 2, 10, QLatin1Char('0')).arg(m, 2, 10, QLatin1Char('0')); 0179 } 0180 0181 return QStringLiteral("%1").arg(val, d->m_labelFieldWidth, d->m_labelFmt, d->m_labelPrec); 0182 } 0183 0184 QList<double> KPlotAxis::majorTickMarks() const 0185 { 0186 return d->m_MajorTickMarks; 0187 } 0188 0189 QList<double> KPlotAxis::minorTickMarks() const 0190 { 0191 return d->m_MinorTickMarks; 0192 }