1/*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include "chart/DefaultChartAxisLegendSource.h"
7
8#include <math.h>
9#include <stdio.h>
10
11#include "chart/ChartDataRange.h"
12#include "chart/StringChartLegend.h"
13
14
15int32
16DefaultChartAxisLegendSource::GetAxisLegends(const ChartDataRange& range,
17	ChartLegend** legends, double* values, int32 maxLegends)
18{
19// TODO: Also support scientific notation! Otherwise the numbers can get really
20// long.
21	double start = range.min;
22	double end = range.max;
23	double rangeSpan = end - start;
24
25	if (rangeSpan >= maxLegends / 2) {
26		// We only need to consider the integer part.
27
28		// find an interval so that we get maxLegends / 2 to maxLegends legends
29		double baseInterval = 1;
30		double relativeFactor = 1;
31		while (rangeSpan / baseInterval / relativeFactor >= maxLegends) {
32			if (relativeFactor == 1) {
33				relativeFactor = 2;
34			} else if (relativeFactor == 2) {
35				relativeFactor = 5;
36			} else if (relativeFactor == 5) {
37				baseInterval *= 10;
38				relativeFactor = 1;
39			}
40		}
41
42		// generate the legends
43		int32 count = 0;
44		double interval = baseInterval * relativeFactor;
45		double value = ceil(start / interval) * interval;
46		for (; value <= end; value += interval) {
47			char buffer[128];
48			snprintf(buffer, sizeof(buffer), "%.0f", value);
49			StringChartLegend* legend
50				= new(std::nothrow) StringChartLegend(buffer, 1);
51			if (legend == NULL)
52				return count;
53
54			legends[count] = legend;
55			values[count++] = value;
56		}
57
58		return count;
59	}
60
61	// The range is so small that we need a fraction interval.
62
63	// First find out how many places after the decimal point we need.
64	int positions = 0;
65	double factor = 1;
66	while (rangeSpan * factor < maxLegends / 2) {
67		factor *= 10;
68		positions++;
69	}
70
71	double relativeFactor = 1;
72	if (rangeSpan * factor / relativeFactor >= maxLegends) {
73		relativeFactor = 2;
74		if (rangeSpan * factor / relativeFactor >= maxLegends)
75			relativeFactor = 5;
76	}
77
78	// generate the legends
79	int32 count = 0;
80	double interval = relativeFactor / factor;
81	double shiftedValue = ceil(start / interval);
82	for (; shiftedValue * interval <= end; shiftedValue++) {
83		double value = shiftedValue * interval;
84		char buffer[128];
85		snprintf(buffer, sizeof(buffer), "%.*f", positions, value);
86		StringChartLegend* legend
87			= new(std::nothrow) StringChartLegend(buffer, 1);
88		if (legend == NULL)
89			return count;
90
91		legends[count] = legend;
92		values[count++] = value;
93	}
94
95	return count;
96}
97