Mercurial > hg > svcore
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 |