blob: c99f5cd5cf890167944998da6fd3d938e1efb6a8 [file] [log] [blame]
Stephen M. Cameronaf58ef32012-03-07 07:56:16 +01001#include <stdio.h>
2#include <math.h>
3#include <malloc.h>
Stephen M. Cameron17ba3e42012-03-07 19:36:18 +01004#include <string.h>
Stephen M. Cameronaf58ef32012-03-07 07:56:16 +01005
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
Stephen M. Cameron17ba3e42012-03-07 19:36:18 +010042static void shorten(char *str)
43{
44 int l;
45
46 l = strlen(str);
47 if (l > 9 && strcmp(&str[l - 9], "000000000") == 0) {
48 str[l - 9] = 'G';
49 str[l - 8] = '\0';
50 } else if (l > 9 && strcmp(&str[l - 6], "000000") == 0) {
51 str[l - 6] = 'M';
52 str[l - 5] = '\0';
53 } else if (l > 9 && strcmp(&str[l - 3], "000") == 0) {
54 str[l - 3] = 'K';
55 str[l - 2] = '\0';
56 }
57}
58
Stephen M. Cameronaf58ef32012-03-07 07:56:16 +010059int calc_tickmarks(double min, double max, int nticks, struct tickmark **tm)
60{
61 char str[100];
62 int nfrac;
63 double d; /* tick mark spacing */
64 double graphmin, graphmax; /* graph range min and max */
65 double range, x;
66 int count, i;
67
68 /* we expect min != max */
69 range = nicenum(max - min, 0);
70 d = nicenum(range / (nticks - 1), 1);
71 graphmin = floor(min / d) * d;
72 graphmax = ceil(max / d) * d;
73 nfrac = MAX(-floor(log10(d)), 0);
74 snprintf(str, sizeof(str)-1, "%%.%df", nfrac);
75
76 count = ((graphmax + 0.5 * d) - graphmin) / d + 1;
77 *tm = malloc(sizeof(**tm) * count);
78
79 i = 0;
80 for (x = graphmin; x < graphmax + 0.5 * d; x += d) {
81 (*tm)[i].value = x;
82 sprintf((*tm)[i].string, str, x);
Stephen M. Cameron17ba3e42012-03-07 19:36:18 +010083 shorten((*tm)[i].string);
Stephen M. Cameronaf58ef32012-03-07 07:56:16 +010084 i++;
85 }
86 return i;
87}
88
89#if 0
90
91static void test_range(double x, double y)
92{
93 int nticks, i;
94
95 struct tickmark *tm = NULL;
96 printf("Testing range %g - %g\n", x, y);
97 nticks = calc_tickmarks(x, y, 10, &tm);
98
99 for (i = 0; i < nticks; i++) {
100 printf(" (%s) %g\n", tm[i].string, tm[i].value);
101 }
102 printf("\n\n");
103 free(tm);
104}
105
106int main(int argc, char *argv[])
107{
108 test_range(0.0005, 0.008);
109 test_range(0.5, 0.8);
110 test_range(5.5, 8.8);
111 test_range(50.5, 80.8);
112 test_range(-20, 20.8);
113 test_range(-30, 700.8);
114}
115#endif