comparison base/ScaleTickIntervals.h @ 1417:359147a50853 scale-ticks

We don't need to return the tick instruction gubbins
author Chris Cannam
date Thu, 04 May 2017 13:32:42 +0100
parents 12316a9bcc8f
children e7cb4fb2aee4
comparison
equal deleted inserted replaced
1416:9a8995785827 1417:359147a50853
18 18
19 #include <string> 19 #include <string>
20 #include <vector> 20 #include <vector>
21 #include <cmath> 21 #include <cmath>
22 22
23 //#define DEBUG_SCALE_TICK_INTERVALS 1 23 #define DEBUG_SCALE_TICK_INTERVALS 1
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
40 struct Tick { 40 struct Tick {
41 double value; // value this tick represents 41 double value; // value this tick represents
42 std::string label; // value as written 42 std::string label; // value as written
43 }; 43 };
44 44
45 struct Ticks { 45 typedef std::vector<Tick> Ticks;
46
47 static Ticks linear(Range r) {
48 return linearTicks(r);
49 }
50
51 static Ticks logarithmic(Range r) {
52 return logTicks(r);
53 }
54
55 private:
56 struct Instruction {
46 double initial; // value of first tick 57 double initial; // value of first tick
58 double limit; // max from original range
47 double spacing; // increment between ticks 59 double spacing; // increment between ticks
48 double roundTo; // what all displayed values should be rounded to 60 double roundTo; // what all displayed values should be rounded to
49 bool fixed; // whether to use fixed precision (%f rather than %e) 61 bool fixed; // whether to use fixed precision (%f rather than %e)
50 int precision; // number of dp (%f) or sf (%e) 62 int precision; // number of dp (%f) or sf (%e)
51 std::vector<Tick> ticks; // computed tick values and labels 63 bool logUnmap; // true if values represent logs of display values
52 }; 64 };
53 65
54 static Ticks linear(Range r) { 66 static Instruction linearInstruction(Range r)
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 { 67 {
65 if (r.n < 1) { 68 if (r.n < 1) {
66 return {}; 69 return {};
67 } 70 }
68 if (r.max < r.min) { 71 if (r.max < r.min) {
69 return unexplodedTicks({ r.max, r.min, r.n }); 72 return linearInstruction({ r.max, r.min, r.n });
70 } 73 }
71 74
72 double inc = (r.max - r.min) / r.n; 75 double inc = (r.max - r.min) / r.n;
73 if (inc == 0) { 76 if (inc == 0) {
74 #ifdef DEBUG_SCALE_TICK_INTERVALS 77 #ifdef DEBUG_SCALE_TICK_INTERVALS
76 #endif 79 #endif
77 double roundTo = r.min; 80 double roundTo = r.min;
78 if (roundTo <= 0.0) { 81 if (roundTo <= 0.0) {
79 roundTo = 1.0; 82 roundTo = 1.0;
80 } 83 }
81 Ticks t { r.min, 1.0, roundTo, true, 1, {} }; 84 return { r.min, r.max, 1.0, roundTo, true, 1, false };
82 return t;
83 } 85 }
84 86
85 double digInc = log10(inc); 87 double digInc = log10(inc);
86 double digMax = log10(fabs(r.max)); 88 double digMax = log10(fabs(r.max));
87 double digMin = log10(fabs(r.min)); 89 double digMin = log10(fabs(r.min));
141 << prec << std::endl; 143 << prec << std::endl;
142 #endif 144 #endif
143 } 145 }
144 } 146 }
145 147
146 Ticks t { min, inc, roundTo, fixed, prec, {} }; 148 return { min, r.max, inc, roundTo, fixed, prec, false };
147 return t;
148 } 149 }
149 150
150 static Ticks linearTicks(Range r) { 151 static Ticks linearTicks(Range r) {
151 Ticks t = unexplodedTicks(r); 152 Instruction instruction = linearInstruction(r);
152 explode(r, t, false); 153 Ticks ticks = explode(instruction);
153 return t; 154 return ticks;
154 } 155 }
155 156
156 static Ticks logTicks(Range r) { 157 static Ticks logTicks(Range r) {
157 Range mapped(r); 158 Range mapped(r);
158 LogRange::mapRange(mapped.min, mapped.max); 159 LogRange::mapRange(mapped.min, mapped.max);
159 Ticks t = unexplodedTicks(mapped); 160 Instruction instruction = linearInstruction(mapped);
161 instruction.logUnmap = true;
160 if (fabs(mapped.min - mapped.max) > 3) { 162 if (fabs(mapped.min - mapped.max) > 3) {
161 t.fixed = false; 163 instruction.fixed = false;
162 } 164 }
163 explode(mapped, t, true); 165 Ticks ticks = explode(instruction);
164 return t; 166 return ticks;
165 } 167 }
166 168
167 static Tick makeTick(bool fixed, int precision, double value) { 169 static Tick makeTick(bool fixed, int precision, double value) {
168 const int buflen = 40; 170 const int buflen = 40;
169 char buffer[buflen]; 171 char buffer[buflen];
171 fixed ? "%.*f" : "%.*e", 173 fixed ? "%.*f" : "%.*e",
172 precision, value); 174 precision, value);
173 return Tick({ value, std::string(buffer) }); 175 return Tick({ value, std::string(buffer) });
174 } 176 }
175 177
176 static void explode(const Range &r, Ticks &t, bool logUnmap) { 178 static Ticks explode(Instruction instruction) {
177 #ifdef DEBUG_SCALE_TICK_INTERVALS 179
178 std::cerr << "initial = " << t.initial << ", spacing = " << t.spacing 180 #ifdef DEBUG_SCALE_TICK_INTERVALS
179 << ", roundTo = " << t.roundTo << ", fixed = " << t.fixed 181 std::cerr << "initial = " << instruction.initial
180 << ", precision = " << t.precision << std::endl; 182 << ", limit = " << instruction.limit
181 #endif 183 << ", spacing = " << instruction.spacing
182 if (t.spacing == 0.0) { 184 << ", roundTo = " << instruction.roundTo
183 return; 185 << ", fixed = " << instruction.fixed
184 } 186 << ", precision = " << instruction.precision
187 << ", logUnmap = " << instruction.logUnmap
188 << std::endl;
189 #endif
190
191 if (instruction.spacing == 0.0) {
192 return {};
193 }
194
185 double eps = 1e-7; 195 double eps = 1e-7;
186 if (t.spacing < eps * 10.0) { 196 if (instruction.spacing < eps * 10.0) {
187 eps = t.spacing / 10.0; 197 eps = instruction.spacing / 10.0;
188 } 198 }
189 double max = std::max(r.min, r.max); 199
200 double max = instruction.limit;
190 int n = 0; 201 int n = 0;
202
203 Ticks ticks;
204
191 while (true) { 205 while (true) {
192 double value = t.initial + n * t.spacing; 206 double value = instruction.initial + n * instruction.spacing;
193 value = t.roundTo * round(value / t.roundTo); 207 value = instruction.roundTo * round(value / instruction.roundTo);
194 if (value >= max + eps) { 208 if (value >= max + eps) {
195 break; 209 break;
196 } 210 }
197 if (logUnmap) { 211 if (instruction.logUnmap) {
198 value = pow(10.0, value); 212 value = pow(10.0, value);
199 } 213 }
200 t.ticks.push_back(makeTick(t.fixed, t.precision, value)); 214 ticks.push_back(makeTick(instruction.fixed,
215 instruction.precision,
216 value));
201 ++n; 217 ++n;
202 } 218 }
219
220 return ticks;
203 } 221 }
204 }; 222 };
205 223
206 #endif 224 #endif