[goffice] Log axis: handle steps that are not integer powers of 10.
- From: Morten Welinder <mortenw src gnome org>
- To: svn-commits-list gnome org
- Subject: [goffice] Log axis: handle steps that are not integer powers of 10.
- Date: Tue, 28 Apr 2009 12:52:26 -0400 (EDT)
commit 1886dfcfcc45e1689de3e0f1c55c164d767afc3a
Author: Morten Welinder <terra gnome org>
Date: Tue Apr 28 12:52:03 2009 -0400
Log axis: handle steps that are not integer powers of 10.
---
ChangeLog | 5 ++
NEWS | 3 +
goffice/graph/gog-axis.c | 145 +++++++++++++++++++++++++++++++---------------
3 files changed, 105 insertions(+), 48 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 582db82..2cd7d73 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2009-04-28 Morten Welinder <terra gnome org>
+
+ * goffice/graph/gog-axis.c (map_log_calc_ticks): Handle
+ non-integer major steps. Fixes #375756.
+
2009-04-27 Jean Brefort <jean brefort normalesup org>
* goffice/app/go-conf-*: use go_conf_node_get_key_type which looks
diff --git a/NEWS b/NEWS
index c875987..b6fd2b7 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,9 @@ goffice 0.7.6:
Jean:
* Fixed segfault during documentation generation. [#580296]
+Morten:
+ * Improve log axes' tick calculation. [#375756]
+
--------------------------------------------------------------------------
goffice 0.7.5:
diff --git a/goffice/graph/gog-axis.c b/goffice/graph/gog-axis.c
index 0707c6b..1977ab2 100644
--- a/goffice/graph/gog-axis.c
+++ b/goffice/graph/gog-axis.c
@@ -1095,66 +1095,115 @@ static void
map_log_calc_ticks (GogAxis *axis)
{
GogAxisTick *ticks;
- double maximum, minimum;
- double position;
- int major_tick, minor_tick, major_label, start_tick;
- int tick_nbr, i, j;
- int count;
-
- major_label = go_rint (gog_axis_get_entry (axis, GOG_AXIS_ELEM_MAJOR_TICK, NULL));
- minor_tick = go_rint (gog_axis_get_entry (axis, GOG_AXIS_ELEM_MINOR_TICK, NULL) + 1.0);
+ double maximum, minimum, lminimum, lmaximum, start_i, lrange;
+ double maj_step, min_step;
+ gboolean base10;
+ int t, N;
+ int maj_i, maj_N; /* Ticks for -1,....,maj_N */
+ int min_i, min_N; /* Ticks for 1,....,(min_N-1) */
- if (!gog_axis_get_bounds (axis, &minimum, &maximum) || major_label < 1) {
+ if (!gog_axis_get_bounds (axis, &minimum, &maximum) ||
+ minimum <= 0.0) {
gog_axis_set_ticks (axis, 2, create_invalid_axis_ticks (1.0, 10.0));
return;
}
- if (minimum <= 0.0) {
- gog_axis_set_ticks (axis, 2, create_invalid_axis_ticks (1.0, 10.0));
- return;
+
+ lminimum = log10 (minimum);
+ lmaximum = log10 (maximum);
+ lrange = lmaximum - lminimum;
+
+ /* This is log10(factor) between major ticks. */
+ maj_step = gog_axis_get_entry (axis, GOG_AXIS_ELEM_MAJOR_TICK, NULL);
+ if (!(maj_step > 0))
+ maj_step = 1;
+ while (1) {
+ double ratio = go_fake_floor (lrange / maj_step);
+ double Nd = (ratio + 1); /* Correct if no minor */
+ if (Nd > GOG_AXIS_MAX_TICK_NBR)
+ maj_step *= 2;
+ else {
+ maj_N = (int)ratio;
+ break;
+ }
}
+ base10 = (maj_step >= 1 && maj_step == floor (maj_step));
- start_tick = go_fake_floor (log10 (minimum));
- tick_nbr = major_tick = go_fake_ceil (go_fake_ceil (log10 (maximum)) -
- go_fake_floor (log10 (minimum)) + 1.0);
- tick_nbr *= minor_tick;
- if (tick_nbr < 1 || tick_nbr > GOG_AXIS_MAX_TICK_NBR) {
- gog_axis_set_ticks (axis, 0, NULL);
- return;
+ /*
+ * This is the number of subticks we want strictly between
+ * each major tick.
+ */
+ min_step = go_fake_floor (gog_axis_get_entry (axis, GOG_AXIS_ELEM_MINOR_TICK, NULL));
+ if (min_step < 0) {
+ min_N = 1;
+ } else if (base10) {
+ double mf = pow (10, maj_step);
+ if (min_step >= mf - 2 && maj_N * (mf - 1) <= GOG_AXIS_MAX_TICK_NBR)
+ min_N = (int)mf - 1;
+ else
+ min_N = 1;
+ } else {
+ while ((min_step + 1) * maj_N > GOG_AXIS_MAX_TICK_NBR)
+ min_step = floor (min_step / 2);
+ min_N = 1 + (int)min_step;
}
- ticks = g_new0 (GogAxisTick, tick_nbr);
-
- count = 0;
- for (i = 0; i < major_tick; i++) {
- position = pow (10.0, i + start_tick);
- if (position >= go_sub_epsilon (minimum) && go_sub_epsilon (position) <= maximum) {
- ticks[count].position = position;
- if (i % major_label == 0) {
- ticks[count].type = GOG_AXIS_TICK_MAJOR;
- ticks[count].label = axis_format_value
- (axis, position);
- count++;
- } else {
- ticks[count].type = GOG_AXIS_TICK_MINOR;
- ticks[count].label = NULL;
- count++;
- }
+ min_step = maj_step / min_N;
+
+ start_i = go_fake_ceil (lminimum / maj_step);
+ maj_N = (int)(go_fake_floor (lmaximum / maj_step) - start_i);
+
+#if 0
+ g_printerr ("lmin=%g lmax=%g maj_N=%d maj_step=%g start_i=%g\n",
+ lminimum, lmaximum, maj_N, maj_step, start_i);
+#endif
+
+ N = (maj_N + 2) * min_N;
+ ticks = g_new0 (GogAxisTick, N);
+
+ t = 0;
+ for (maj_i = -1; maj_i <= maj_N; maj_i++) {
+ /*
+ * Always calculate based on start to avoid a build-up of
+ * rounding errors. Note, that the left factor is an
+ * integer, so we will get precisely zero when we need
+ * to.
+ */
+ double maj_lpos = (start_i + maj_i) * maj_step;
+ double maj_pos = pow (10, maj_lpos);
+
+ if (maj_i >= 0) {
+ g_assert (t < N);
+ ticks[t].position = maj_pos;
+ ticks[t].type = GOG_AXIS_TICK_MAJOR;
+ ticks[t].label = axis_format_value (axis, maj_pos);
+ t++;
}
- for (j = 1; j < minor_tick; j++) {
- position = pow (10.0, i + start_tick) * (9.0 / (double)minor_tick * (double) j + 1.0);
- if (position >= go_sub_epsilon (minimum) && go_sub_epsilon (position) <= maximum) {
- ticks[count].position = position;
- ticks[count].type = GOG_AXIS_TICK_MINOR;
- ticks[count].label = NULL;
- count++;
+
+ for (min_i = 1; min_i < min_N; min_i++) {
+ double min_pos;
+
+ if (base10) {
+ min_pos = maj_pos * (1 + min_i);
+ } else {
+ double min_lpos = maj_lpos + min_i * min_step;
+ min_pos = pow (10, min_lpos);
}
+
+ if (min_pos < minimum)
+ continue;
+ if (min_pos > maximum)
+ break;
+
+ g_assert (t < N);
+ ticks[t].position = min_pos;
+ ticks[t].type = GOG_AXIS_TICK_MINOR;
+ ticks[t].label = NULL;
+ t++;
}
}
- if (count > tick_nbr)
- g_critical ("[GogAxisMap::log_calc_ticks] wrong memory allocation size");
-
- ticks = g_renew (GogAxisTick, ticks, count);
- gog_axis_set_ticks (axis, count, ticks);
+ if (t > N)
+ g_critical ("[GogAxisMap::log_calc_ticks] wrong allocation size");
+ gog_axis_set_ticks (axis, t, ticks);
}
/*****************************************************************************/
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]