Mercurial > hg > svcore
comparison base/ScaleTickIntervals.h @ 1407:25ed6dde2ce0 scale-ticks
Scale tick labeller, and tests (some failing so far)
author | Chris Cannam |
---|---|
date | Wed, 03 May 2017 13:02:08 +0100 |
parents | |
children | f89365917d02 |
comparison
equal
deleted
inserted
replaced
1406:09751743647e | 1407:25ed6dde2ce0 |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 Sonic Visualiser | |
5 An audio file viewer and annotation editor. | |
6 Centre for Digital Music, Queen Mary, University of London. | |
7 This file copyright 2006-2017 Chris Cannam and QMUL. | |
8 | |
9 This program is free software; you can redistribute it and/or | |
10 modify it under the terms of the GNU General Public License as | |
11 published by the Free Software Foundation; either version 2 of the | |
12 License, or (at your option) any later version. See the file | |
13 COPYING included with this distribution for more information. | |
14 */ | |
15 | |
16 #ifndef SV_SCALE_TICK_INTERVALS_H | |
17 #define SV_SCALE_TICK_INTERVALS_H | |
18 | |
19 #include <string> | |
20 #include <vector> | |
21 #include <cmath> | |
22 | |
23 #include <iostream> | |
24 | |
25 | |
26 class ScaleTickIntervals | |
27 { | |
28 public: | |
29 struct Range { | |
30 double min; // start of value range | |
31 double max; // end of value range | |
32 int n; // number of divisions requested (will be n+1 ticks) | |
33 }; | |
34 | |
35 struct Tick { | |
36 double value; // value this tick represents | |
37 std::string label; // value as written | |
38 }; | |
39 | |
40 struct Ticks { | |
41 double initial; // value of first tick | |
42 double spacing; // increment between ticks | |
43 double roundTo; // what all displayed values should be rounded to | |
44 bool fixed; // whether to use fixed precision (%f rather than %e) | |
45 int precision; // number of dp (%f) or sf (%e) | |
46 std::vector<Tick> ticks; // computed tick values and labels | |
47 }; | |
48 | |
49 static Ticks linear(Range r) { | |
50 | |
51 if (r.n < 1) { | |
52 return {}; | |
53 } | |
54 if (r.max < r.min) { | |
55 return linear({ r.max, r.min, r.n }); | |
56 } | |
57 | |
58 double inc = (r.max - r.min) / r.n; | |
59 if (inc == 0) { | |
60 Ticks t { r.min, 1.0, r.min, false, 1, {} }; | |
61 explode(r, t); | |
62 return t; | |
63 } | |
64 | |
65 double ilg = log10(inc); | |
66 int prec = int((ilg > 0.0) ? round(ilg) : trunc(ilg)) - 1; | |
67 int dp = 0, sf = 0; | |
68 bool fixed = false; | |
69 if (prec < 0) { | |
70 dp = -prec; | |
71 sf = 1; // was 2, but should probably vary | |
72 } else { | |
73 sf = prec; | |
74 } | |
75 if (sf == 0) { | |
76 sf = 1; | |
77 } | |
78 if (prec > -4 && prec < 4) { | |
79 fixed = true; | |
80 } | |
81 | |
82 double roundTo = pow(10.0, prec); | |
83 inc = round(inc / roundTo) * roundTo; | |
84 double min = ceil(r.min / roundTo) * roundTo; | |
85 if (min > r.max) min = r.max; | |
86 | |
87 Ticks t { min, inc, roundTo, fixed, fixed ? dp : sf, {} }; | |
88 explode(r, t); | |
89 return t; | |
90 } | |
91 | |
92 private: | |
93 static void explode(const Range &r, Ticks &t) { | |
94 std::cerr << "initial = " << t.initial << ", spacing = " << t.spacing | |
95 << ", roundTo = " << t.roundTo << ", fixed = " << t.fixed | |
96 << ", precision = " << t.precision << std::endl; | |
97 auto makeTick = [&](double value) { | |
98 const int buflen = 40; | |
99 char buffer[buflen]; | |
100 snprintf(buffer, buflen, | |
101 t.fixed ? "%.*f" : "%.*e", | |
102 t.precision, value); | |
103 return Tick({ value, std::string(buffer) }); | |
104 }; | |
105 for (double value = t.initial; value <= r.max; value += t.spacing) { | |
106 value = t.roundTo * round(value / t.roundTo); | |
107 t.ticks.push_back(makeTick(value)); | |
108 } | |
109 } | |
110 }; | |
111 | |
112 #endif |