Mercurial > hg > svcore
changeset 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 (2017-05-04) |
parents | 9a8995785827 |
children | e7cb4fb2aee4 |
files | base/ScaleTickIntervals.h base/test/TestScaleTickIntervals.h |
diffstat | 2 files changed, 121 insertions(+), 103 deletions(-) [+] |
line wrap: on
line diff
--- a/base/ScaleTickIntervals.h Thu May 04 13:19:57 2017 +0100 +++ b/base/ScaleTickIntervals.h Thu May 04 13:32:42 2017 +0100 @@ -20,7 +20,7 @@ #include <vector> #include <cmath> -//#define DEBUG_SCALE_TICK_INTERVALS 1 +#define DEBUG_SCALE_TICK_INTERVALS 1 #ifdef DEBUG_SCALE_TICK_INTERVALS #include <iostream> @@ -42,14 +42,7 @@ std::string label; // value as written }; - struct Ticks { - double initial; // value of first tick - double spacing; // increment between ticks - double roundTo; // what all displayed values should be rounded to - bool fixed; // whether to use fixed precision (%f rather than %e) - int precision; // number of dp (%f) or sf (%e) - std::vector<Tick> ticks; // computed tick values and labels - }; + typedef std::vector<Tick> Ticks; static Ticks linear(Range r) { return linearTicks(r); @@ -60,13 +53,23 @@ } private: - static Ticks unexplodedTicks(Range r) + struct Instruction { + double initial; // value of first tick + double limit; // max from original range + double spacing; // increment between ticks + double roundTo; // what all displayed values should be rounded to + bool fixed; // whether to use fixed precision (%f rather than %e) + int precision; // number of dp (%f) or sf (%e) + bool logUnmap; // true if values represent logs of display values + }; + + static Instruction linearInstruction(Range r) { if (r.n < 1) { return {}; } if (r.max < r.min) { - return unexplodedTicks({ r.max, r.min, r.n }); + return linearInstruction({ r.max, r.min, r.n }); } double inc = (r.max - r.min) / r.n; @@ -78,8 +81,7 @@ if (roundTo <= 0.0) { roundTo = 1.0; } - Ticks t { r.min, 1.0, roundTo, true, 1, {} }; - return t; + return { r.min, r.max, 1.0, roundTo, true, 1, false }; } double digInc = log10(inc); @@ -143,25 +145,25 @@ } } - Ticks t { min, inc, roundTo, fixed, prec, {} }; - return t; + return { min, r.max, inc, roundTo, fixed, prec, false }; } static Ticks linearTicks(Range r) { - Ticks t = unexplodedTicks(r); - explode(r, t, false); - return t; + Instruction instruction = linearInstruction(r); + Ticks ticks = explode(instruction); + return ticks; } static Ticks logTicks(Range r) { Range mapped(r); LogRange::mapRange(mapped.min, mapped.max); - Ticks t = unexplodedTicks(mapped); + Instruction instruction = linearInstruction(mapped); + instruction.logUnmap = true; if (fabs(mapped.min - mapped.max) > 3) { - t.fixed = false; + instruction.fixed = false; } - explode(mapped, t, true); - return t; + Ticks ticks = explode(instruction); + return ticks; } static Tick makeTick(bool fixed, int precision, double value) { @@ -173,33 +175,49 @@ return Tick({ value, std::string(buffer) }); } - static void explode(const Range &r, Ticks &t, bool logUnmap) { + static Ticks explode(Instruction instruction) { + #ifdef DEBUG_SCALE_TICK_INTERVALS - std::cerr << "initial = " << t.initial << ", spacing = " << t.spacing - << ", roundTo = " << t.roundTo << ", fixed = " << t.fixed - << ", precision = " << t.precision << std::endl; + std::cerr << "initial = " << instruction.initial + << ", limit = " << instruction.limit + << ", spacing = " << instruction.spacing + << ", roundTo = " << instruction.roundTo + << ", fixed = " << instruction.fixed + << ", precision = " << instruction.precision + << ", logUnmap = " << instruction.logUnmap + << std::endl; #endif - if (t.spacing == 0.0) { - return; + + if (instruction.spacing == 0.0) { + return {}; } + double eps = 1e-7; - if (t.spacing < eps * 10.0) { - eps = t.spacing / 10.0; + if (instruction.spacing < eps * 10.0) { + eps = instruction.spacing / 10.0; } - double max = std::max(r.min, r.max); + + double max = instruction.limit; int n = 0; + + Ticks ticks; + while (true) { - double value = t.initial + n * t.spacing; - value = t.roundTo * round(value / t.roundTo); + double value = instruction.initial + n * instruction.spacing; + value = instruction.roundTo * round(value / instruction.roundTo); if (value >= max + eps) { break; } - if (logUnmap) { + if (instruction.logUnmap) { value = pow(10.0, value); } - t.ticks.push_back(makeTick(t.fixed, t.precision, value)); + ticks.push_back(makeTick(instruction.fixed, + instruction.precision, + value)); ++n; } + + return ticks; } };
--- a/base/test/TestScaleTickIntervals.h Thu May 04 13:19:57 2017 +0100 +++ b/base/test/TestScaleTickIntervals.h Thu May 04 13:32:42 2017 +0100 @@ -46,8 +46,8 @@ } } - void compareTicks(vector<ScaleTickIntervals::Tick> ticks, - vector<ScaleTickIntervals::Tick> expected, + void compareTicks(ScaleTickIntervals::Ticks ticks, + ScaleTickIntervals::Ticks expected, bool fuzzier = false) { double eps = 1e-7; @@ -83,7 +83,7 @@ void linear_0_1_10() { auto ticks = ScaleTickIntervals::linear({ 0, 1, 10 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 0.0, "0.0" }, { 0.1, "0.1" }, { 0.2, "0.2" }, @@ -96,13 +96,13 @@ { 0.9, "0.9" }, { 1.0, "1.0" } }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_0_5_5() { auto ticks = ScaleTickIntervals::linear({ 0, 5, 5 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 0, "0" }, { 1, "1" }, { 2, "2" }, @@ -110,13 +110,13 @@ { 4, "4" }, { 5, "5" }, }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_0_10_5() { auto ticks = ScaleTickIntervals::linear({ 0, 10, 5 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 0, "0" }, { 2, "2" }, { 4, "4" }, @@ -124,13 +124,13 @@ { 8, "8" }, { 10, "10" } }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_10_0_5() { auto ticks = ScaleTickIntervals::linear({ 10, 0, 5 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 0, "0" }, { 2, "2" }, { 4, "4" }, @@ -138,13 +138,13 @@ { 8, "8" }, { 10, "10" } }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_m10_0_5() { auto ticks = ScaleTickIntervals::linear({ -10, 0, 5 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { -10, "-10" }, { -8, "-8" }, { -6, "-6" }, @@ -152,13 +152,13 @@ { -2, "-2" }, { 0, "0" } }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_0_m10_5() { auto ticks = ScaleTickIntervals::linear({ 0, -10, 5 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { -10, "-10" }, { -8, "-8" }, { -6, "-6" }, @@ -166,13 +166,13 @@ { -2, "-2" }, { 0, "0" } }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_0_0p1_5() { auto ticks = ScaleTickIntervals::linear({ 0, 0.1, 5 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 0.00, "0.00" }, { 0.02, "0.02" }, { 0.04, "0.04" }, @@ -180,13 +180,13 @@ { 0.08, "0.08" }, { 0.10, "0.10" } }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_0_0p01_5() { auto ticks = ScaleTickIntervals::linear({ 0, 0.01, 5 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 0.000, "0.000" }, { 0.002, "0.002" }, { 0.004, "0.004" }, @@ -194,13 +194,13 @@ { 0.008, "0.008" }, { 0.010, "0.010" } }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_0_0p005_5() { auto ticks = ScaleTickIntervals::linear({ 0, 0.005, 5 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 0.000, "0.000" }, { 0.001, "0.001" }, { 0.002, "0.002" }, @@ -208,13 +208,13 @@ { 0.004, "0.004" }, { 0.005, "0.005" } }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_0_0p001_5() { auto ticks = ScaleTickIntervals::linear({ 0, 0.001, 5 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 0.0000, "0.0e+00" }, { 0.0002, "2.0e-04" }, { 0.0004, "4.0e-04" }, @@ -222,13 +222,13 @@ { 0.0008, "8.0e-04" }, { 0.0010, "1.0e-03" } }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_1_1p001_5() { auto ticks = ScaleTickIntervals::linear({ 1, 1.001, 5 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 1.0000, "1.0000" }, { 1.0002, "1.0002" }, { 1.0004, "1.0004" }, @@ -236,26 +236,26 @@ { 1.0008, "1.0008" }, { 1.0010, "1.0010" } }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_0p001_1_5() { auto ticks = ScaleTickIntervals::linear({ 0.001, 1, 5 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 0.1, "0.1" }, { 0.3, "0.3" }, { 0.5, "0.5" }, { 0.7, "0.7" }, { 0.9, "0.9" }, }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_10000_10010_5() { auto ticks = ScaleTickIntervals::linear({ 10000, 10010, 5 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 10000, "10000" }, { 10002, "10002" }, { 10004, "10004" }, @@ -263,13 +263,13 @@ { 10008, "10008" }, { 10010, "10010" }, }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_10000_20000_5() { auto ticks = ScaleTickIntervals::linear({ 10000, 20000, 5 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 10000, "10000" }, { 12000, "12000" }, { 14000, "14000" }, @@ -277,13 +277,13 @@ { 18000, "18000" }, { 20000, "20000" }, }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_m1_1_10() { auto ticks = ScaleTickIntervals::linear({ -1, 1, 10 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { -1.0, "-1.0" }, { -0.8, "-0.8" }, { -0.6, "-0.6" }, @@ -296,7 +296,7 @@ { 0.8, "0.8" }, { 1.0, "1.0" } }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_221p23_623p7_57p4() @@ -304,13 +304,13 @@ auto ticks = ScaleTickIntervals::linear({ 221.23, 623.7, 4 }); // only 4 ticks, not 5, because none of the rounded tick // values lies on an end value - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 230, "230" }, { 330, "330" }, { 430, "430" }, { 530, "530" }, }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_sqrt2_pi_7() @@ -318,7 +318,7 @@ auto ticks = ScaleTickIntervals::linear({ sqrt(2.0), M_PI, 7 }); // This would be better in steps of 0.25, but we only round to // integral powers of ten - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 1.5, "1.5" }, { 1.7, "1.7" }, { 1.9, "1.9" }, @@ -329,13 +329,13 @@ { 2.9, "2.9" }, { 3.1, "3.1" }, }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_pi_avogadro_7() { auto ticks = ScaleTickIntervals::linear({ M_PI, 6.022140857e23, 7 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 1e+21, "1.000e+21" }, { 8.7e+22, "8.700e+22" }, { 1.73e+23, "1.730e+23" }, @@ -344,40 +344,40 @@ { 4.31e+23, "4.310e+23" }, { 5.17e+23, "5.170e+23" }, }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_2_3_1() { auto ticks = ScaleTickIntervals::linear({ 2, 3, 1 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 2.0, "2" }, { 3.0, "3" } }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_2_3_2() { auto ticks = ScaleTickIntervals::linear({ 2, 3, 2 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 2.0, "2.0" }, { 2.5, "2.5" }, { 3.0, "3.0" } }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_2_3_3() { auto ticks = ScaleTickIntervals::linear({ 2, 3, 3 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 2.0, "2.0" }, { 2.3, "2.3" }, { 2.6, "2.6" }, { 2.9, "2.9" } }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_2_3_4() @@ -385,19 +385,19 @@ auto ticks = ScaleTickIntervals::linear({ 2, 3, 4 }); // This would be better in steps of 0.25, but we only round to // integral powers of ten - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 2.0, "2.0" }, { 2.3, "2.3" }, { 2.6, "2.6" }, { 2.9, "2.9" } }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_2_3_5() { auto ticks = ScaleTickIntervals::linear({ 2, 3, 5 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 2.0, "2.0" }, { 2.2, "2.2" }, { 2.4, "2.4" }, @@ -405,13 +405,13 @@ { 2.8, "2.8" }, { 3.0, "3.0" } }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_2_3_6() { auto ticks = ScaleTickIntervals::linear({ 2, 3, 6 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 2.0, "2.0" }, { 2.2, "2.2" }, { 2.4, "2.4" }, @@ -419,92 +419,92 @@ { 2.8, "2.8" }, { 3.0, "3.0" } }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_1_1_10() { // pathological range auto ticks = ScaleTickIntervals::linear({ 1, 1, 10 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 1.0, "1.0" } }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_0_0_10() { // pathological range auto ticks = ScaleTickIntervals::linear({ 0, 0, 10 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 0.0, "0.0" } }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_0_1_1() { auto ticks = ScaleTickIntervals::linear({ 0, 1, 1 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 0.0, "0" }, { 1.0, "1" } }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_0_1_0() { // senseless input auto ticks = ScaleTickIntervals::linear({ 0, 1, 0 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_0_1_m1() { // senseless input auto ticks = ScaleTickIntervals::linear({ 0, 1, -1 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void linear_0p465_778_10() { // a case that gave unsatisfactory results in real life auto ticks = ScaleTickIntervals::linear({ 0.465, 778.08, 10 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void log_1_10_2() { auto ticks = ScaleTickIntervals::logarithmic({ 1, 10, 2 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 1.0, "1.0" }, { pow(10.0, 0.5), "3.2" }, { 10.0, "10.0" }, }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void log_0_10_2() { auto ticks = ScaleTickIntervals::logarithmic({ 0, 10, 2 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 1e-10, "1e-10" }, { pow(10.0, -4.5), "3e-05" }, { 10.0, "1e+01" }, }; - compareTicks(ticks.ticks, expected); + compareTicks(ticks, expected); } void log_pi_avogadro_7() { auto ticks = ScaleTickIntervals::logarithmic({ M_PI, 6.022140857e23, 7 }); - vector<ScaleTickIntervals::Tick> expected { + ScaleTickIntervals::Ticks expected { { 3.16228, "3e+00" }, { 6309.57, "6e+03" }, { 1.25893e+07, "1e+07" }, @@ -514,7 +514,7 @@ { 1.99526e+20, "2e+20" }, { 3.98107e+23, "4e+23" }, }; - compareTicks(ticks.ticks, expected, true); + compareTicks(ticks, expected, true); } };