7 * adapted from Paul Heckbert's algorithm on p 657-659 of
8 * Andrew S. Glassner's book, "Graphics Gems"
13 #include "tickmarks.h"
15 #define MAX(a, b) (((a) < (b)) ? (b) : (a))
17 static double nicenum(double x, int round)
19 int exp; /* exponent of x */
20 double f; /* fractional part of x */
22 exp = floor(log10(x));
23 f = x / pow(10.0, exp);
26 return 1.0 * pow(10.0, exp);
28 return 2.0 * pow(10.0, exp);
30 return 5.0 * pow(10.0, exp);
31 return 10.0 * pow(10.0, exp);
34 return 1.0 * pow(10.0, exp);
36 return 2.0 * pow(10.0, exp);
38 return 5.0 * pow(10.0, exp);
39 return 10.0 * pow(10.0, exp);
42 static void shorten(struct tickmark *tm, int nticks, int *power_of_ten,
47 char shorten_char = '?';
50 for (i = 0; i < nticks; i++) {
54 if (strcmp(str, "0") == 0)
56 if (l > 9 && strcmp(&str[l - 9], "000000000") == 0) {
58 shorten_char = use_KMG_symbols ? 'G' : '\0';
59 } else if (6 < minshorten && l > 6 &&
60 strcmp(&str[l - 6], "000000") == 0) {
62 shorten_char = use_KMG_symbols ? 'M' : '\0';
63 } else if (l > 3 && strcmp(&str[l - 3], "000") == 0) {
65 shorten_char = use_KMG_symbols ? 'K': '\0';
70 if (*power_of_ten < minshorten)
71 minshorten = *power_of_ten;
77 for (i = 0; i < nticks; i++) {
80 str[l - minshorten] = shorten_char;
81 str[l - minshorten + 1] = '\0';
85 int calc_tickmarks(double min, double max, int nticks, struct tickmark **tm,
86 int *power_of_ten, int use_KMG_symbols)
90 double d; /* tick mark spacing */
91 double graphmin, graphmax; /* graph range min and max */
95 /* we expect min != max */
96 range = nicenum(max - min, 0);
97 d = nicenum(range / (nticks - 1), 1);
98 graphmin = floor(min / d) * d;
99 graphmax = ceil(max / d) * d;
100 nfrac = MAX(-floor(log10(d)), 0);
101 snprintf(str, sizeof(str)-1, "%%.%df", nfrac);
103 count = ((graphmax + 0.5 * d) - graphmin) / d + 1;
104 *tm = malloc(sizeof(**tm) * count);
107 for (x = graphmin; x < graphmax + 0.5 * d; x += d) {
109 sprintf((*tm)[i].string, str, x);
112 shorten(*tm, i, power_of_ten, use_KMG_symbols);
118 static void test_range(double x, double y)
122 struct tickmark *tm = NULL;
123 printf("Testing range %g - %g\n", x, y);
124 nticks = calc_tickmarks(x, y, 10, &tm);
126 for (i = 0; i < nticks; i++) {
127 printf(" (%s) %g\n", tm[i].string, tm[i].value);
133 int main(int argc, char *argv[])
135 test_range(0.0005, 0.008);
136 test_range(0.5, 0.8);
137 test_range(5.5, 8.8);
138 test_range(50.5, 80.8);
139 test_range(-20, 20.8);
140 test_range(-30, 700.8);