gfio: Add mini library to draw bar graphs and line graphs
[fio.git] / tickmarks.c
diff --git a/tickmarks.c b/tickmarks.c
new file mode 100644 (file)
index 0000000..7766acd
--- /dev/null
@@ -0,0 +1,96 @@
+#include <stdio.h>
+#include <math.h>
+#include <malloc.h>
+
+/* 
+ * adapted from Paul Heckbert's algorithm on p 657-659 of
+ * Andrew S. Glassner's book, "Graphics Gems"
+ * ISBN 0-12-286166-3
+ *
+ */
+
+#include "tickmarks.h"
+
+#define MAX(a, b) (((a) < (b)) ? (b) : (a))
+
+static double nicenum(double x, int round)
+{
+       int exp;        /* exponent of x */
+       double f;       /* fractional part of x */
+
+       exp = floor(log10(x));
+       f = x / pow(10.0, exp);
+       if (round) {
+               if (f < 1.5)
+                       return 1.0 * pow(10.0, exp);
+               if (f < 3.0)
+                       return 2.0 * pow(10.0, exp);
+               if (f < 7.0)
+                       return 5.0 * pow(10.0, exp);
+               return 10.0 * pow(10.0, exp);
+       }
+       if (f <= 1.0)
+               return 1.0 * pow(10.0, exp);
+       if (f <= 2.0)
+               return 2.0 * pow(10.0, exp);
+       if (f <= 5.0)
+               return 5.0 * pow(10.0, exp);
+       return 10.0 * pow(10.0, exp);
+}
+
+int calc_tickmarks(double min, double max, int nticks, struct tickmark **tm)
+{
+       char str[100];
+       int nfrac;
+       double d;       /* tick mark spacing */
+       double graphmin, graphmax;      /* graph range min and max */
+       double range, x;
+       int count, i;
+
+       /* we expect min != max */
+       range = nicenum(max - min, 0);
+       d = nicenum(range / (nticks - 1), 1);
+       graphmin = floor(min / d) * d;
+       graphmax = ceil(max / d) * d;
+       nfrac = MAX(-floor(log10(d)), 0);
+       snprintf(str, sizeof(str)-1, "%%.%df", nfrac);
+
+       count = ((graphmax + 0.5 * d) - graphmin) / d + 1;
+       *tm = malloc(sizeof(**tm) * count);
+
+       i = 0;
+       for (x = graphmin; x < graphmax + 0.5 * d; x += d) {
+               (*tm)[i].value = x;
+               sprintf((*tm)[i].string, str, x);
+               i++;
+       }
+       return i;
+}
+
+#if 0
+
+static void test_range(double x, double y)
+{
+       int nticks, i;
+
+       struct tickmark *tm = NULL;
+       printf("Testing range %g - %g\n", x, y);
+       nticks = calc_tickmarks(x, y, 10, &tm);
+
+       for (i = 0; i < nticks; i++) {
+               printf("   (%s) %g\n", tm[i].string, tm[i].value);
+       }
+       printf("\n\n");
+       free(tm);
+}
+
+int main(int argc, char *argv[])
+{
+       test_range(0.0005, 0.008);      
+       test_range(0.5, 0.8);   
+       test_range(5.5, 8.8);   
+       test_range(50.5, 80.8); 
+       test_range(-20, 20.8);  
+       test_range(-30, 700.8); 
+}
+#endif