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