File indexing completed on 2024-04-28 03:56:42
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() = default; 0043 0044 bool KPlotAxis::isVisible() const 0045 { 0046 return d->m_visible; 0047 } 0048 0049 void KPlotAxis::setVisible(bool visible) 0050 { 0051 d->m_visible = visible; 0052 } 0053 0054 bool KPlotAxis::areTickLabelsShown() const 0055 { 0056 return d->m_showTickLabels; 0057 } 0058 0059 void KPlotAxis::setTickLabelsShown(bool b) 0060 { 0061 d->m_showTickLabels = b; 0062 } 0063 0064 void KPlotAxis::setLabel(const QString &label) 0065 { 0066 d->m_label = label; 0067 } 0068 0069 QString KPlotAxis::label() const 0070 { 0071 return d->m_label; 0072 } 0073 0074 void KPlotAxis::setTickLabelFormat(char format, int fieldWidth, int precision) 0075 { 0076 d->m_labelFieldWidth = fieldWidth; 0077 d->m_labelFmt = format; 0078 d->m_labelPrec = precision; 0079 } 0080 0081 int KPlotAxis::tickLabelWidth() const 0082 { 0083 return d->m_labelFieldWidth; 0084 } 0085 0086 char KPlotAxis::tickLabelFormat() const 0087 { 0088 return d->m_labelFmt; 0089 } 0090 0091 int KPlotAxis::tickLabelPrecision() const 0092 { 0093 return d->m_labelPrec; 0094 } 0095 0096 void KPlotAxis::setTickMarks(double x0, double length) 0097 { 0098 d->m_MajorTickMarks.clear(); 0099 d->m_MinorTickMarks.clear(); 0100 0101 // s is the power-of-ten factor of length: 0102 // length = t * s; s = 10^(pwr). e.g., length=350.0 then t=3.5, s = 100.0; pwr = 2.0 0103 double pwr = 0.0; 0104 modf(log10(length), &pwr); 0105 double s = pow(10.0, pwr); 0106 double t = length / s; 0107 0108 double TickDistance = 0.0; // The distance between major tickmarks 0109 int NumMajorTicks = 0; // will be between 3 and 5 0110 int NumMinorTicks = 0; // The number of minor ticks between major ticks (will be 4 or 5) 0111 0112 // adjust s and t such that t is between 3 and 5: 0113 if (t < 3.0) { 0114 t *= 10.0; 0115 s /= 10.0; 0116 // t is now between 3 and 30 0117 } 0118 0119 if (t < 6.0) { // accept current values 0120 TickDistance = s; 0121 NumMajorTicks = int(t); 0122 NumMinorTicks = 5; 0123 } else if (t < 10.0) { // adjust by a factor of 2 0124 TickDistance = s * 2.0; 0125 NumMajorTicks = int(t / 2.0); 0126 NumMinorTicks = 4; 0127 } else if (t < 20.0) { // adjust by a factor of 4 0128 TickDistance = s * 4.0; 0129 NumMajorTicks = int(t / 4.0); 0130 NumMinorTicks = 4; 0131 } else { // adjust by a factor of 5 0132 TickDistance = s * 5.0; 0133 NumMajorTicks = int(t / 5.0); 0134 NumMinorTicks = 5; 0135 } 0136 0137 // We have determined the number of tickmarks and their separation 0138 // Now we determine their positions in the Data space. 0139 0140 // Tick0 is the position of a "virtual" tickmark; the first major tickmark 0141 // position beyond the "minimum" edge of the data range. 0142 double Tick0 = x0 - fmod(x0, TickDistance); 0143 if (x0 < 0.0) { 0144 Tick0 -= TickDistance; 0145 NumMajorTicks++; 0146 } 0147 0148 for (int i = 0; i < NumMajorTicks + 2; i++) { 0149 double xmaj = Tick0 + i * TickDistance; 0150 if (xmaj >= x0 && xmaj <= x0 + length) { 0151 d->m_MajorTickMarks.append(xmaj); 0152 } 0153 0154 for (int j = 1; j < NumMinorTicks; j++) { 0155 double xmin = xmaj + TickDistance * j / NumMinorTicks; 0156 if (xmin >= x0 && xmin <= x0 + length) { 0157 d->m_MinorTickMarks.append(xmin); 0158 } 0159 } 0160 } 0161 } 0162 0163 QString KPlotAxis::tickLabel(double val) const 0164 { 0165 if (d->m_labelFmt == 't') { 0166 while (val < 0.0) { 0167 val += 24.0; 0168 } 0169 while (val >= 24.0) { 0170 val -= 24.0; 0171 } 0172 0173 int h = int(val); 0174 int m = int(60. * (val - h)); 0175 return QStringLiteral("%1:%2").arg(h, 2, 10, QLatin1Char('0')).arg(m, 2, 10, QLatin1Char('0')); 0176 } 0177 0178 return QStringLiteral("%1").arg(val, d->m_labelFieldWidth, d->m_labelFmt, d->m_labelPrec); 0179 } 0180 0181 QList<double> KPlotAxis::majorTickMarks() const 0182 { 0183 return d->m_MajorTickMarks; 0184 } 0185 0186 QList<double> KPlotAxis::minorTickMarks() const 0187 { 0188 return d->m_MinorTickMarks; 0189 }