Home | History | Annotate | Download | only in fio
      1 #include <stdio.h>
      2 #include <math.h>
      3 #include <malloc.h>
      4 #include <string.h>
      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 
     17 static 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 
     42 static void shorten(struct tickmark *tm, int nticks, int *power_of_ten,
     43 			int use_KMG_symbols, int base_offset)
     44 {
     45 	const char shorten_chr[] = { 0, 'K', 'M', 'G', 'P', 'E', 0 };
     46 	int i, l, minshorten, shorten_idx = 0;
     47 	char *str;
     48 
     49 	minshorten = 100;
     50 	for (i = 0; i < nticks; i++) {
     51 		str = tm[i].string;
     52 		l = strlen(str);
     53 
     54 		if (strcmp(str, "0") == 0)
     55 			continue;
     56 		if (l > 9 && strcmp(&str[l - 9], "000000000") == 0) {
     57 			*power_of_ten = 9;
     58 			shorten_idx = 3;
     59 		} else if (6 < minshorten && l > 6 &&
     60 				strcmp(&str[l - 6], "000000") == 0) {
     61 			*power_of_ten = 6;
     62 			shorten_idx = 2;
     63 		} else if (l > 3 && strcmp(&str[l - 3], "000") == 0) {
     64 			*power_of_ten = 3;
     65 			shorten_idx = 1;
     66 		} else {
     67 			*power_of_ten = 0;
     68 		}
     69 
     70 		if (*power_of_ten < minshorten)
     71 			minshorten = *power_of_ten;
     72 	}
     73 
     74 	if (minshorten == 0)
     75 		return;
     76 	if (!use_KMG_symbols)
     77 		shorten_idx = 0;
     78 	else if (base_offset)
     79 		shorten_idx += base_offset;
     80 
     81 	for (i = 0; i < nticks; i++) {
     82 		str = tm[i].string;
     83 		l = strlen(str);
     84 		str[l - minshorten] = shorten_chr[shorten_idx];
     85 		if (shorten_idx)
     86 			str[l - minshorten + 1] = '\0';
     87 	}
     88 }
     89 
     90 int calc_tickmarks(double min, double max, int nticks, struct tickmark **tm,
     91 		int *power_of_ten, int use_KMG_symbols, int base_offset)
     92 {
     93 	char str[100];
     94 	int nfrac;
     95 	double d;	/* tick mark spacing */
     96 	double graphmin, graphmax;	/* graph range min and max */
     97 	double range, x;
     98 	int count, i;
     99 
    100 	/* we expect min != max */
    101 	range = nicenum(max - min, 0);
    102 	d = nicenum(range / (nticks - 1), 1);
    103 	graphmin = floor(min / d) * d;
    104 	graphmax = ceil(max / d) * d;
    105 	nfrac = MAX(-floor(log10(d)), 0);
    106 	snprintf(str, sizeof(str)-1, "%%.%df", nfrac);
    107 
    108 	count = ((graphmax + 0.5 * d) - graphmin) / d + 1;
    109 	*tm = malloc(sizeof(**tm) * count);
    110 
    111 	i = 0;
    112 	for (x = graphmin; x < graphmax + 0.5 * d; x += d) {
    113 		(*tm)[i].value = x;
    114 		sprintf((*tm)[i].string, str, x);
    115 		i++;
    116 	}
    117 	shorten(*tm, i, power_of_ten, use_KMG_symbols, base_offset);
    118 	return i;
    119 }
    120 
    121 #if 0
    122 
    123 static void test_range(double x, double y)
    124 {
    125 	int nticks, i;
    126 
    127 	struct tickmark *tm = NULL;
    128 	printf("Testing range %g - %g\n", x, y);
    129 	nticks = calc_tickmarks(x, y, 10, &tm);
    130 
    131 	for (i = 0; i < nticks; i++)
    132 		printf("   (%s) %g\n", tm[i].string, tm[i].value);
    133 
    134 	printf("\n\n");
    135 	free(tm);
    136 }
    137 
    138 int main(int argc, char *argv[])
    139 {
    140 	test_range(0.0005, 0.008);
    141 	test_range(0.5, 0.8);
    142 	test_range(5.5, 8.8);
    143 	test_range(50.5, 80.8);
    144 	test_range(-20, 20.8);
    145 	test_range(-30, 700.8);
    146 }
    147 #endif
    148