[goffice] Add control for 3D plots axes lengths. [#694746]
- From: Jean Bréfort <jbrefort src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [goffice] Add control for 3D plots axes lengths. [#694746]
- Date: Thu, 29 May 2014 19:00:28 +0000 (UTC)
commit 9f09bedbb0a0234b0f7b48a4a6518fd284a9b99d
Author: Jean Brefort <jean brefort normalesup org>
Date: Thu May 29 21:00:03 2014 +0200
Add control for 3D plots axes lengths. [#694746]
ChangeLog | 11 ++
NEWS | 3 +
goffice/Makefile.am | 2 +
goffice/goffice.c | 1 +
goffice/graph/gog-axis.c | 378 ++++++++++++++++++++++++++++++++++++++++-
goffice/graph/gog-axis.h | 13 ++-
goffice/graph/gog-chart.c | 97 ++++++++++-
goffice/utils/go-unit.c | 138 +++++++++++++++
goffice/utils/go-unit.h | 53 ++++++
goffice/utils/goffice-utils.h | 1 +
10 files changed, 687 insertions(+), 10 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index e730141..d02f9d9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2014-05-29 Jean Brefort <jean brefort normalesup org>
+
+ * goffice/Makefile.am: new GoUnit objects.
+ * goffice/goffice.c (libgoffice_shutdown): ditto.
+ * goffice/graph/gog-axis.c: Add control for 3D plots axes lengths. [#694746]
+ * goffice/graph/gog-axis.h: ditto.
+ * goffice/graph/gog-chart.c (gog_chart_view_3d_process): ditto.
+ * goffice/utils/goffice-utils.h: new GoUnit objects.
+ * goffice/utils/go-unit.c: ditto.
+ * goffice/utils/go-unit.h: ditto.
+
2014-05-23 Morten Welinder <terra gnome org>
* configure.ac: Post-release bump.
diff --git a/NEWS b/NEWS
index ade06bd..7c8cb4d 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,8 @@
goffice 0.10.17:
+Jean:
+ * Add control for 3D plots axes lengths. [#694746]
+
--------------------------------------------------------------------------
goffice 0.10.16:
diff --git a/goffice/Makefile.am b/goffice/Makefile.am
index 030a6a3..71e2b2d 100644
--- a/goffice/Makefile.am
+++ b/goffice/Makefile.am
@@ -395,6 +395,7 @@ utils_SOURCES = \
utils/go-rsm.c \
utils/go-string.c \
utils/go-undo.c \
+ utils/go-unit.c \
utils/datetime.c \
utils/formats.c \
utils/go-format.c \
@@ -429,6 +430,7 @@ utils_HEADERS = \
utils/go-mml-to-itex.h \
utils/go-path.h \
utils/go-pattern.h \
+ utils/go-unit.h \
utils/go-units.h \
utils/go-geometry.h \
utils/go-string.h \
diff --git a/goffice/goffice.c b/goffice/goffice.c
index 98d49e5..9d52425 100644
--- a/goffice/goffice.c
+++ b/goffice/goffice.c
@@ -271,6 +271,7 @@ libgoffice_shutdown (void)
_go_string_shutdown ();
_go_locale_shutdown ();
_go_rsm_shutdown ();
+ _go_unit_shutdown ();
#ifdef G_OS_WIN32
/* const_cast, we created these above */
g_free ((char *)libgoffice_data_dir);
diff --git a/goffice/graph/gog-axis.c b/goffice/graph/gog-axis.c
index 1a1489f..2cf2c7e 100644
--- a/goffice/graph/gog-axis.c
+++ b/goffice/graph/gog-axis.c
@@ -93,6 +93,46 @@ static struct {
typedef struct _GogAxisMapDesc GogAxisMapDesc;
+static struct {
+ GogAxisMetrics metrics;
+ const char *name;
+} metrics_desc[GOG_AXIS_METRICS_MAX] = {
+ { GOG_AXIS_METRICS_DEFAULT, "default"},
+ { GOG_AXIS_METRICS_ABSOLUTE, "absolute"},
+ { GOG_AXIS_METRICS_RELATIVE, "relative"},
+ { GOG_AXIS_METRICS_RELATIVE_TICKS, "relative-ticks-distance"}
+};
+
+static GogAxisMetrics
+gog_axis_metrics_from_str (char const *name)
+{
+ unsigned i;
+ GogAxisMetrics ret = GOG_AXIS_METRICS_DEFAULT;
+
+ for (i = 0; i < GO_LINE_MAX; i++) {
+ if (strcmp (metrics_desc[i].name, name) == 0) {
+ ret = metrics_desc[i].metrics;
+ break;
+ }
+ }
+ return ret;
+}
+
+static char const *
+gog_axis_metrics_as_str (GogAxisMetrics metrics)
+{
+ unsigned i;
+ char const *ret = "default";
+
+ for (i = 0; i < GO_LINE_MAX; i++) {
+ if (metrics_desc[i].metrics == metrics) {
+ ret = metrics_desc[i].name;
+ break;
+ }
+ }
+ return ret;
+}
+
struct _GogAxis {
GogAxisBase base;
@@ -126,6 +166,11 @@ struct _GogAxis {
GogAxisColorMap const *color_map; /* color map for color and pseudo-3d axis */
gboolean auto_color_map;
GogColorScale *color_scale;
+ GogAxisMetrics metrics;
+ GogAxis *ref_axis;
+ GSList *refering_axes;
+ double metrics_ratio;
+ GoUnitId unit;
};
/*****************************************************************************/
@@ -2093,7 +2138,11 @@ enum {
AXIS_PROP_POLAR_UNIT,
AXIS_PROP_SPAN_START,
AXIS_PROP_SPAN_END,
- AXIS_PROP_COLOR_MAP
+ AXIS_PROP_COLOR_MAP,
+ AXIS_PROP_METRICS,
+ AXIS_PROP_REF_AXIS,
+ AXIS_PROP_METRICS_RATIO,
+ AXIS_PROP_METRICS_UNIT
};
/*****************************************************************************/
@@ -2255,6 +2304,44 @@ gog_axis_sax_save (GOPersist const *gp, GsfXMLOut *output)
GO_PERSIST (axis->color_map));
}
+struct axis_ref_struct {
+ GogAxis *axis;
+ char *ref;
+};
+
+static gboolean
+axis_ref_load_cb (struct axis_ref_struct *s)
+{
+ GogObject *parent = gog_object_get_parent ((GogObject *) s->axis);
+ GogAxis *axis;
+ GSList *ptr, *l;
+ l = gog_object_get_children (parent, NULL);
+ s->axis->ref_axis = NULL;
+ if (s->axis->refering_axes != NULL) {
+ s->axis->metrics = GOG_AXIS_METRICS_DEFAULT;
+ s->axis->metrics_ratio = 1.;
+ s->axis->unit = GO_UNIT_CENTIMETER;
+ goto clean;
+ }
+ for (ptr = l; (ptr != NULL) && (s->axis->ref_axis == NULL); ptr = ptr->next) {
+ if (!GOG_IS_AXIS (ptr->data))
+ continue;
+ axis = ptr->data;
+ if (axis->metrics > GOG_AXIS_METRICS_ABSOLUTE || axis == s->axis)
+ continue;
+ if (!strcmp (gog_object_get_name (ptr->data), s->ref)) {
+ s->axis->ref_axis = axis;
+ axis->refering_axes = g_slist_prepend (axis->refering_axes, s->axis);
+ }
+ }
+ g_slist_free (l);
+clean:
+ gog_object_request_update ((GogObject *) s->axis);
+ g_free (s->ref);
+ g_free (s);
+ return FALSE;
+}
+
static void
gog_axis_set_property (GObject *obj, guint param_id,
GValue const *value, GParamSpec *pspec)
@@ -2337,6 +2424,30 @@ gog_axis_set_property (GObject *obj, guint param_id,
}
break;
}
+ case AXIS_PROP_METRICS:
+ axis->metrics = gog_axis_metrics_from_str (g_value_get_string (value));
+ break;
+ case AXIS_PROP_REF_AXIS: {
+ char const *str = g_value_get_string (value);
+ if ((axis->ref_axis == NULL && !strcmp (str, "none")) ||
+ (axis->ref_axis && !strcmp (gog_object_get_name (GOG_OBJECT (axis->ref_axis)), str)))
+ return;
+ if (strcmp (str, "none")) {
+ struct axis_ref_struct *s = g_new (struct axis_ref_struct, 1);
+ s->ref = g_strdup (str);
+ s->axis = axis;
+ g_idle_add ((GSourceFunc) axis_ref_load_cb, s);
+ return;
+ }
+ axis->ref_axis = NULL;
+ break;
+ }
+ case AXIS_PROP_METRICS_RATIO:
+ axis->metrics_ratio = g_value_get_double (value);
+ break;
+ case AXIS_PROP_METRICS_UNIT:
+ axis->unit = (strcmp (g_value_get_string (value), "in"))? GO_UNIT_CENTIMETER: GO_UNIT_INCH;
+ break;
default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
return; /* NOTE : RETURN */
@@ -2389,6 +2500,21 @@ gog_axis_get_property (GObject *obj, guint param_id,
case AXIS_PROP_COLOR_MAP:
g_value_set_string (value, (axis->auto_color_map)? "default": gog_axis_color_map_get_id
(axis->color_map));
break;
+ case AXIS_PROP_METRICS:
+ g_value_set_string (value, gog_axis_metrics_as_str (axis->metrics));
+ break;
+ case AXIS_PROP_REF_AXIS:
+ if (axis->ref_axis == NULL || axis->metrics < GOG_AXIS_METRICS_RELATIVE)
+ g_value_set_string (value, "none");
+ else
+ g_value_set_string (value, gog_object_get_name ((GogObject *) axis->ref_axis));
+ break;
+ case AXIS_PROP_METRICS_RATIO:
+ g_value_set_double (value, axis->metrics_ratio);
+ break;
+ case AXIS_PROP_METRICS_UNIT:
+ g_value_set_string (value, (axis->unit == GO_UNIT_INCH)? "in": "cm");
+ break;
default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
break;
@@ -2830,6 +2956,101 @@ add_color_map_cb (GogAxisColorMap const *map, struct ColorMapState *state)
gtk_combo_box_set_active_iter (state->combo, &iter);
}
+struct MetricsState {
+ GogAxis *axis;
+ GtkWidget *axes, *label, *ratio, *unit;
+};
+
+static void
+metrics_ratio_changed_cb (GtkSpinButton *btn, struct MetricsState *state)
+{
+ state->axis->metrics_ratio = gtk_spin_button_get_value (btn);
+ gog_object_request_update ((GogObject *) state->axis);
+}
+
+static void
+metrics_unit_changed_cb (GtkComboBox *box, struct MetricsState *state)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model = gtk_combo_box_get_model (box);
+ gtk_combo_box_get_active_iter (box, &iter);
+ gtk_tree_model_get (model, &iter, 1, &state->axis->unit, -1);
+ gog_object_request_update ((GogObject *) state->axis);
+}
+
+static void
+metrics_axis_changed_cb (GtkComboBox *box, struct MetricsState *state)
+{
+ GogAxis *ref_axis;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ if (state->axis->ref_axis != NULL)
+ state->axis->ref_axis->refering_axes = g_slist_remove (state->axis->ref_axis->refering_axes,
state->axis);
+ model = gtk_combo_box_get_model (box);
+ gtk_combo_box_get_active_iter (box, &iter);
+ gtk_tree_model_get (model, &iter, 1, &ref_axis, -1);
+ ref_axis->refering_axes = g_slist_prepend (ref_axis->refering_axes, state->axis);
+ state->axis->ref_axis = ref_axis;
+ gog_object_request_update ((GogObject *) state->axis);
+}
+
+static void
+metrics_changed_cb (GtkComboBox *box, struct MetricsState *state)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ model = gtk_combo_box_get_model (box);
+ gtk_combo_box_get_active_iter (box, &iter);
+ gtk_tree_model_get (model, &iter, 1, &state->axis->metrics, -1);
+ switch (state->axis->metrics) {
+ case GOG_AXIS_METRICS_DEFAULT:
+ gtk_widget_hide (state->axes);
+ gtk_widget_hide (state->label);
+ gtk_widget_hide (state->ratio);
+ gtk_widget_hide (state->unit);
+ state->axis->ref_axis = NULL;
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (state->ratio), 1.);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (state->unit), 0);
+ break;
+ case GOG_AXIS_METRICS_ABSOLUTE:
+ gtk_widget_hide (state->axes);
+ state->axis->ref_axis = NULL;
+ gtk_label_set_text (GTK_LABEL (state->label), _("Distance:"));
+ gtk_widget_show (state->label);
+ gtk_widget_show (state->ratio);
+ gtk_widget_show (state->unit);
+ break;
+ case GOG_AXIS_METRICS_RELATIVE:
+ gtk_widget_show (state->axes);
+ gtk_label_set_text (GTK_LABEL (state->label), _("Ratio:"));
+ gtk_widget_show (state->label);
+ gtk_widget_show (state->ratio);
+ gtk_widget_hide (state->unit);
+ if (gtk_combo_box_get_active ((GtkComboBox *) state->axes) < 0)
+ gtk_combo_box_set_active ((GtkComboBox *) state->axes, 0);
+ else
+ metrics_axis_changed_cb (GTK_COMBO_BOX (state->axes), state);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (state->unit), 0);
+ break;
+ case GOG_AXIS_METRICS_RELATIVE_TICKS:
+ gtk_widget_show (state->axes);
+ gtk_label_set_text (GTK_LABEL (state->label), _("Ratio:"));
+ gtk_widget_show (state->label);
+ gtk_widget_show (state->ratio);
+ gtk_widget_hide (state->unit);
+ if (gtk_combo_box_get_active ((GtkComboBox *) state->axes) < 0)
+ gtk_combo_box_set_active ((GtkComboBox *) state->axes, 0);
+ else
+ metrics_axis_changed_cb ((GtkComboBox *) state->axes, state);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (state->unit), 0);
+ break;
+ default:
+ /* will never occur */
+ break;
+ }
+ gog_object_request_update ((GogObject *) state->axis);
+}
+
static void
gog_axis_populate_editor (GogObject *gobj,
GOEditor *editor,
@@ -3014,6 +3235,117 @@ gog_axis_populate_editor (GogObject *gobj,
go_gtk_builder_get_widget (gui, "color-map-grid"),
_("Colors"));
}
+ /* Metrics */
+ if ((axis->type == GOG_AXIS_X || axis->type == GOG_AXIS_Y ||
+ axis->type == GOG_AXIS_Z || axis->type == GOG_AXIS_RADIAL)
+ && (gog_chart_is_3d (GOG_CHART (gog_object_get_parent ((GogObject *) axis)))
+ && axis->refering_axes == NULL)) {
+ /* only 3d for now */
+ GogChart *parent = GOG_CHART (gog_object_get_parent ((GogObject *) axis));
+ GogAxis *axis_;
+ GtkGrid *grid;
+ GtkWidget *combo;
+ GSList *l, *ptr;
+ GtkListStore *store;
+ GtkCellRenderer *cell;
+ GtkTreeIter iter;
+ GtkAdjustment *adj;
+ GoUnit const *unit;
+ struct MetricsState *state = g_new (struct MetricsState, 1);
+ state->axis = axis;
+ w = gtk_grid_new ();
+ g_object_set (w, "border-width", 12, "column-spacing", 12, "row-spacing", 6, NULL);
+ gtk_widget_show (w);
+ grid = GTK_GRID (w);
+ store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_UINT);
+ combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
+ cell = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell,
+ "text", 0, NULL);
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, _("Default"), 1, GOG_AXIS_METRICS_DEFAULT, -1);
+ if (axis->metrics == GOG_AXIS_METRICS_DEFAULT)
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &iter);
+ if (!gog_chart_is_3d ((GogChart *) parent)) {
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, _("Absolute"), 1, GOG_AXIS_METRICS_ABSOLUTE, -1);
+ if (axis->metrics == GOG_AXIS_METRICS_ABSOLUTE)
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &iter);
+ }
+ if (axis->refering_axes == NULL) {
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, _("Relative length"), 1,
GOG_AXIS_METRICS_RELATIVE, -1);
+ if (axis->metrics == GOG_AXIS_METRICS_RELATIVE)
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &iter);
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, _("Relative ticks distance"), 1,
GOG_AXIS_METRICS_RELATIVE_TICKS, -1);
+ if (axis->metrics == GOG_AXIS_METRICS_RELATIVE_TICKS)
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &iter);
+ }
+ gtk_grid_attach (grid, combo, 0, 0, 3, 1);
+ gtk_widget_show ((GtkWidget *) combo);
+ state->axes = gtk_combo_box_new ();
+ store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
+ gtk_combo_box_set_model (GTK_COMBO_BOX (state->axes), GTK_TREE_MODEL (store));
+ cell = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (state->axes), cell, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (state->axes), cell,
+ "text", 0, NULL);
+ l = gog_object_get_children ((GogObject *) parent, NULL);
+ for (ptr = l; ptr != NULL; ptr = ptr->next) {
+ if (!GOG_IS_AXIS (ptr->data))
+ continue;
+ axis_ = ptr->data;
+ if (axis_->metrics > GOG_AXIS_METRICS_ABSOLUTE || axis_ == axis)
+ continue;
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, gog_object_get_name (ptr->data), 1, axis_, -1);
+ if (axis_ == axis->ref_axis)
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (state->axes), &iter);
+ }
+ /* now add a spin button for the metrix_ratio */
+ gtk_grid_attach (grid, state->axes, 0, 1, 3, 1);
+ g_signal_connect (state->axes, "changed", G_CALLBACK (metrics_axis_changed_cb), state);
+ if (axis->metrics > GOG_AXIS_METRICS_ABSOLUTE)
+ gtk_widget_show (state->axes);
+ state->label = gtk_label_new (NULL); /* the text will be set later */
+ gtk_grid_attach (grid, state->label, 0, 2, 1, 1);
+ g_signal_connect (combo, "changed", G_CALLBACK (metrics_changed_cb), state);
+ /* now add a spin button for the metrix_ratio */
+ adj = gtk_adjustment_new (1., 0.01, 100., .1, 1., 1.);
+ state->ratio = gtk_spin_button_new (adj, .1, 2);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (state->ratio), axis->metrics_ratio);
+ g_signal_connect (state->ratio, "value-changed", G_CALLBACK (metrics_ratio_changed_cb),
state);
+ gtk_grid_attach (grid, state->ratio, 1, 2, 1, 1);
+ state->unit = gtk_combo_box_new ();
+ store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
+ gtk_combo_box_set_model (GTK_COMBO_BOX (state->unit), GTK_TREE_MODEL (store));
+ cell = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (state->unit), cell, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (state->unit), cell,
+ "text", 0, NULL);
+ unit = go_unit_get (GO_UNIT_CENTIMETER);
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, go_unit_get_symbol (unit), 1, unit, -1);
+ if (axis->unit == GO_UNIT_CENTIMETER)
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (state->unit), &iter);
+ unit = go_unit_get (GO_UNIT_INCH);
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, go_unit_get_symbol (unit), 1, unit, -1);
+ if (axis->unit == GO_UNIT_INCH)
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (state->unit), &iter);
+ gtk_grid_attach (grid, state->unit, 2, 2, 1, 1);
+ g_signal_connect (state->unit, "changed", G_CALLBACK (metrics_unit_changed_cb), state);
+ if (axis->metrics >= GOG_AXIS_METRICS_ABSOLUTE) {
+ gtk_widget_show (state->label);
+ gtk_widget_show (state->ratio);
+ if (axis->metrics == GOG_AXIS_METRICS_ABSOLUTE)
+ gtk_widget_show (state->unit);
+ }
+ g_object_set_data_full ((GObject *) w, "state", state, g_free);
+ go_editor_add_page (editor, w, _("Metrics"));
+ }
if (gog_object_is_visible (axis) && gog_axis_get_atype (axis) < GOG_AXIS_VIRTUAL) {
/* Style page */
@@ -3143,6 +3475,27 @@ gog_axis_class_init (GObjectClass *gobject_klass)
_("The name of the color map"),
"default",
GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
+ g_object_class_install_property (gobject_klass, AXIS_PROP_METRICS,
+ g_param_spec_string ("metrics", _("Metrics"),
+ _("The way the axis ticks distance is evaluated"),
+ "default",
+ GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
+ g_object_class_install_property (gobject_klass, AXIS_PROP_REF_AXIS,
+ g_param_spec_string ("axis-ref", _("AxisRef"),
+ _("The name of the axis used as reference for ticks distance"),
+ "none",
+ GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
+ g_object_class_install_property (gobject_klass, AXIS_PROP_METRICS_RATIO,
+ g_param_spec_double ("metrics-ratio",
+ _("Metrics ratio"),
+ _("If an axis is used as reference, gives the ratio of the ticks distance, and it the
metrix is absolute, the ticks distance. Defaults to 1.0"),
+ 0.01, 100., 1.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
+ g_object_class_install_property (gobject_klass, AXIS_PROP_REF_AXIS,
+ g_param_spec_string ("metrics-unit", _("Matrics Unit"),
+ _("The unit symbol for the absolute distance unit between ticks. Might be \"cm\" or
\"in\""),
+ "cm",
+ GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
gog_object_register_roles (gog_klass, roles, G_N_ELEMENTS (roles));
@@ -3181,6 +3534,8 @@ gog_axis_init (GogAxis *axis)
axis->span_start = 0.;
axis->span_end = 1.;
axis->auto_color_map = TRUE;
+ axis->metrics_ratio = 1.;
+ axis->unit = GO_UNIT_CENTIMETER;
}
static void
@@ -3617,6 +3972,27 @@ _gog_axis_set_color_scale (GogAxis *axis, GogColorScale *scale)
axis->color_scale = scale;
}
+GogAxisMetrics
+gog_axis_get_metrics (GogAxis const *axis)
+{
+ g_return_val_if_fail (GOG_IS_AXIS (axis), GOG_AXIS_METRICS_INVALID);
+ return axis->metrics;
+}
+
+GogAxis *
+gog_axis_get_ref_axis (GogAxis const *axis)
+{
+ g_return_val_if_fail (GOG_IS_AXIS (axis) && axis->metrics > GOG_AXIS_METRICS_ABSOLUTE, NULL);
+ return axis->ref_axis;
+}
+
+double
+gog_axis_get_major_ticks_distance (GogAxis const *axis)
+{
+ g_return_val_if_fail (GOG_IS_AXIS (axis), go_nan);
+ return gog_axis_get_entry (axis, GOG_AXIS_ELEM_MAJOR_TICK, NULL);
+}
+
/****************************************************************************/
typedef GogAxisBaseView GogAxisView;
diff --git a/goffice/graph/gog-axis.h b/goffice/graph/gog-axis.h
index 2cc1fd1..d2d107b 100644
--- a/goffice/graph/gog-axis.h
+++ b/goffice/graph/gog-axis.h
@@ -42,6 +42,15 @@ typedef enum {
GOG_AXIS_ELEM_MAX_ENTRY
} GogAxisElemType;
+typedef enum {
+ GOG_AXIS_METRICS_INVALID = -1,
+ GOG_AXIS_METRICS_DEFAULT,
+ GOG_AXIS_METRICS_ABSOLUTE,
+ GOG_AXIS_METRICS_RELATIVE,
+ GOG_AXIS_METRICS_RELATIVE_TICKS,
+ GOG_AXIS_METRICS_MAX
+} GogAxisMetrics;
+
typedef struct {
double position;
GogAxisTickTypes type;
@@ -111,7 +120,9 @@ double gog_axis_get_polar_perimeter (GogAxis *axis);
double gog_axis_get_circular_rotation (GogAxis *axis);
GogAxisColorMap const *gog_axis_get_color_map (GogAxis *axis);
GogColorScale *gog_axis_get_color_scale (GogAxis *axis);
-
+GogAxisMetrics gog_axis_get_metrics (GogAxis const *axis);
+GogAxis *gog_axis_get_ref_axis (GogAxis const *axis);
+double gog_axis_get_major_ticks_distance (GogAxis const *axis);
/* private */
void _gog_axis_set_color_scale (GogAxis *axis, GogColorScale *scale);
diff --git a/goffice/graph/gog-chart.c b/goffice/graph/gog-chart.c
index 6d69c37..1977cc4 100644
--- a/goffice/graph/gog-chart.c
+++ b/goffice/graph/gog-chart.c
@@ -1141,7 +1141,7 @@ gog_chart_view_3d_process (GogView *view, GogViewAllocation *bbox)
/* A XYZ axis set in supposed. If new sets (cylindrical, spherical or
other are added, we'll need to change this code */
GogViewAllocation tmp = *bbox;
- GogAxis *axisX, *axisY, *axisZ;
+ GogAxis *axisX, *axisY, *axisZ, *ref = NULL;
GSList *axes;
double xmin, xmax, ymin, ymax, zmin, zmax;
double o[3], x[3], y[3], z[3], tg, d;
@@ -1152,6 +1152,7 @@ gog_chart_view_3d_process (GogView *view, GogViewAllocation *bbox)
GSList *ptr;
GogView *child;
GogViewPadding padding;
+ GogAxisMetrics xm, ym, zm;
if (!obj) {
obj = g_object_new (GOG_3D_BOX_TYPE, NULL);
@@ -1163,25 +1164,105 @@ gog_chart_view_3d_process (GogView *view, GogViewAllocation *bbox)
/* Only use the first of the axes. */
axes = gog_chart_get_axes (chart, GOG_AXIS_X);
axisX = GOG_AXIS (axes->data);
+ xm = gog_axis_get_metrics (axisX);
+ if (xm != GOG_AXIS_METRICS_DEFAULT)
+ ref = gog_axis_get_ref_axis (axisX);
g_slist_free (axes);
gog_axis_get_bounds (axisX, &xmin, &xmax);
axes = gog_chart_get_axes (chart, GOG_AXIS_Y);
axisY = GOG_AXIS (axes->data);
+ ym = gog_axis_get_metrics (axisY);
+ if (ym != GOG_AXIS_METRICS_DEFAULT && ref == NULL)
+ ref = gog_axis_get_ref_axis (axisY);
g_slist_free (axes);
gog_axis_get_bounds (axisY, &ymin, &ymax);
axes = gog_chart_get_axes (chart, GOG_AXIS_Z);
axisZ = GOG_AXIS (axes->data);
+ zm = gog_axis_get_metrics (axisZ);
+ if (zm != GOG_AXIS_METRICS_DEFAULT && ref == NULL)
+ ref = gog_axis_get_ref_axis (axisZ);
g_slist_free (axes);
gog_axis_get_bounds (axisZ, &zmin, &zmax);
/* define the 3d box */
- /* FIXME: take axes into account */
- box_view->dz = tmp.h;
- if (ymax - ymin > xmax - xmin) {
- box_view->dy = tmp.w;
- box_view->dx = (xmax - xmin) / (ymax - ymin) * tmp.w;
+ if (ref == NULL) {
+ box_view->dz = tmp.h;
+ if (ymax - ymin > xmax - xmin) {
+ box_view->dy = tmp.w;
+ box_view->dx = (xmax - xmin) / (ymax - ymin) * tmp.w;
+ } else {
+ box_view->dx = tmp.w;
+ box_view->dy = (ymax - ymin) / (xmax - xmin) * tmp.w;
+ }
} else {
- box_view->dx = tmp.w;
- box_view->dy = (ymax - ymin) / (xmax - xmin) * tmp.w;
+ double ref_length, ref_tick_dist, xspan, yspan, zspan;
+ gog_axis_get_bounds (ref, &ref_length, &xspan);
+ ref_length -= xspan;
+ ref_tick_dist = gog_axis_get_major_ticks_distance (ref);
+ xspan = xmax - xmin;
+ if (xm == GOG_AXIS_METRICS_RELATIVE_TICKS) {
+ double ratio, tick_dist = gog_axis_get_major_ticks_distance (axisX);
+ g_object_get (axisX, "metrics-ratio", &ratio, NULL);
+ xspan = (xmax - xmin) / tick_dist * ref_tick_dist * ratio;
+ }
+ yspan = ymax - ymin;
+ if (ym == GOG_AXIS_METRICS_RELATIVE_TICKS) {
+ double ratio, tick_dist = gog_axis_get_major_ticks_distance (axisY);
+ g_object_get (axisY, "metrics-ratio", &ratio, NULL);
+ yspan = (ymax - ymin) / tick_dist * ref_tick_dist * ratio;
+ }
+ zspan = zmax - zmin;
+ if (zm == GOG_AXIS_METRICS_RELATIVE_TICKS) {
+ double ratio, tick_dist = gog_axis_get_major_ticks_distance (axisZ);
+ g_object_get (axisZ, "metrics-ratio", &ratio, NULL);
+ zspan = (zmax - zmin) / tick_dist * ref_tick_dist * ratio;
+ }
+ if (ref == axisZ) {
+ gboolean xrel = FALSE;
+ box_view->dz = tmp.h;
+ switch (xm) {
+ case GOG_AXIS_METRICS_RELATIVE:
+ case GOG_AXIS_METRICS_RELATIVE_TICKS:
+ box_view->dx = xspan / zspan * tmp.h;
+ if (box_view->dx > tmp.w) {
+ box_view->dz *= tmp.w / box_view->dx;
+ box_view->dx = tmp.w;
+ }
+ xrel = TRUE;
+ break;
+ default:
+ box_view->dx = tmp.w;
+ break;
+ }
+ switch (ym) {
+ case GOG_AXIS_METRICS_RELATIVE:
+ case GOG_AXIS_METRICS_RELATIVE_TICKS:
+ box_view->dy = yspan / zspan * box_view->dz;
+ if (box_view->dy > tmp.w) {
+ box_view->dz *= tmp.w / box_view->dy;
+ if (xrel)
+ box_view->dx *= tmp.w / box_view->dy;
+ box_view->dy = tmp.w;
+ }
+ break;
+ default:
+ box_view->dy = tmp.w;
+ break;
+ }
+ } else {
+ if (yspan > xspan) {
+ box_view->dy = tmp.w;
+ box_view->dx = xspan / yspan * tmp.w;
+ } else {
+ box_view->dx = tmp.w;
+ box_view->dy = yspan / xspan * tmp.w;
+ }
+ if (zm == GOG_AXIS_METRICS_DEFAULT)
+ box_view->dz = tmp.h;
+ else
+ box_view->dz = (ref == axisX)?
+ zspan / xspan * box_view->dx:
+ zspan / yspan * box_view->dy;
+ }
}
/* now compute the position of each vertex, ignoring the fov */
diff --git a/goffice/utils/go-unit.c b/goffice/utils/go-unit.c
new file mode 100644
index 0000000..51a01c4
--- /dev/null
+++ b/goffice/utils/go-unit.c
@@ -0,0 +1,138 @@
+/*
+ * go-unit.c - Units support
+ *
+ * Copyright (C) 2014 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include <goffice/utils/go-unit.h>
+#include <string.h>
+
+static GHashTable *units_hash = NULL;
+static GPtrArray *custom_units;
+
+struct _GoUnit {
+ char *symbol;
+ char *dim;
+ double factor_to_SI; /* how many SI units is this one: 0.0254 for inch */
+ unsigned Id;
+};
+
+static unsigned last_unit = GO_UNIT_MAX;
+
+GoUnit units[GO_UNIT_MAX] = {
+ {(char *) "m", (char *) "L", 1., GO_UNIT_METER},
+ {(char *) "cm", (char *) "L", 0.01, GO_UNIT_CENTIMETER},
+ {(char *) "in", (char *) "L", 0.0254, GO_UNIT_INCH},
+ {(char *) "pt", (char *) "L", 0.0254/72, GO_UNIT_POINT}
+};
+
+char const *
+go_unit_get_symbol (GoUnit const *unit)
+{
+ g_return_val_if_fail (unit != NULL, NULL);
+ return unit->symbol;
+}
+
+GoUnitId
+go_unit_get_id (GoUnit const *unit)
+{
+ g_return_val_if_fail (unit != NULL, GO_UNIT_UNKNOWN);
+ return unit->Id;
+}
+
+double
+go_unit_convert (GoUnit const *from, GoUnit const *to, double value)
+{
+ g_return_val_if_fail (from != NULL && to != NULL, go_nan);
+ if (strcmp (from->dim, to->dim))
+ return go_nan;
+ return value * from->factor_to_SI / to->factor_to_SI;
+}
+
+GoUnit const *go_unit_get_from_symbol (char const *symbol)
+{
+ if (units_hash == NULL)
+ _go_unit_init ();
+ return (GoUnit const *) g_hash_table_lookup (units_hash, symbol);
+}
+
+GoUnit const *
+go_unit_get (GoUnitId Id)
+{
+ if (Id < 0)
+ return NULL;
+ if (Id < GO_UNIT_MAX)
+ return units + Id;
+ else if (custom_units != NULL && Id < last_unit)
+ return g_ptr_array_index (custom_units, Id - GO_UNIT_MAX);
+ return NULL;
+}
+
+GoUnit const *
+go_unit_define (char const *symbol, char const *dim, double factor_to_SI)
+{
+ GoUnit *unit;
+ if (units_hash == NULL)
+ _go_unit_init ();
+ unit = (GoUnit *) go_unit_get_from_symbol (symbol);
+ if (unit == NULL) {
+ unit = (GoUnit *) g_new (GoUnit, 1);
+ unit->symbol = g_strdup (symbol);
+ unit->dim = g_strdup (dim);
+ unit->factor_to_SI = factor_to_SI;
+ unit->Id = last_unit++;
+ g_hash_table_replace (units_hash, unit->symbol, unit);
+ if (custom_units == NULL)
+ custom_units = g_ptr_array_new ();
+ g_ptr_array_add (custom_units, unit);
+ }
+ return unit;
+}
+
+static void
+go_unit_destroy (GoUnit *unit)
+{
+ if (unit != NULL && unit->Id >= GO_UNIT_MAX) {
+ g_free (unit->symbol);
+ g_free (unit->dim);
+ g_free (unit);
+ }
+}
+
+void
+_go_unit_init ()
+{
+ GoUnitId Id;
+ if (units_hash != NULL)
+ return;
+ g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) go_unit_destroy);
+ for (Id = GO_UNIT_METER; Id < GO_UNIT_MAX; Id++)
+ g_hash_table_insert (units_hash, units[Id].symbol, units + Id);
+}
+
+void _go_unit_shutdown ()
+{
+ if (units_hash == NULL)
+ return;
+ g_hash_table_destroy (units_hash);
+ units_hash = NULL;
+ if (custom_units != NULL) {
+ g_ptr_array_unref (custom_units);
+ custom_units = NULL;
+ }
+}
diff --git a/goffice/utils/go-unit.h b/goffice/utils/go-unit.h
new file mode 100644
index 0000000..5253528
--- /dev/null
+++ b/goffice/utils/go-unit.h
@@ -0,0 +1,53 @@
+/*
+ * go-unit.h - Units support
+ *
+ * Copyright (C) 2014 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GO_UNIT_H
+#define GO_UNIT_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GoUnit GoUnit;
+
+typedef enum {
+ GO_UNIT_UNKNOWN = -1,
+ GO_UNIT_METER,
+ GO_UNIT_CENTIMETER,
+ GO_UNIT_INCH,
+ GO_UNIT_POINT,
+ GO_UNIT_MAX
+} GoUnitId;
+
+char const *go_unit_get_symbol (GoUnit const *unit);
+GoUnitId go_unit_get_id (GoUnit const *unit);
+double go_unit_convert (GoUnit const *from, GoUnit const *to, double value);
+GoUnit const *go_unit_get_from_symbol (char const *symbol);
+GoUnit const *go_unit_get (GoUnitId Id);
+GoUnit const *go_unit_define (char const *symbol, char const *dim, double factor_to_SI);
+
+/* private */
+void _go_unit_init (void);
+void _go_unit_shutdown (void);
+
+G_END_DECLS
+
+#endif /* GO_UNIT_H */
diff --git a/goffice/utils/goffice-utils.h b/goffice/utils/goffice-utils.h
index 6dd60f6..2e5a4e9 100644
--- a/goffice/utils/goffice-utils.h
+++ b/goffice/utils/goffice-utils.h
@@ -173,6 +173,7 @@ G_END_DECLS
#include <goffice/utils/go-styled-object.h>
#include <goffice/utils/go-style.h>
#include <goffice/utils/go-undo.h>
+#include <goffice/utils/go-unit.h>
#include <goffice/utils/go-units.h>
#include <goffice/utils/regutf8.h>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]