comparison base/ScaleTickIntervals.h @ 1414:c57994e1edd7 scale-ticks

Add logarithmic ticks. This is getting complicated!
author Chris Cannam
date Thu, 04 May 2017 10:14:56 +0100
parents c6fa111b4553
children 12316a9bcc8f
comparison
equal deleted inserted replaced
1413:c6fa111b4553 1414:c57994e1edd7
24 24
25 #ifdef DEBUG_SCALE_TICK_INTERVALS 25 #ifdef DEBUG_SCALE_TICK_INTERVALS
26 #include <iostream> 26 #include <iostream>
27 #endif 27 #endif
28 28
29 #include "LogRange.h"
30
29 class ScaleTickIntervals 31 class ScaleTickIntervals
30 { 32 {
31 public: 33 public:
32 struct Range { 34 struct Range {
33 double min; // start of value range 35 double min; // start of value range
48 int precision; // number of dp (%f) or sf (%e) 50 int precision; // number of dp (%f) or sf (%e)
49 std::vector<Tick> ticks; // computed tick values and labels 51 std::vector<Tick> ticks; // computed tick values and labels
50 }; 52 };
51 53
52 static Ticks linear(Range r) { 54 static Ticks linear(Range r) {
53 55 return linearTicks(r);
56 }
57
58 static Ticks logarithmic(Range r) {
59 return logTicks(r);
60 }
61
62 private:
63 static Ticks unexplodedTicks(Range r)
64 {
54 if (r.n < 1) { 65 if (r.n < 1) {
55 return {}; 66 return {};
56 } 67 }
57 if (r.max < r.min) { 68 if (r.max < r.min) {
58 return linear({ r.max, r.min, r.n }); 69 return unexplodedTicks({ r.max, r.min, r.n });
59 } 70 }
60 71
61 double inc = (r.max - r.min) / r.n; 72 double inc = (r.max - r.min) / r.n;
62 if (inc == 0) { 73 if (inc == 0) {
63 #ifdef DEBUG_SCALE_TICK_INTERVALS 74 #ifdef DEBUG_SCALE_TICK_INTERVALS
66 double roundTo = r.min; 77 double roundTo = r.min;
67 if (roundTo <= 0.0) { 78 if (roundTo <= 0.0) {
68 roundTo = 1.0; 79 roundTo = 1.0;
69 } 80 }
70 Ticks t { r.min, 1.0, roundTo, true, 1, {} }; 81 Ticks t { r.min, 1.0, roundTo, true, 1, {} };
71 explode(r, t);
72 return t; 82 return t;
73 } 83 }
74 84
75 double digInc = log10(inc); 85 double digInc = log10(inc);
76 double digMax = log10(fabs(r.max)); 86 double digMax = log10(fabs(r.max));
132 #endif 142 #endif
133 } 143 }
134 } 144 }
135 145
136 Ticks t { min, inc, roundTo, fixed, prec, {} }; 146 Ticks t { min, inc, roundTo, fixed, prec, {} };
137 explode(r, t);
138 return t; 147 return t;
139 } 148 }
140 149
141 private: 150 static Ticks linearTicks(Range r) {
142 static void explode(const Range &r, Ticks &t) { 151 Ticks t = unexplodedTicks(r);
152 explode(r, t, false);
153 return t;
154 }
155
156 static Ticks logTicks(Range r) {
157 Range mapped(r);
158 LogRange::mapRange(mapped.min, mapped.max);
159 Ticks t = unexplodedTicks(mapped);
160 if (fabs(mapped.min - mapped.max) > 3) {
161 t.fixed = false;
162 }
163 explode(mapped, t, true);
164 return t;
165 }
166
167 static Tick makeTick(bool fixed, int precision, double value) {
168 const int buflen = 40;
169 char buffer[buflen];
170 snprintf(buffer, buflen,
171 fixed ? "%.*f" : "%.*e",
172 precision, value);
173 return Tick({ value, std::string(buffer) });
174 }
175
176 static void explode(const Range &r, Ticks &t, bool logUnmap) {
143 #ifdef DEBUG_SCALE_TICK_INTERVALS 177 #ifdef DEBUG_SCALE_TICK_INTERVALS
144 std::cerr << "initial = " << t.initial << ", spacing = " << t.spacing 178 std::cerr << "initial = " << t.initial << ", spacing = " << t.spacing
145 << ", roundTo = " << t.roundTo << ", fixed = " << t.fixed 179 << ", roundTo = " << t.roundTo << ", fixed = " << t.fixed
146 << ", precision = " << t.precision << std::endl; 180 << ", precision = " << t.precision << std::endl;
147 #endif 181 #endif
148 auto makeTick = [&](double value) { 182 if (t.spacing == 0.0) {
149 const int buflen = 40; 183 return;
150 char buffer[buflen]; 184 }
151 snprintf(buffer, buflen,
152 t.fixed ? "%.*f" : "%.*e",
153 t.precision, value);
154 return Tick({ value, std::string(buffer) });
155 };
156 double eps = 1e-7; 185 double eps = 1e-7;
157 if (t.spacing < eps * 10.0) { 186 if (t.spacing < eps * 10.0) {
158 eps = t.spacing / 10.0; 187 eps = t.spacing / 10.0;
159 } 188 }
189 double max = std::max(r.min, r.max);
160 int n = 0; 190 int n = 0;
161 while (true) { 191 while (true) {
162 double value = t.initial + n * t.spacing; 192 double value = t.initial + n * t.spacing;
163 value = t.roundTo * round(value / t.roundTo); 193 value = t.roundTo * round(value / t.roundTo);
164 if (value >= r.max + eps) { 194 if (value >= max + eps) {
165 break; 195 break;
166 } 196 }
167 t.ticks.push_back(makeTick(value)); 197 if (logUnmap) {
198 value = pow(10.0, value);
199 }
200 t.ticks.push_back(makeTick(t.fixed, t.precision, value));
168 ++n; 201 ++n;
169 } 202 }
170 } 203 }
171 }; 204 };
172 205