16 #ifndef SV_SCALE_TICK_INTERVALS_H 17 #define SV_SCALE_TICK_INTERVALS_H 43 typedef std::vector<Tick>
Ticks;
99 if (r.
n < 1 || r.
max == r.
min) {
100 return { r.
min, r.
min, 1.0, r.
min, display, 1,
false };
103 double inc = (r.
max - r.
min) / r.
n;
105 double digInc = log10(inc);
106 double digMax = log10(fabs(r.
max));
107 double digMin = log10(fabs(r.
min));
109 int precInc = int(floor(digInc));
110 double roundTo = pow(10.0, precInc);
112 if (precInc > -4 && precInc < 4) {
114 }
else if ((digMax >= -2.0 && digMax <= 3.0) &&
115 (digMin >= -3.0 && digMin <= 3.0)) {
121 int precRange = int(ceil(digMax - digInc));
125 if (display ==
Fixed) {
135 #ifdef DEBUG_SCALE_TICK_INTERVALS 136 SVDEBUG <<
"ScaleTickIntervals: calculating linearInstruction" << endl
137 <<
"ScaleTickIntervals: min = " << r.
min <<
", max = " << r.
max 138 <<
", n = " << r.
n <<
", inc = " << inc << endl;
139 SVDEBUG <<
"ScaleTickIntervals: digMax = " << digMax
140 <<
", digInc = " << digInc << endl;
141 SVDEBUG <<
"ScaleTickIntervals: display = " << display
142 <<
", inc = " << inc <<
", precInc = " << precInc
143 <<
", precRange = " << precRange
144 <<
", prec = " << prec <<
", roundTo = " << roundTo
150 if (roundTo != 0.0) {
158 inc = round(inc / roundTo + eps) * roundTo;
159 if (inc < roundTo) inc = roundTo;
160 min = ceil(min / roundTo - eps) * roundTo;
161 if (min > r.
max) min = r.
max;
162 if (min == -0.0) min = 0.0;
163 #ifdef DEBUG_SCALE_TICK_INTERVALS 164 SVDEBUG <<
"ScaleTickIntervals: rounded inc to " << inc
165 <<
" and min to " << min << endl;
170 double digNewMin = log10(fabs(min));
171 if (digNewMin < digInc) {
172 prec = int(ceil(digMax - digNewMin));
173 #ifdef DEBUG_SCALE_TICK_INTERVALS 174 SVDEBUG <<
"ScaleTickIntervals: min is smaller than increment, adjusting prec to " << prec << endl;
179 return {
min, r.
max, inc, roundTo, display, prec,
false };
186 #ifdef DEBUG_SCALE_TICK_INTERVALS 187 SVDEBUG <<
"ScaleTickIntervals::logInstruction: Range is " 188 << r.
min <<
" to " << r.
max << endl;
198 return { r.
min, r.
max, 1.0, r.
min, display, 1,
true };
201 double inc = (r.
max - r.
min) / r.
n;
203 #ifdef DEBUG_SCALE_TICK_INTERVALS
204 SVDEBUG <<
"ScaleTickIntervals::logInstruction: " 205 <<
"Naive increment is " << inc << endl;
211 precision = int(ceil(1.0 - inc)) + 1;
214 double digInc = log10(inc);
215 int precInc = int(floor(digInc));
216 double roundIncTo = pow(10.0, precInc);
218 inc = round(inc / roundIncTo) * roundIncTo;
219 if (inc < roundIncTo) inc = roundIncTo;
221 #ifdef DEBUG_SCALE_TICK_INTERVALS 222 SVDEBUG <<
"ScaleTickIntervals::logInstruction: " 223 <<
"Rounded increment to " << inc << endl;
227 if (fabs(inc - 0.301) < 0.01) {
230 #ifdef DEBUG_SCALE_TICK_INTERVALS 231 SVDEBUG <<
"ScaleTickIntervals::logInstruction: " 232 <<
"Nudged increment to " << inc <<
" to get powers of two" 239 min = ceil(r.
min / inc) * inc;
240 if (min > r.
max) min = r.
max;
243 return {
min, r.
max, inc, 0.0, display, precision,
true };
248 Ticks ticks =
explode(instruction);
254 Ticks ticks =
explode(instruction);
264 const int buflen = 40;
267 if (display ==
Auto) {
271 int digits = (value != 0.0 ?
272 1 + int(floor(eps + log10(fabs(value)))) :
275 #ifdef DEBUG_SCALE_TICK_INTERVALS 276 SVDEBUG <<
"makeTick: display = Auto, precision = " 277 << precision <<
", value = " << value
278 <<
", resulting digits = " << digits << endl;
284 if (digits < -3 || digits > 4) {
293 if (precision >= digits) {
301 const char *spec = (display ==
Auto ?
"%.*g" :
305 #pragma GCC diagnostic ignored "-Wformat-nonliteral" 307 snprintf(buffer, buflen, spec, precision, value);
309 #ifdef DEBUG_SCALE_TICK_INTERVALS 310 SVDEBUG <<
"makeTick: spec = \"" << spec
311 <<
"\", prec = " << precision <<
", value = " << value
312 <<
", label = \"" << buffer <<
"\"" << endl;
315 return Tick({ value, std::string(buffer) });
320 #ifdef DEBUG_SCALE_TICK_INTERVALS 321 SVDEBUG <<
"ScaleTickIntervals::explode:" << endl
322 <<
"initial = " << instruction.
initial 323 <<
", limit = " << instruction.
limit 324 <<
", spacing = " << instruction.
spacing 325 <<
", roundTo = " << instruction.
roundTo 326 <<
", display = " << instruction.
display 327 <<
", precision = " << instruction.
precision 328 <<
", logUnmap = " << instruction.
logUnmap 332 if (instruction.
spacing == 0.0) {
337 if (instruction.
spacing < eps * 10.0) {
338 eps = instruction.
spacing / 10.0;
350 if (value >= max + eps) {
355 value = pow(10.0, value);
358 double roundTo = instruction.
roundTo;
360 if (roundTo == 0.0 && value != 0.0) {
364 pow(10, ceil(log10(fabs(value))) - instruction.
precision);
367 if (roundTo != 0.0) {
368 value = roundTo * round(value / roundTo);
371 if (fabs(value) < eps) {
static void mapRange(double &min, double &max, double thresh=-10)
Map a linear range onto a logarithmic range.
static Ticks linear(Range r)
Return a set of ticks that divide the range r linearly into roughly r.n equal divisions, in such a way as to yield reasonably human-readable labels.
static Ticks logarithmic(Range r)
Return a set of ticks that divide the range r into roughly r.n logarithmic divisions, in such a way as to yield reasonably human-readable labels.
static Instruction linearInstruction(Range r)
static Tick makeTick(Display display, int precision, double value)
static Ticks explode(Instruction instruction)
static Instruction logInstruction(Range r)
static Ticks logTicks(Range r)
static Ticks logarithmicAlready(Range r)
Return a set of ticks that divide the range r into roughly r.n logarithmic divisions, on the asssumption that r.min and r.max already represent the logarithms of the boundary values rather than the values themselves.
std::vector< Tick > Ticks
static Ticks linearTicks(Range r)