Mercurial > hg > svcore
comparison base/ScaleTickIntervals.h @ 1411:1f0d071e7ce6 scale-ticks
More tests & fixes
author | Chris Cannam |
---|---|
date | Wed, 03 May 2017 18:26:26 +0100 |
parents | c4af57d59434 |
children | b7a9edee85e0 |
comparison
equal
deleted
inserted
replaced
1410:c4af57d59434 | 1411:1f0d071e7ce6 |
---|---|
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 | |
24 | |
25 #ifdef DEBUG_SCALE_TICK_INTERVALS | |
23 #include <iostream> | 26 #include <iostream> |
24 | 27 #endif |
25 | 28 |
26 class ScaleTickIntervals | 29 class ScaleTickIntervals |
27 { | 30 { |
28 public: | 31 public: |
29 struct Range { | 32 struct Range { |
30 double min; // start of value range | 33 double min; // start of value range |
31 double max; // end of value range | 34 double max; // end of value range |
32 int n; // number of divisions requested (will be n+1 ticks) | 35 int n; // number of divisions (will be at most n+1 ticks) |
33 }; | 36 }; |
34 | 37 |
35 struct Tick { | 38 struct Tick { |
36 double value; // value this tick represents | 39 double value; // value this tick represents |
37 std::string label; // value as written | 40 std::string label; // value as written |
55 return linear({ r.max, r.min, r.n }); | 58 return linear({ r.max, r.min, r.n }); |
56 } | 59 } |
57 | 60 |
58 double inc = (r.max - r.min) / r.n; | 61 double inc = (r.max - r.min) / r.n; |
59 if (inc == 0) { | 62 if (inc == 0) { |
60 Ticks t { r.min, 1.0, r.min, false, 1, {} }; | 63 #ifdef DEBUG_SCALE_TICK_INTERVALS |
64 std::cerr << "inc == 0, using trivial range" << std::endl; | |
65 #endif | |
66 double roundTo = r.min; | |
67 if (roundTo <= 0.0) { | |
68 roundTo = 1.0; | |
69 } | |
70 Ticks t { r.min, 1.0, roundTo, true, 1, {} }; | |
61 explode(r, t); | 71 explode(r, t); |
62 return t; | 72 return t; |
63 } | 73 } |
64 | 74 |
65 double digInc = log10(inc); | 75 double digInc = log10(inc); |
91 } | 101 } |
92 } else { | 102 } else { |
93 prec = precRange; | 103 prec = precRange; |
94 } | 104 } |
95 | 105 |
106 double roundTo = pow(10.0, precInc); | |
107 | |
108 #ifdef DEBUG_SCALE_TICK_INTERVALS | |
96 std::cerr << "\nmin = " << r.min << ", max = " << r.max << ", n = " << r.n | 109 std::cerr << "\nmin = " << r.min << ", max = " << r.max << ", n = " << r.n |
97 << ", inc = " << inc << std::endl; | 110 << ", inc = " << inc << std::endl; |
98 std::cerr << "digMax = " << digMax << ", digInc = " << digInc | 111 std::cerr << "digMax = " << digMax << ", digInc = " << digInc |
99 << std::endl; | 112 << std::endl; |
100 std::cerr << "fixed = " << fixed << ", inc = " << inc | 113 std::cerr << "fixed = " << fixed << ", inc = " << inc |
101 << ", precInc = " << precInc << ", precRange = " << precRange | 114 << ", precInc = " << precInc << ", precRange = " << precRange |
102 << ", prec = " << prec << std::endl; | 115 << ", prec = " << prec << std::endl; |
103 | |
104 double roundTo = pow(10.0, precInc); | |
105 | |
106 std::cerr << "roundTo = " << roundTo << std::endl; | 116 std::cerr << "roundTo = " << roundTo << std::endl; |
117 #endif | |
107 | 118 |
108 inc = round(inc / roundTo) * roundTo; | 119 inc = round(inc / roundTo) * roundTo; |
109 if (inc < roundTo) inc = roundTo; | 120 if (inc < roundTo) inc = roundTo; |
110 | 121 |
111 double min = ceil(r.min / roundTo) * roundTo; | 122 double min = ceil(r.min / roundTo) * roundTo; |
116 return t; | 127 return t; |
117 } | 128 } |
118 | 129 |
119 private: | 130 private: |
120 static void explode(const Range &r, Ticks &t) { | 131 static void explode(const Range &r, Ticks &t) { |
132 #ifdef DEBUG_SCALE_TICK_INTERVALS | |
121 std::cerr << "initial = " << t.initial << ", spacing = " << t.spacing | 133 std::cerr << "initial = " << t.initial << ", spacing = " << t.spacing |
122 << ", roundTo = " << t.roundTo << ", fixed = " << t.fixed | 134 << ", roundTo = " << t.roundTo << ", fixed = " << t.fixed |
123 << ", precision = " << t.precision << std::endl; | 135 << ", precision = " << t.precision << std::endl; |
136 #endif | |
124 auto makeTick = [&](double value) { | 137 auto makeTick = [&](double value) { |
125 const int buflen = 40; | 138 const int buflen = 40; |
126 char buffer[buflen]; | 139 char buffer[buflen]; |
127 snprintf(buffer, buflen, | 140 snprintf(buffer, buflen, |
128 t.fixed ? "%.*f" : "%.*e", | 141 t.fixed ? "%.*f" : "%.*e", |
129 t.precision, value); | 142 t.precision, value); |
130 return Tick({ value, std::string(buffer) }); | 143 return Tick({ value, std::string(buffer) }); |
131 }; | 144 }; |
132 for (double value = t.initial; | 145 double eps = 1e-7; |
133 value < r.max + t.spacing/2; | 146 if (t.spacing < eps * 10.0) { |
134 value += t.spacing) { | 147 eps = t.spacing / 10.0; |
148 } | |
149 for (double value = t.initial; value < r.max + eps; value += t.spacing) { | |
135 value = t.roundTo * round(value / t.roundTo); | 150 value = t.roundTo * round(value / t.roundTo); |
136 t.ticks.push_back(makeTick(value)); | 151 t.ticks.push_back(makeTick(value)); |
137 } | 152 } |
138 } | 153 } |
139 }; | 154 }; |