gfio: fix discrepancies between graph header and implementation
[fio.git] / tickmarks.c
CommitLineData
af58ef32
SC
1#include <stdio.h>
2#include <math.h>
3#include <malloc.h>
17ba3e42 4#include <string.h>
af58ef32
SC
5
6/*
7 * adapted from Paul Heckbert's algorithm on p 657-659 of
8 * Andrew S. Glassner's book, "Graphics Gems"
9 * ISBN 0-12-286166-3
10 *
11 */
12
13#include "tickmarks.h"
14
15#define MAX(a, b) (((a) < (b)) ? (b) : (a))
16
17static double nicenum(double x, int round)
18{
19 int exp; /* exponent of x */
20 double f; /* fractional part of x */
21
22 exp = floor(log10(x));
23 f = x / pow(10.0, exp);
24 if (round) {
25 if (f < 1.5)
26 return 1.0 * pow(10.0, exp);
27 if (f < 3.0)
28 return 2.0 * pow(10.0, exp);
29 if (f < 7.0)
30 return 5.0 * pow(10.0, exp);
31 return 10.0 * pow(10.0, exp);
32 }
33 if (f <= 1.0)
34 return 1.0 * pow(10.0, exp);
35 if (f <= 2.0)
36 return 2.0 * pow(10.0, exp);
37 if (f <= 5.0)
38 return 5.0 * pow(10.0, exp);
39 return 10.0 * pow(10.0, exp);
40}
41
1e1ffcc4 42static void shorten(struct tickmark *tm, int nticks)
17ba3e42 43{
1e1ffcc4
SC
44 int i, l, minshorten, can_shorten_by;
45 char *str;
46 char shorten_char = '?';
47
48 minshorten = 100;
49 for (i = 0; i < nticks; i++) {
50 str = tm[i].string;
51 l = strlen(str);
52
53 if (l > 9 && strcmp(&str[l - 9], "000000000") == 0) {
54 can_shorten_by = 9;
55 shorten_char = 'G';
56 } else if (6 < minshorten && l > 6 &&
57 strcmp(&str[l - 6], "000000") == 0) {
58 can_shorten_by = 6;
59 shorten_char = 'M';
60 } else if (l > 3 && strcmp(&str[l - 3], "000") == 0) {
61 can_shorten_by = 3;
62 shorten_char = 'K';
63 } else {
64 can_shorten_by = 0;
65 }
66
67 if (can_shorten_by < minshorten)
68 minshorten = can_shorten_by;
69 }
70
71 if (minshorten == 0)
72 return;
73
74 for (i = 0; i < nticks; i++) {
75 str = tm[i].string;
76 l = strlen(str);
77 str[l - minshorten] = shorten_char;
78 str[l - minshorten + 1] = '\0';
17ba3e42
SC
79 }
80}
81
af58ef32
SC
82int calc_tickmarks(double min, double max, int nticks, struct tickmark **tm)
83{
84 char str[100];
85 int nfrac;
86 double d; /* tick mark spacing */
87 double graphmin, graphmax; /* graph range min and max */
88 double range, x;
89 int count, i;
90
91 /* we expect min != max */
92 range = nicenum(max - min, 0);
93 d = nicenum(range / (nticks - 1), 1);
94 graphmin = floor(min / d) * d;
95 graphmax = ceil(max / d) * d;
96 nfrac = MAX(-floor(log10(d)), 0);
97 snprintf(str, sizeof(str)-1, "%%.%df", nfrac);
98
99 count = ((graphmax + 0.5 * d) - graphmin) / d + 1;
100 *tm = malloc(sizeof(**tm) * count);
101
102 i = 0;
103 for (x = graphmin; x < graphmax + 0.5 * d; x += d) {
104 (*tm)[i].value = x;
105 sprintf((*tm)[i].string, str, x);
106 i++;
107 }
1e1ffcc4 108 shorten(*tm, i);
af58ef32
SC
109 return i;
110}
111
112#if 0
113
114static void test_range(double x, double y)
115{
116 int nticks, i;
117
118 struct tickmark *tm = NULL;
119 printf("Testing range %g - %g\n", x, y);
120 nticks = calc_tickmarks(x, y, 10, &tm);
121
122 for (i = 0; i < nticks; i++) {
123 printf(" (%s) %g\n", tm[i].string, tm[i].value);
124 }
125 printf("\n\n");
126 free(tm);
127}
128
129int main(int argc, char *argv[])
130{
131 test_range(0.0005, 0.008);
132 test_range(0.5, 0.8);
133 test_range(5.5, 8.8);
134 test_range(50.5, 80.8);
135 test_range(-20, 20.8);
136 test_range(-30, 700.8);
137}
138#endif