[goffice] Implement custom grids in xyz plots. [#624273]



commit a2c9cde8524ea3b1c7e471d7c8a1526e1fa4ab16
Author: Jean Brefort <jean brefort normalesup org>
Date:   Thu Sep 23 16:52:22 2010 +0200

    Implement custom grids in xyz plots. [#624273]

 ChangeLog                                     |   11 +
 NEWS                                          |    3 +
 plugins/plot_surface/gog-contour.c            |    2 +-
 plugins/plot_surface/gog-contour.h            |    2 +-
 plugins/plot_surface/gog-xyz-surface-prefs.c  |   92 ++++++++-
 plugins/plot_surface/gog-xyz-surface-prefs.ui |  194 ++++++++++++++++--
 plugins/plot_surface/gog-xyz-surface.c        |  273 ++++++++++++++++++++-----
 plugins/plot_surface/gog-xyz-surface.h        |   11 +-
 plugins/plot_surface/gog-xyz.h                |    1 +
 9 files changed, 502 insertions(+), 87 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index a4d108f..75d487d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2010-09-23  Jean Brefort  <jean brefort normalesup org>
+
+	* plugins/plot_surface/gog-contour.c: implement
+	custom grids in xyz plots. [#624273]
+	* plugins/plot_surface/gog-contour.h: ditto.
+	* plugins/plot_surface/gog-xyz-surface-prefs.c: ditto.
+	* plugins/plot_surface/gog-xyz-surface-prefs.ui: ditto.
+	* plugins/plot_surface/gog-xyz-surface.c: ditto.
+	* plugins/plot_surface/gog-xyz-surface.h: ditto.
+	* plugins/plot_surface/gog-xyz.h: ditto.
+
 2010-09-20  Jon Nordby <jonn openismus com>
 
 	* docs/reference/goffice-docs.sgml: update API documentation.
diff --git a/NEWS b/NEWS
index ccfbf16..5c5e661 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,8 @@
 goffice 0.8.11:
 
+Jean:
+	* Implement custom grids in xyz plots. [#624273]
+	
 Jon Nordby:
 	* Update API documentation.
 
diff --git a/plugins/plot_surface/gog-contour.c b/plugins/plot_surface/gog-contour.c
index 71d260e..7f9ba57 100644
--- a/plugins/plot_surface/gog-contour.c
+++ b/plugins/plot_surface/gog-contour.c
@@ -288,7 +288,7 @@ gog_contour_view_render (GogView *view, GogViewAllocation const *bbox)
 		imax = plot->rows;
 		jmax = plot->columns;
 	}
-	if (imax ==0 || jmax == 0)
+	if (imax == 0 || jmax == 0)
 		return;
 
 	if (plot->plotted_data)
diff --git a/plugins/plot_surface/gog-contour.h b/plugins/plot_surface/gog-contour.h
index 82c80e5..01d0116 100644
--- a/plugins/plot_surface/gog-contour.h
+++ b/plugins/plot_surface/gog-contour.h
@@ -38,7 +38,7 @@ typedef GogXYZPlotClass GogContourPlotClass;
 
 #define GOG_TYPE_CONTOUR_PLOT	(gog_contour_plot_get_type ())
 #define GOG_CONTOUR_PLOT(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOG_TYPE_CONTOUR_PLOT, GogContourPlot))
-#define GOG_IS_PLOT_CONTOUR(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOG_TYPE_CONTOUR_PLOT))
+#define GOG_IS_CONTOUR_PLOT(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOG_TYPE_CONTOUR_PLOT))
 
 GType gog_contour_plot_get_type (void);
 void  gog_contour_plot_register_type   (GTypeModule *module);
diff --git a/plugins/plot_surface/gog-xyz-surface-prefs.c b/plugins/plot_surface/gog-xyz-surface-prefs.c
index c6eb5eb..1ecf9df 100644
--- a/plugins/plot_surface/gog-xyz-surface-prefs.c
+++ b/plugins/plot_surface/gog-xyz-surface-prefs.c
@@ -27,7 +27,12 @@
 
 #include <string.h>
 
-GtkWidget *gog_xyz_surface_plot_pref   (GogXYZSurfacePlot *plot, GOCmdContext *cc);
+GtkWidget *gog_xyz_surface_plot_pref   (GogXYZPlot *plot, GogDataAllocator *dalloc, GOCmdContext *cc);
+
+typedef struct {
+	GogXYZPlot *plot;
+	GtkWidget *x_spin, *y_spin, *x_label, *y_label, *x_entry, *y_entry;
+} XYZSurfPrefsState;
 
 static void
 cb_rows_changed (GtkAdjustment *adj, GObject *plot)
@@ -41,33 +46,100 @@ cb_columns_changed (GtkAdjustment *adj, GObject *plot)
 	g_object_set (plot, "columns", (int) gtk_adjustment_get_value (adj), NULL);
 }
 
+static void
+cb_cols_toggled (GtkToggleButton *btn, XYZSurfPrefsState *state)
+{
+	if (gtk_toggle_button_get_active (btn)) {
+		gtk_widget_show (state->x_spin);
+		gtk_widget_show (state->x_label);
+		gtk_widget_hide (state->x_entry);
+		g_object_set (state->plot, "auto-columns", TRUE, NULL);
+	} else {
+		gtk_widget_hide (state->x_spin);
+		gtk_widget_hide (state->x_label);
+		gtk_widget_show (state->x_entry);
+		g_object_set (state->plot, "auto-columns", FALSE, NULL);
+	}
+}
+
+static void
+cb_rows_toggled (GtkToggleButton *btn, XYZSurfPrefsState *state)
+{
+	if (gtk_toggle_button_get_active (btn)) {
+		gtk_widget_show (state->y_spin);
+		gtk_widget_show (state->y_label);
+		gtk_widget_hide (state->y_entry);
+		g_object_set (state->plot, "auto-rows", TRUE, NULL);
+	} else {
+		gtk_widget_hide (state->y_spin);
+		gtk_widget_hide (state->y_label);
+		gtk_widget_show (state->y_entry);
+		g_object_set (state->plot, "auto-rows", FALSE, NULL);
+	}
+}
+
 GtkWidget *
-gog_xyz_surface_plot_pref (GogXYZSurfacePlot *plot, GOCmdContext *cc)
+gog_xyz_surface_plot_pref (GogXYZPlot *plot, GogDataAllocator *dalloc, GOCmdContext *cc)
 {
-	GogXYZPlot *xyz = GOG_XYZ_PLOT (plot);
-	GtkWidget  *w;
+	XYZSurfPrefsState *state;
+	GtkWidget  *w, *box;
 	char const *dir = go_plugin_get_dir_name (
 		go_plugins_get_plugin_by_id ("GOffice_plot_surface"));
 	char	 *path = g_build_filename (dir, "gog-xyz-surface-prefs.ui", NULL);
 	GtkBuilder *gui = go_gtk_builder_new (path, GETTEXT_PACKAGE, cc);
+	GogDataset *set = GOG_DATASET (plot);
 
 	g_free (path);
         if (gui == NULL)
                 return NULL;
 
-	w = go_gtk_builder_get_widget (gui, "rows_spinner");
-	gtk_spin_button_set_value (GTK_SPIN_BUTTON (w), xyz->rows);
+	state = g_new (XYZSurfPrefsState, 1);
+	state->plot = plot;
+
+	state->x_spin = w = go_gtk_builder_get_widget (gui, "columns_spinner");
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (w), plot->columns);
 	g_signal_connect (G_OBJECT (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (w))),
 		"value_changed",
-		G_CALLBACK (cb_rows_changed), plot);
+		G_CALLBACK (cb_columns_changed), plot);
+	state->x_label = go_gtk_builder_get_widget (gui, "cols-nb-lbl");
 
-	w = go_gtk_builder_get_widget (gui, "columns_spinner");
-	gtk_spin_button_set_value (GTK_SPIN_BUTTON (w), xyz->columns);
+	box = go_gtk_builder_get_widget (gui, "cols-box");
+	state->x_entry = GTK_WIDGET (gog_data_allocator_editor (dalloc, set, 0, GOG_DATA_VECTOR));
+	gtk_widget_show_all (state->x_entry);
+	gtk_box_pack_start (GTK_BOX (box), state->x_entry, TRUE, TRUE, 0);
+	w = go_gtk_builder_get_widget (gui, "preset-cols-btn");
+	if (!state->plot->auto_x) {
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), TRUE);
+		gtk_widget_hide (state->x_spin);
+		gtk_widget_hide (state->x_label);
+	} else
+		gtk_widget_hide (state->x_entry);
+	w = go_gtk_builder_get_widget (gui, "calc-cols-btn");
+	g_signal_connect (G_OBJECT (w), "toggled", G_CALLBACK (cb_cols_toggled), state);
+		
+	state->y_spin = w = go_gtk_builder_get_widget (gui, "rows_spinner");
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (w), plot->rows);
 	g_signal_connect (G_OBJECT (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (w))),
 		"value_changed",
-		G_CALLBACK (cb_columns_changed), plot);
+		G_CALLBACK (cb_rows_changed), plot);
+	state->y_label = go_gtk_builder_get_widget (gui, "rows-nb-lbl");
+
+	box = go_gtk_builder_get_widget (gui, "rows-box");
+	state->y_entry = GTK_WIDGET (gog_data_allocator_editor (dalloc, set, 1, GOG_DATA_VECTOR));
+	gtk_widget_show_all (state->y_entry);
+	gtk_box_pack_start (GTK_BOX (box), state->y_entry, TRUE, TRUE, 0);
+	w = go_gtk_builder_get_widget (gui, "preset-rows-btn");
+	if (!state->plot->auto_y) {
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), TRUE);
+		gtk_widget_hide (state->y_spin);
+		gtk_widget_hide (state->y_label);
+	} else
+		gtk_widget_hide (state->y_entry);
+	w = go_gtk_builder_get_widget (gui, "calc-rows-btn");
+	g_signal_connect (G_OBJECT (w), "toggled", G_CALLBACK (cb_rows_toggled), state);
 
 	w = GTK_WIDGET (g_object_ref (gtk_builder_get_object (gui, "gog_xyz_surface_prefs")));
+	g_object_set_data_full (G_OBJECT (w), "state", state, g_free);
 	g_object_unref (gui);
 
 	return w;
diff --git a/plugins/plot_surface/gog-xyz-surface-prefs.ui b/plugins/plot_surface/gog-xyz-surface-prefs.ui
index 8b8dda5..e1d01f1 100644
--- a/plugins/plot_surface/gog-xyz-surface-prefs.ui
+++ b/plugins/plot_surface/gog-xyz-surface-prefs.ui
@@ -1,5 +1,6 @@
 <?xml version="1.0"?>
 <interface>
+  <!-- interface-requires gtk+ 2.12 -->
   <!-- interface-naming-policy toplevel-contextual -->
   <object class="GtkAdjustment" id="adjustment1">
     <property name="value">10</property>
@@ -18,65 +19,103 @@
   <object class="GtkTable" id="gog_xyz_surface_prefs">
     <property name="visible">True</property>
     <property name="border_width">12</property>
-    <property name="n_rows">2</property>
-    <property name="n_columns">2</property>
+    <property name="n_rows">6</property>
+    <property name="n_columns">3</property>
     <property name="column_spacing">12</property>
     <property name="row_spacing">6</property>
     <child>
-      <object class="GtkLabel" id="label61">
+      <object class="GtkLabel" id="rows_lbl">
         <property name="visible">True</property>
         <property name="xalign">0</property>
         <property name="yalign">0</property>
-        <property name="label" translatable="yes">_Rows:</property>
+        <property name="label" translatable="yes">&lt;b&gt;_Rows:&lt;/b&gt;</property>
+        <property name="use_markup">True</property>
         <property name="use_underline">True</property>
-        <property name="mnemonic_widget">rows_spinner</property>
       </object>
       <packing>
+        <property name="top_attach">3</property>
+        <property name="bottom_attach">4</property>
         <property name="x_options">GTK_FILL</property>
         <property name="y_options"></property>
       </packing>
     </child>
     <child>
-      <object class="GtkLabel" id="label64">
+      <object class="GtkLabel" id="cols_lbl">
         <property name="visible">True</property>
         <property name="xalign">0</property>
-        <property name="label" translatable="yes">_Columns:</property>
+        <property name="yalign">0.46000000834465027</property>
+        <property name="label" translatable="yes">&lt;b&gt;_Columns:&lt;/b&gt;</property>
+        <property name="use_markup">True</property>
         <property name="use_underline">True</property>
-        <property name="mnemonic_widget">columns_spinner</property>
       </object>
       <packing>
-        <property name="top_attach">1</property>
-        <property name="bottom_attach">2</property>
         <property name="x_options">GTK_FILL</property>
         <property name="y_options"></property>
       </packing>
     </child>
     <child>
-      <object class="GtkSpinButton" id="rows_spinner">
+      <object class="GtkRadioButton" id="calc-rows-btn">
+        <property name="label" translatable="yes">Calculated</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
+        <property name="active">True</property>
+        <property name="draw_indicator">True</property>
+      </object>
+      <packing>
+        <property name="top_attach">4</property>
+        <property name="bottom_attach">5</property>
+        <property name="x_options">GTK_FILL</property>
+        <property name="y_options"></property>
+        <property name="x_padding">12</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkRadioButton" id="preset-rows-btn">
+        <property name="label" translatable="yes">Preset:</property>
         <property name="visible">True</property>
         <property name="can_focus">True</property>
-        <property name="invisible_char">&#x2022;</property>
-        <property name="adjustment">adjustment1</property>
-        <property name="climb_rate">10</property>
-        <property name="snap_to_ticks">True</property>
-        <property name="numeric">True</property>
+        <property name="receives_default">False</property>
+        <property name="active">True</property>
+        <property name="draw_indicator">True</property>
+        <property name="group">calc-rows-btn</property>
       </object>
       <packing>
         <property name="left_attach">1</property>
         <property name="right_attach">2</property>
+        <property name="top_attach">4</property>
+        <property name="bottom_attach">5</property>
+        <property name="x_options">GTK_FILL</property>
+        <property name="y_options"></property>
+        <property name="x_padding">12</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkRadioButton" id="calc-cols-btn">
+        <property name="label" translatable="yes">Calculated</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
+        <property name="active">True</property>
+        <property name="draw_indicator">True</property>
+      </object>
+      <packing>
+        <property name="top_attach">1</property>
+        <property name="bottom_attach">2</property>
         <property name="x_options">GTK_FILL</property>
         <property name="y_options"></property>
+        <property name="x_padding">12</property>
       </packing>
     </child>
     <child>
-      <object class="GtkSpinButton" id="columns_spinner">
+      <object class="GtkRadioButton" id="preset-cols-btn">
+        <property name="label" translatable="yes">Preset:</property>
         <property name="visible">True</property>
         <property name="can_focus">True</property>
-        <property name="invisible_char">&#x2022;</property>
-        <property name="adjustment">adjustment2</property>
-        <property name="climb_rate">0.10000000000000001</property>
-        <property name="snap_to_ticks">True</property>
-        <property name="numeric">True</property>
+        <property name="receives_default">False</property>
+        <property name="active">True</property>
+        <property name="draw_indicator">True</property>
+        <property name="group">calc-cols-btn</property>
       </object>
       <packing>
         <property name="left_attach">1</property>
@@ -85,7 +124,118 @@
         <property name="bottom_attach">2</property>
         <property name="x_options">GTK_FILL</property>
         <property name="y_options"></property>
+        <property name="x_padding">12</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkHBox" id="rows-box">
+        <property name="visible">True</property>
+        <child>
+          <object class="GtkLabel" id="rows-nb-lbl">
+            <property name="visible">True</property>
+            <property name="label" translatable="yes">Count:</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkSpinButton" id="rows_spinner">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="invisible_char">&#x25CF;</property>
+            <property name="adjustment">adjustment1</property>
+            <property name="climb_rate">10</property>
+            <property name="snap_to_ticks">True</property>
+            <property name="numeric">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="padding">12</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="right_attach">3</property>
+        <property name="top_attach">5</property>
+        <property name="bottom_attach">6</property>
+        <property name="y_options"></property>
+        <property name="x_padding">12</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkHBox" id="cols-box">
+        <property name="visible">True</property>
+        <child>
+          <object class="GtkLabel" id="cols-nb-lbl">
+            <property name="visible">True</property>
+            <property name="label" translatable="yes">Count:</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkSpinButton" id="columns_spinner">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="invisible_char">&#x25CF;</property>
+            <property name="adjustment">adjustment2</property>
+            <property name="climb_rate">0.10000000000000001</property>
+            <property name="snap_to_ticks">True</property>
+            <property name="numeric">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="padding">12</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="right_attach">3</property>
+        <property name="top_attach">2</property>
+        <property name="bottom_attach">3</property>
+        <property name="x_options">GTK_FILL</property>
+        <property name="y_options"></property>
+        <property name="x_padding">12</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="label1">
+        <property name="visible">True</property>
+        <property name="xalign">0.46000000834465027</property>
+        <property name="label" translatable="yes">
+</property>
+      </object>
+      <packing>
+        <property name="left_attach">2</property>
+        <property name="right_attach">3</property>
+        <property name="top_attach">1</property>
+        <property name="bottom_attach">2</property>
+        <property name="y_options"></property>
       </packing>
     </child>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
   </object>
 </interface>
diff --git a/plugins/plot_surface/gog-xyz-surface.c b/plugins/plot_surface/gog-xyz-surface.c
index 4975cbb..f904735 100644
--- a/plugins/plot_surface/gog-xyz-surface.c
+++ b/plugins/plot_surface/gog-xyz-surface.c
@@ -38,7 +38,9 @@
 enum {
 	XYZ_SURFACE_PROP_0,
 	XYZ_SURFACE_PROP_ROWS,
-	XYZ_SURFACE_PROP_COLUMNS
+	XYZ_SURFACE_PROP_COLUMNS,
+	XYZ_SURFACE_PROP_AUTO_ROWS,
+	XYZ_SURFACE_PROP_AUTO_COLUMNS
 };
 
 static GogObjectClass *plot_xyz_contour_parent_klass;
@@ -46,44 +48,112 @@ static GogObjectClass *plot_xyz_surface_parent_klass;
 
 #define EPSILON 1e-13
 
+typedef struct {
+	double const *values[2];
+	unsigned cur_series;
+} xyz_data;
+
+static int
+data_compare (unsigned const *a, unsigned const *b, xyz_data *data)
+{
+	double  xa = data->values[data->cur_series][*a],
+		xb = data->values[data->cur_series][*b];
+	if (xa < xb)
+		return -1;
+	else if (xa == xb)
+		return 0;
+	else
+		return 1;
+}
+
 static double *
 gog_xyz_surface_plot_build_matrix (GogXYZPlot const *plot, gboolean *cardinality_changed)
 {
-	unsigned i, j, k, index;
+	unsigned i, j, k, l, index;
 	GogSeries *series = GOG_SERIES (plot->base.series->data);
 	const double *x_vals, *y_vals, *z_vals = NULL;
+	double *x_limits, *y_limits;
 	double *data;
-	unsigned *grid;
-	unsigned n = plot->rows * plot->columns;
-	unsigned kmax = gog_series_get_xyz_data (GOG_SERIES (series),
+	unsigned *grid, n, kmax, imax, jmax;
+	double xmin, ymin, xinc, yinc;
+	xyz_data raw_data;
+	unsigned *sort;
+	if (GOG_IS_CONTOUR_PLOT (plot)) {
+		GogXYZContourPlot *xyz = GOG_XYZ_CONTOUR_PLOT (plot);
+		if (xyz->grid[0].data) {
+			xyz->base.x_vals = g_object_ref (xyz->grid[0].data);
+			xyz->base.columns = go_data_get_vector_size (plot->x_vals);
+		}
+		if (xyz->grid[1].data) {
+			xyz->base.y_vals = g_object_ref (xyz->grid[1].data);
+			xyz->base.rows = go_data_get_vector_size (plot->y_vals);
+		}
+	} else {
+		GogXYZSurfacePlot *xyz = GOG_XYZ_SURFACE_PLOT (plot);
+		if (xyz->grid[0].data) {
+			xyz->base.x_vals = g_object_ref (xyz->grid[0].data);
+			xyz->base.columns = go_data_get_vector_size (plot->x_vals);
+		}
+		if (xyz->grid[1].data) {
+			xyz->base.y_vals = g_object_ref (xyz->grid[1].data);
+			xyz->base.rows = go_data_get_vector_size (plot->y_vals);
+		}
+	}
+	n = plot->rows * plot->columns;
+	if (n == 0)
+		return NULL;
+	x_limits = go_range_sort (go_data_get_values (gog_xyz_plot_get_x_vals ((GogXYZPlot *) plot)), plot->columns);
+	for (i = 0; i < plot->columns - 1; i++)
+		x_limits[i] = (x_limits[i] + x_limits[i+1]) / 2.;
+	x_limits[i] = G_MAXDOUBLE;
+	y_limits = go_range_sort (go_data_get_values (gog_xyz_plot_get_y_vals ((GogXYZPlot *) plot)), plot->rows);
+	for (i = 0; i < plot->rows - 1; i++)
+		y_limits[i] = (y_limits[i] + y_limits[i+1]) / 2.;
+	y_limits[i] = G_MAXDOUBLE;
+	kmax = gog_series_get_xyz_data (GOG_SERIES (series),
 						 &x_vals, &y_vals, &z_vals);
-	unsigned imax = plot->rows;
-	unsigned jmax = plot->columns;
-	double xmin = plot->x.minima;
-	double ymin = plot->y.minima;
-	double xinc = (plot->x.maxima - xmin) / (jmax - 1);
-	double yinc = (plot->y.maxima - ymin) / (imax - 1);
+	/* sort the data by column and row */
+	raw_data.values[0] = x_vals;
+	raw_data.values[1] = y_vals;
+	raw_data.cur_series = 1;
+	sort = g_new0 (unsigned, kmax);
+	for (i = 0; i < kmax; i++)
+		sort[i] = i;
+	g_qsort_with_data (sort, kmax, sizeof (unsigned), (GCompareDataFunc) data_compare, &raw_data);
+	raw_data.cur_series = 0;
+	imax = plot->rows;
+	jmax = plot->columns;
+	xmin = plot->x.minima;
+	ymin = plot->y.minima;
+	xinc = (plot->x.maxima - xmin) / (jmax - 1);
+	yinc = (plot->y.maxima - ymin) / (imax - 1);
 
 	data = g_new0 (double, n);
 	grid = g_new0 (unsigned, n);
 
-	for (k = 0; k < kmax; ++k) {
-		j = (int) floor ((x_vals[k] - xmin) / xinc + 0.5);
-		i = (int) floor ((y_vals[k] - ymin) / yinc + 0.5);
-		index = i * jmax + j;
-		/* Watch out not to fall beyond array limits; however,
-		 * its unlikely and shouldn't happen normally */
-		if (G_LIKELY (index < n)) {
-			data[index] += z_vals[k];
-			grid[index]++;
+	k = l = index = 0;
+	for (i = 0; i < imax; i++) {
+		while (l < kmax && y_vals[sort[l]] < y_limits[i])
+			l++;
+		g_qsort_with_data (sort + k, l - k, sizeof (unsigned), (GCompareDataFunc) data_compare, &raw_data);
+		for (j = 0; j < jmax && k < l; j++) {
+			index = i * jmax + j;
+			while (k < l && x_vals[sort[k]] < x_limits[j]) {
+				if (G_LIKELY (index < n)) {
+					data[index] += z_vals[sort[k]];
+					grid[index]++;
+				}
+				k++;
+			}
 		}
+		k = l;
 	}
 
 	for (k = 0; k < n; ++k)
 		if (grid[k] != 0)
 			data[k] /= grid[k];
 
-	if (GOG_IS_PLOT_CONTOUR (plot)) {
+	if (GOG_IS_CONTOUR_PLOT (plot)) {
 		GogAxisMap *map;
 		GogAxisTick *zticks;
 		GogAxis *axis = plot->base.axis[GOG_AXIS_PSEUDO_3D];
@@ -91,7 +161,7 @@ gog_xyz_surface_plot_build_matrix (GogXYZPlot const *plot, gboolean *cardinality
 		double *x, val, minimum, maximum, slope, offset = 0.;
 		unsigned max;
 
-	if (!gog_axis_get_bounds (axis, &minimum, &maximum)) {
+		if (!gog_axis_get_bounds (axis, &minimum, &maximum)) {
 			g_free (grid);
 			g_free (data);
 			return NULL;
@@ -145,6 +215,9 @@ gog_xyz_surface_plot_build_matrix (GogXYZPlot const *plot, gboolean *cardinality
 		}
 	} else
 		*cardinality_changed = FALSE;
+	g_free (x_limits);
+	g_free (y_limits);
+	g_free (sort);
 	g_free (grid);
 	return data;
 }
@@ -166,17 +239,17 @@ gog_xyz_surface_plot_type_name (G_GNUC_UNUSED GogObject const *item)
 }
 
 #ifdef GOFFICE_WITH_GTK
-extern gpointer gog_xyz_surface_plot_pref (GogXYZPlot *plot, GOCmdContext *cc);
+extern gpointer gog_xyz_surface_plot_pref (GogXYZPlot *plot, GogDataAllocator *dalloc, GOCmdContext *cc);
 static void
 gog_xyz_surface_plot_populate_editor (GogObject *item,
 				  GOEditor *editor,
-				  G_GNUC_UNUSED GogDataAllocator *dalloc,
+				  GogDataAllocator *dalloc,
 				  GOCmdContext *cc)
 {
-	GogObjectClass *klass = (GOG_IS_PLOT_CONTOUR (item))?
+	GogObjectClass *klass = (GOG_IS_CONTOUR_PLOT (item))?
 				plot_xyz_contour_parent_klass:
 				plot_xyz_surface_parent_klass;
-	GtkWidget *w = gog_xyz_surface_plot_pref (GOG_XYZ_PLOT (item), cc);
+	GtkWidget *w = gog_xyz_surface_plot_pref (GOG_XYZ_PLOT (item), dalloc, cc);
 	go_editor_add_page (editor, w, _("Properties"));
 	g_object_unref (G_OBJECT (w));
 
@@ -190,10 +263,9 @@ gog_xyz_surface_plot_update (GogObject *obj)
 	GogXYZPlot *model = GOG_XYZ_PLOT(obj);
 	GogXYZSeries *series;
 	double tmp_min, tmp_max;
-	GogObjectClass *klass = (GOG_IS_PLOT_CONTOUR (obj))?
+	GogObjectClass *klass = (GOG_IS_CONTOUR_PLOT (obj))?
 				plot_xyz_contour_parent_klass:
 				plot_xyz_surface_parent_klass;
-
 	if (model->base.series == NULL)
 		return;
 
@@ -243,7 +315,7 @@ gog_xyz_surface_plot_update (GogObject *obj)
 	model->z.date_conv = go_data_date_conv (series->base.values[2].data);
 	model->z.minima = tmp_min;
 	model->z.maxima = tmp_max;
-	gog_axis_bound_changed (model->base.axis[((GOG_IS_PLOT_CONTOUR (model))? GOG_AXIS_PSEUDO_3D: GOG_AXIS_Z)], GOG_OBJECT (model));
+	gog_axis_bound_changed (model->base.axis[((GOG_IS_CONTOUR_PLOT (model))? GOG_AXIS_PSEUDO_3D: GOG_AXIS_Z)], GOG_OBJECT (model));
 
 	gog_object_emit_changed (GOG_OBJECT (obj), FALSE);
 	if (klass->update)
@@ -258,25 +330,47 @@ gog_xyz_surface_plot_set_property (GObject *obj, guint param_id,
 
 	switch (param_id) {
 	case XYZ_SURFACE_PROP_ROWS :
-		if (plot->rows != g_value_get_uint (value)) {
-			plot->rows = g_value_get_uint (value);
-			g_free (plot->plotted_data);
-			plot->plotted_data = NULL;
-			if (plot->y_vals != NULL) {
-				g_object_unref (plot->y_vals);
-				plot->y_vals = NULL;
-			}
+		if (plot->rows == g_value_get_uint (value))
+			return;
+		plot->rows = g_value_get_uint (value);
+		g_free (plot->plotted_data);
+		plot->plotted_data = NULL;
+		if (plot->y_vals != NULL) {
+			g_object_unref (plot->y_vals);
+			plot->y_vals = NULL;
 		}
 		break;
 	case XYZ_SURFACE_PROP_COLUMNS :
-		if (plot->columns != g_value_get_uint (value)) {
-			plot->columns = g_value_get_uint (value);
-			g_free (plot->plotted_data);
-			plot->plotted_data = NULL;
-			if (plot->x_vals != NULL) {
-				g_object_unref (plot->x_vals);
-				plot->x_vals = NULL;
-			}
+		if (plot->columns == g_value_get_uint (value))
+			return;
+		plot->columns = g_value_get_uint (value);
+		g_free (plot->plotted_data);
+		plot->plotted_data = NULL;
+		if (plot->x_vals != NULL) {
+			g_object_unref (plot->x_vals);
+			plot->x_vals = NULL;
+		}
+		break;
+	case XYZ_SURFACE_PROP_AUTO_ROWS :
+		if (plot->auto_y == g_value_get_boolean (value))
+			return;
+		plot->auto_y = g_value_get_boolean (value);
+		g_free (plot->plotted_data);
+		plot->plotted_data = NULL;
+		if (plot->y_vals != NULL) {
+			g_object_unref (plot->y_vals);
+			plot->y_vals = NULL;
+		}
+		break;
+	case XYZ_SURFACE_PROP_AUTO_COLUMNS :
+		if (plot->auto_x == g_value_get_boolean (value))
+			return;
+		plot->auto_x = g_value_get_boolean (value);
+		g_free (plot->plotted_data);
+		plot->plotted_data = NULL;
+		if (plot->x_vals != NULL) {
+			g_object_unref (plot->x_vals);
+			plot->x_vals = NULL;
 		}
 		break;
 
@@ -299,6 +393,12 @@ gog_xyz_surface_plot_get_property (GObject *obj, guint param_id,
 	case XYZ_SURFACE_PROP_COLUMNS :
 		g_value_set_uint (value, plot->columns);
 		break;
+	case XYZ_SURFACE_PROP_AUTO_ROWS :
+		g_value_set_boolean (value, plot->auto_y);
+		break;
+	case XYZ_SURFACE_PROP_AUTO_COLUMNS :
+		g_value_set_boolean (value, plot->auto_x);
+		break;
 
 	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
 		 break;
@@ -306,6 +406,14 @@ gog_xyz_surface_plot_get_property (GObject *obj, guint param_id,
 }
 
 static void
+gog_xyz_surface_finalize (GObject *obj)
+{
+	GObjectClass *klass = g_type_class_peek_parent (G_OBJECT_GET_CLASS (obj));
+	gog_dataset_finalize (GOG_DATASET (obj));
+	klass->finalize (obj);
+}
+
+static void
 common_init_class (GogXYZPlotClass *klass)
 {
 	GogPlotClass *gog_plot_klass = (GogPlotClass*) klass;
@@ -314,18 +422,31 @@ common_init_class (GogXYZPlotClass *klass)
 
 	gobject_klass->set_property = gog_xyz_surface_plot_set_property;
 	gobject_klass->get_property = gog_xyz_surface_plot_get_property;
+	gobject_klass->finalize = gog_xyz_surface_finalize;
 	g_object_class_install_property (gobject_klass, XYZ_SURFACE_PROP_ROWS,
 		g_param_spec_uint ("rows",
 			_("Rows"),
 			_("Number of rows"),
 			2, 1000, 10,
 			GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
+	g_object_class_install_property (gobject_klass, XYZ_SURFACE_PROP_AUTO_ROWS,
+		g_param_spec_boolean ("auto-rows",
+			_("Auto Rows"),
+			_("Whether the rows limts should be evaluated"),
+			TRUE,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
 	g_object_class_install_property (gobject_klass, XYZ_SURFACE_PROP_COLUMNS,
 		g_param_spec_uint ("columns",
 			_("Columns"),
 			_("Number of columns"),
 			2, 1000, 10,
 			GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
+	g_object_class_install_property (gobject_klass, XYZ_SURFACE_PROP_AUTO_COLUMNS,
+		g_param_spec_boolean ("auto-columns",
+			_("Auto Columns"),
+			_("Whether the columns limts should be evaluated"),
+			TRUE,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
 
 	gog_object_klass->update	= gog_xyz_surface_plot_update;
 
@@ -371,12 +492,62 @@ gog_xyz_surface_plot_init (GogXYZPlot *xyz)
 	xyz->data_xyz = TRUE;
 	xyz->rows = 10;
 	xyz->columns = 10;
+	xyz->auto_x = xyz->auto_y = TRUE;
+}
+
+static void
+gog_xyz_surface_plot_dataset_dims (GogDataset const *set, int *first, int *last)
+{
+	*first = 0;
+	*last = 1;
+}
+
+static GogDatasetElement *
+gog_xyz_contour_plot_dataset_get_elem (GogDataset const *set, int dim_i)
+{
+	GogXYZContourPlot *plot = GOG_XYZ_CONTOUR_PLOT (set);
+	g_return_val_if_fail (2 > dim_i, NULL);
+	g_return_val_if_fail (dim_i >= 0, NULL);
+	return plot->grid + dim_i;
+}
+
+static GogDatasetElement *
+gog_xyz_surface_plot_dataset_get_elem (GogDataset const *set, int dim_i)
+{
+	GogXYZSurfacePlot *plot = GOG_XYZ_SURFACE_PLOT (set);
+	g_return_val_if_fail (2 > dim_i, NULL);
+	g_return_val_if_fail (dim_i >= 0, NULL);
+	return plot->grid + dim_i;
+}
+
+static void
+gog_xyz_surface_plot_dataset_dim_changed (GogDataset *set, int dim_i)
+{
+	gog_object_request_update (GOG_OBJECT (set));
+}
+
+static void
+gog_xyz_contour_plot_dataset_init (GogDatasetClass *iface)
+{
+	iface->get_elem	   = gog_xyz_contour_plot_dataset_get_elem;
+	iface->dims	   = gog_xyz_surface_plot_dataset_dims;
+	iface->dim_changed = gog_xyz_surface_plot_dataset_dim_changed;
+}
+
+static void
+gog_xyz_surface_plot_dataset_init (GogDatasetClass *iface)
+{
+	iface->get_elem	   = gog_xyz_surface_plot_dataset_get_elem;
+	iface->dims	   = gog_xyz_surface_plot_dataset_dims;
+	iface->dim_changed = gog_xyz_surface_plot_dataset_dim_changed;
 }
 
-GSF_DYNAMIC_CLASS (GogXYZContourPlot, gog_xyz_contour_plot,
-	gog_xyz_contour_plot_class_init, gog_xyz_surface_plot_init,
-	GOG_TYPE_CONTOUR_PLOT)
+GSF_DYNAMIC_CLASS_FULL (GogXYZContourPlot, gog_xyz_contour_plot,
+	NULL, NULL, gog_xyz_contour_plot_class_init, NULL,
+        gog_xyz_surface_plot_init, GOG_TYPE_CONTOUR_PLOT, 0,
+        GSF_INTERFACE (gog_xyz_contour_plot_dataset_init, GOG_TYPE_DATASET))
 
-GSF_DYNAMIC_CLASS (GogXYZSurfacePlot, gog_xyz_surface_plot,
-	gog_xyz_surface_plot_class_init, gog_xyz_surface_plot_init,
-	GOG_TYPE_SURFACE_PLOT)
+GSF_DYNAMIC_CLASS_FULL (GogXYZSurfacePlot, gog_xyz_surface_plot,
+	NULL, NULL, gog_xyz_surface_plot_class_init, NULL,
+        gog_xyz_surface_plot_init, GOG_TYPE_SURFACE_PLOT, 0,
+        GSF_INTERFACE (gog_xyz_surface_plot_dataset_init, GOG_TYPE_DATASET))
diff --git a/plugins/plot_surface/gog-xyz-surface.h b/plugins/plot_surface/gog-xyz-surface.h
index 08d9f19..65099d6 100644
--- a/plugins/plot_surface/gog-xyz-surface.h
+++ b/plugins/plot_surface/gog-xyz-surface.h
@@ -34,7 +34,11 @@ G_BEGIN_DECLS
  *-----------------------------------------------------------------------------
  */
 
-typedef GogContourPlot GogXYZContourPlot;
+
+typedef struct {
+	GogContourPlot base;
+	GogDatasetElement grid[2];       /* for preset cols and rows */
+} GogXYZContourPlot;
 typedef GogContourPlotClass GogXYZContourPlotClass;
 
 #define GOG_TYPE_XYZ_CONTOUR_PLOT	(gog_xyz_contour_plot_get_type ())
@@ -52,7 +56,10 @@ void  gog_xyz_contour_plot_register_type   (GTypeModule *module);
  *-----------------------------------------------------------------------------
  */
 
-typedef GogSurfacePlot GogXYZSurfacePlot;
+typedef struct {
+	GogSurfacePlot base;
+	GogDatasetElement grid[2];       /* for preset cols and rows */
+} GogXYZSurfacePlot;
 typedef GogSurfacePlotClass GogXYZSurfacePlotClass;
 
 #define GOG_TYPE_XYZ_SURFACE_PLOT	(gog_xyz_surface_plot_get_type ())
diff --git a/plugins/plot_surface/gog-xyz.h b/plugins/plot_surface/gog-xyz.h
index ad3b09f..f52a2be 100644
--- a/plugins/plot_surface/gog-xyz.h
+++ b/plugins/plot_surface/gog-xyz.h
@@ -39,6 +39,7 @@ typedef struct {
 	unsigned rows, columns;
 	gboolean transposed;
 	gboolean data_xyz;
+	gboolean auto_x, auto_y; /* automatic limits for xyz plots */
 	struct {
 		double minima, maxima;
 		GOFormat *fmt;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]