annotate base/ScaleTickIntervals.h @ 1409:21ba60008200 scale-ticks

More fixes, more tests, including some more that now fail
author Chris Cannam
date Wed, 03 May 2017 18:01:25 +0100
parents f89365917d02
children c4af57d59434
rev   line source
Chris@1407 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@1407 2
Chris@1407 3 /*
Chris@1407 4 Sonic Visualiser
Chris@1407 5 An audio file viewer and annotation editor.
Chris@1407 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1407 7 This file copyright 2006-2017 Chris Cannam and QMUL.
Chris@1407 8
Chris@1407 9 This program is free software; you can redistribute it and/or
Chris@1407 10 modify it under the terms of the GNU General Public License as
Chris@1407 11 published by the Free Software Foundation; either version 2 of the
Chris@1407 12 License, or (at your option) any later version. See the file
Chris@1407 13 COPYING included with this distribution for more information.
Chris@1407 14 */
Chris@1407 15
Chris@1407 16 #ifndef SV_SCALE_TICK_INTERVALS_H
Chris@1407 17 #define SV_SCALE_TICK_INTERVALS_H
Chris@1407 18
Chris@1407 19 #include <string>
Chris@1407 20 #include <vector>
Chris@1407 21 #include <cmath>
Chris@1407 22
Chris@1407 23 #include <iostream>
Chris@1407 24
Chris@1407 25
Chris@1407 26 class ScaleTickIntervals
Chris@1407 27 {
Chris@1407 28 public:
Chris@1407 29 struct Range {
Chris@1407 30 double min; // start of value range
Chris@1407 31 double max; // end of value range
Chris@1407 32 int n; // number of divisions requested (will be n+1 ticks)
Chris@1407 33 };
Chris@1407 34
Chris@1407 35 struct Tick {
Chris@1407 36 double value; // value this tick represents
Chris@1407 37 std::string label; // value as written
Chris@1407 38 };
Chris@1407 39
Chris@1407 40 struct Ticks {
Chris@1407 41 double initial; // value of first tick
Chris@1407 42 double spacing; // increment between ticks
Chris@1407 43 double roundTo; // what all displayed values should be rounded to
Chris@1407 44 bool fixed; // whether to use fixed precision (%f rather than %e)
Chris@1407 45 int precision; // number of dp (%f) or sf (%e)
Chris@1407 46 std::vector<Tick> ticks; // computed tick values and labels
Chris@1407 47 };
Chris@1407 48
Chris@1407 49 static Ticks linear(Range r) {
Chris@1407 50
Chris@1407 51 if (r.n < 1) {
Chris@1407 52 return {};
Chris@1407 53 }
Chris@1407 54 if (r.max < r.min) {
Chris@1407 55 return linear({ r.max, r.min, r.n });
Chris@1407 56 }
Chris@1407 57
Chris@1407 58 double inc = (r.max - r.min) / r.n;
Chris@1407 59 if (inc == 0) {
Chris@1407 60 Ticks t { r.min, 1.0, r.min, false, 1, {} };
Chris@1407 61 explode(r, t);
Chris@1407 62 return t;
Chris@1407 63 }
Chris@1408 64
Chris@1408 65 double digInc = log10(inc);
Chris@1408 66 double digMax = log10(fabs(r.max));
Chris@1408 67 double digMin = log10(fabs(r.min));
Chris@1408 68
Chris@1409 69 int precInc = int(trunc(digInc));
Chris@1409 70 if (double(precInc) != digInc) {
Chris@1409 71 precInc -= 1;
Chris@1409 72 }
Chris@1408 73
Chris@1408 74 bool fixed = false;
Chris@1408 75 if (precInc > -4 && precInc < 4) {
Chris@1408 76 fixed = true;
Chris@1408 77 } else if ((digMax >= -3.0 && digMax <= 2.0) &&
Chris@1408 78 (digMin >= -3.0 && digMin <= 3.0)) {
Chris@1408 79 fixed = true;
Chris@1408 80 }
Chris@1408 81
Chris@1408 82 int precRange = int(ceil(digMax - digInc));
Chris@1408 83
Chris@1408 84 int prec = 1;
Chris@1408 85
Chris@1408 86 if (fixed) {
Chris@1408 87 prec = precInc;
Chris@1408 88 if (prec < 0) {
Chris@1408 89 prec = -prec;
Chris@1408 90 }
Chris@1408 91 } else {
Chris@1408 92 prec = precRange;
Chris@1408 93 }
Chris@1408 94
Chris@1408 95 std::cerr << "\nmin = " << r.min << ", max = " << r.max << ", n = " << r.n
Chris@1408 96 << ", inc = " << inc << std::endl;
Chris@1408 97 std::cerr << "digMax = " << digMax << ", digInc = " << digInc
Chris@1408 98 << std::endl;
Chris@1408 99 std::cerr << "fixed = " << fixed << ", inc = " << inc
Chris@1408 100 << ", precInc = " << precInc << ", precRange = " << precRange
Chris@1408 101 << ", prec = " << prec << std::endl;
Chris@1409 102
Chris@1408 103 double roundTo = pow(10.0, precInc);
Chris@1407 104
Chris@1408 105 std::cerr << "roundTo = " << roundTo << std::endl;
Chris@1408 106
Chris@1407 107 inc = round(inc / roundTo) * roundTo;
Chris@1408 108 if (inc < roundTo) inc = roundTo;
Chris@1408 109
Chris@1407 110 double min = ceil(r.min / roundTo) * roundTo;
Chris@1407 111 if (min > r.max) min = r.max;
Chris@1407 112
Chris@1408 113 Ticks t { min, inc, roundTo, fixed, prec, {} };
Chris@1407 114 explode(r, t);
Chris@1407 115 return t;
Chris@1407 116 }
Chris@1407 117
Chris@1407 118 private:
Chris@1407 119 static void explode(const Range &r, Ticks &t) {
Chris@1407 120 std::cerr << "initial = " << t.initial << ", spacing = " << t.spacing
Chris@1407 121 << ", roundTo = " << t.roundTo << ", fixed = " << t.fixed
Chris@1407 122 << ", precision = " << t.precision << std::endl;
Chris@1407 123 auto makeTick = [&](double value) {
Chris@1407 124 const int buflen = 40;
Chris@1407 125 char buffer[buflen];
Chris@1407 126 snprintf(buffer, buflen,
Chris@1407 127 t.fixed ? "%.*f" : "%.*e",
Chris@1407 128 t.precision, value);
Chris@1407 129 return Tick({ value, std::string(buffer) });
Chris@1407 130 };
Chris@1408 131 for (double value = t.initial;
Chris@1408 132 value < r.max + t.spacing/2;
Chris@1408 133 value += t.spacing) {
Chris@1407 134 value = t.roundTo * round(value / t.roundTo);
Chris@1407 135 t.ticks.push_back(makeTick(value));
Chris@1407 136 }
Chris@1407 137 }
Chris@1407 138 };
Chris@1407 139
Chris@1407 140 #endif