goffice r2085 - in trunk: . goffice goffice/data goffice/graph goffice/math plugins/plot_surface



Author: jbrefort
Date: Mon May 12 09:02:12 2008
New Revision: 2085
URL: http://svn.gnome.org/viewvc/goffice?rev=2085&view=rev

Log:
2008-05-12  Jean Brefort  <jean brefort normalesup org>

	* goffice/data/go-data.c: (go_data_vector_increasing),
	(go_data_vector_decreasing), (go_data_vector_vary_uniformly):
	new functions.
	* goffice/data/go-data.h: ditto.
	* goffice/goffice.c: (libgoffice_init): add initial 3d plots support.
	* goffice/graph/Makefile.am: ditto.
	* goffice/graph/goffice-graph.h: ditto.
	* goffice/graph/gog-3d-box.c: (gog_3d_box_class_init),
	(gog_3d_box_init): ditto.
	* goffice/graph/gog-3d-box.h: ditto.
	* goffice/graph/gog-axis-line.c: (xyz_process),
	(gog_axis_base_view_point), (gog_axis_base_view_padding_request):
	* goffice/graph/gog-axis.c: (gog_axis_view_size_allocate): ditto.
	* goffice/graph/gog-chart-impl.h: ditto.
	* goffice/graph/gog-chart-map-3d.c: (null_map_3D),
	(xyz_map_3D_to_view), (gog_chart_map_3d_new),
	(gog_chart_map_3d_to_view), (gog_chart_map_3d_is_valid),
	(gog_chart_map_3d_free): ditto.
	* goffice/graph/gog-chart-map-3d.h: ditto.
	* goffice/graph/gog-chart.c: (role_3d_box_can_add),
	(role_3d_box_can_remove), (gog_chart_is_3d),
	(gog_chart_3d_process), (gog_chart_view_size_allocate),
	(gog_chart_view_render): ditto.
	* goffice/graph/gog-chart.h: ditto.
	* goffice/math/Makefile.am: ditto.
	* goffice/math/go-matrix3x3.c: (go_matrix3x3_transform),
	(go_matrix3x3_from_euler): ditto.
	* goffice/math/go-matrix3x3.h: ditto.
	* goffice/math/go-rangefunc.c: (go_range_decreasing),
	(go_range_vary_uniformly): new functions.
	* goffice/math/go-rangefunc.h: ditto.
	* plugins/plot_surface/Makefile.am: new surface plot type.
	* plugins/plot_surface/gog-contour-prefs.c: ditto.
	* plugins/plot_surface/gog-contour-prefs.glade: ditto.
	* plugins/plot_surface/gog-contour.c: ditto.
	(gog_contour_plot_build_matrix), (gog_contour_plot_type_name),
	(gog_contour_plot_foreach_elem), (gog_contour_plot_class_init),
	(gog_contour_plot_init), (gog_contour_view_render),
	(gog_contour_view_class_init): ditto.
	* plugins/plot_surface/gog-contour.h: ditto.
	* plugins/plot_surface/gog-surface.c: ditto.
	(gog_surface_plot_build_matrix), (gog_surface_plot_type_name),
	(gog_surface_plot_class_init), (gog_surface_plot_init),
	(gog_surface_view_render), (gog_surface_view_class_init):
	* plugins/plot_surface/gog-surface.h:
	* plugins/plot_surface/gog-xyz-prefs.c:
	* plugins/plot_surface/gog-xyz-prefs.glade:
	* plugins/plot_surface/gog-xyz.c: (gog_xyz_plot_build_matrix),
	(gog_xyz_plot_update_3d), (gog_xyz_plot_populate_editor),
	(gog_xyz_plot_clear_formats), (gog_xyz_plot_update),
	(gog_xyz_plot_axis_get_bounds), (gog_xyz_plot_finalize),
	(gog_xyz_plot_set_property), (gog_xyz_plot_get_property),
	(gog_xyz_plot_class_init), (gog_xyz_plot_init),
	(gog_xyz_series_update), (gog_xyz_series_init_style),
	(gog_xyz_series_class_init), (go_plugin_init),
	(go_plugin_shutdown): ditto.
	* plugins/plot_surface/gog-xyz.h: ditto.
	* plugins/plot_surface/plot-types.xml.in: ditto.
	* plugins/plot_surface/plugin.xml.in: ditto.
	* plugins/plot_surface/xl-surface.c: (xl_labels_init),
	(xl_xyz_series_update), (xl_xyz_series_init_style),
	(xl_xyz_series_class_init), (xl_xyz_plot_update), (get_y_vector),
	(xl_xyz_plot_axis_get_bounds), (xl_contour_plot_build_matrix),
	(xl_contour_plot_finalize), (xl_contour_plot_class_init),
	(xl_surface_plot_build_matrix), (xl_surface_plot_finalize),
	(xl_surface_plot_class_init): ditto.
	* plugins/plot_surface/xl-surface.h: ditto.



Added:
   trunk/goffice/graph/gog-3d-box.c
   trunk/goffice/graph/gog-3d-box.h
   trunk/goffice/graph/gog-chart-map-3d.c
   trunk/goffice/graph/gog-chart-map-3d.h
   trunk/goffice/math/go-matrix3x3.c
   trunk/goffice/math/go-matrix3x3.h
   trunk/plugins/plot_surface/gog-contour.c
   trunk/plugins/plot_surface/gog-contour.h
   trunk/plugins/plot_surface/gog-xyz-prefs.c
      - copied, changed from r2048, /trunk/plugins/plot_surface/gog-contour-prefs.c
   trunk/plugins/plot_surface/gog-xyz-prefs.glade
      - copied, changed from r2048, /trunk/plugins/plot_surface/gog-contour-prefs.glade
   trunk/plugins/plot_surface/gog-xyz.c
   trunk/plugins/plot_surface/gog-xyz.h
Removed:
   trunk/plugins/plot_surface/gog-contour-prefs.c
   trunk/plugins/plot_surface/gog-contour-prefs.glade
Modified:
   trunk/ChangeLog
   trunk/goffice/data/go-data.c
   trunk/goffice/data/go-data.h
   trunk/goffice/goffice.c
   trunk/goffice/graph/Makefile.am
   trunk/goffice/graph/goffice-graph.h
   trunk/goffice/graph/gog-axis-line.c
   trunk/goffice/graph/gog-axis.c
   trunk/goffice/graph/gog-chart-impl.h
   trunk/goffice/graph/gog-chart.c
   trunk/goffice/graph/gog-chart.h
   trunk/goffice/math/Makefile.am
   trunk/goffice/math/go-rangefunc.c
   trunk/goffice/math/go-rangefunc.h
   trunk/plugins/plot_surface/Makefile.am
   trunk/plugins/plot_surface/gog-surface.c
   trunk/plugins/plot_surface/gog-surface.h
   trunk/plugins/plot_surface/plot-types.xml.in
   trunk/plugins/plot_surface/plugin.xml.in
   trunk/plugins/plot_surface/xl-surface.c
   trunk/plugins/plot_surface/xl-surface.h

Modified: trunk/goffice/data/go-data.c
==============================================================================
--- trunk/goffice/data/go-data.c	(original)
+++ trunk/goffice/data/go-data.c	Mon May 12 09:02:12 2008
@@ -23,6 +23,7 @@
 #include "go-data.h"
 #include "go-data-impl.h"
 #include <goffice/math/go-math.h>
+#include <goffice/math/go-rangefunc.h>
 
 #include <gsf/gsf-impl-utils.h>
 #include <glib/gi18n-lib.h>
@@ -334,6 +335,30 @@
 		*max = vec->maximum;
 }
 
+gboolean
+go_data_vector_increasing (GODataVector *vec)
+{
+	double *data = go_data_vector_get_values (vec);
+	int length = go_data_vector_get_len (vec);
+	return go_range_increasing (data, length);
+}
+
+gboolean
+go_data_vector_decreasing (GODataVector *vec)
+{
+	double *data = go_data_vector_get_values (vec);
+	int length = go_data_vector_get_len (vec);
+	return go_range_decreasing (data, length);
+}
+
+gboolean
+go_data_vector_vary_uniformly (GODataVector *vec)
+{
+	double *data = go_data_vector_get_values (vec);
+	int length = go_data_vector_get_len (vec);
+	return go_range_vary_uniformly (data, length);
+}
+
 /*************************************************************************/
 
 #define GO_DATA_MATRIX_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST ((k), GO_DATA_MATRIX_TYPE, GODataMatrixClass))

Modified: trunk/goffice/data/go-data.h
==============================================================================
--- trunk/goffice/data/go-data.h	(original)
+++ trunk/goffice/data/go-data.h	Mon May 12 09:02:12 2008
@@ -63,6 +63,9 @@
 double	 go_data_vector_get_value  (GODataVector *vec, unsigned i);
 char	*go_data_vector_get_str    (GODataVector *vec, unsigned i);
 void	 go_data_vector_get_minmax (GODataVector *vec, double *min, double *max);
+gboolean go_data_vector_increasing (GODataVector *vec);
+gboolean go_data_vector_decreasing (GODataVector *vec);
+gboolean go_data_vector_vary_uniformly (GODataVector *vec);
 
 /*************************************************************************/
 

Modified: trunk/goffice/goffice.c
==============================================================================
--- trunk/goffice/goffice.c	(original)
+++ trunk/goffice/goffice.c	Mon May 12 09:02:12 2008
@@ -35,6 +35,7 @@
 #include <goffice/graph/gog-theme.h>
 #include <goffice/graph/gog-error-bar.h>
 #include <goffice/graph/gog-series-lines.h>
+#include <goffice/graph/gog-3d-box.h>
 #include <goffice/data/go-data-simple.h>
 #include <goffice/math/go-math.h>
 #include <goffice/utils/go-format.h>
@@ -126,6 +127,7 @@
 	(void) GOG_SERIES_LINES_TYPE;
 	(void) GO_DATA_SCALAR_VAL_TYPE;
 	(void) GO_DATA_SCALAR_STR_TYPE;
+	(void) GOG_3D_BOX_TYPE;
 	gog_themes_init	();
 	go_number_format_init ();
 	go_currency_date_format_init ();

Modified: trunk/goffice/graph/Makefile.am
==============================================================================
--- trunk/goffice/graph/Makefile.am	(original)
+++ trunk/goffice/graph/Makefile.am	Mon May 12 09:02:12 2008
@@ -11,6 +11,8 @@
 	gog-chart.c			\
 	\
 	gog-chart-map.c			\
+	gog-chart-map-3d.c			\
+	gog-3d-box.c			\
 	\
 	gog-axis.c			\
 	gog-axis-line.c			\
@@ -48,6 +50,8 @@
 	gog-chart.h			\
 	gog-chart-impl.h		\
 	gog-chart-map.h			\
+	gog-chart-map-3d.h			\
+	gog-3d-box.h			\
 	gog-axis.h			\
 	gog-axis-line.h			\
 	gog-axis-line-impl.h		\

Modified: trunk/goffice/graph/goffice-graph.h
==============================================================================
--- trunk/goffice/graph/goffice-graph.h	(original)
+++ trunk/goffice/graph/goffice-graph.h	Mon May 12 09:02:12 2008
@@ -55,6 +55,7 @@
 typedef struct _GogTrendLineType	GogTrendLineType;
 typedef struct _GogSeriesLines GogSeriesLines;
 typedef struct _GogSmoothedCurve	GogSmoothedCurve;
+typedef struct _Gog3DBox	Gog3DBox;
 
 /* formating */
 typedef struct _GogTheme	GogTheme;

Added: trunk/goffice/graph/gog-3d-box.c
==============================================================================
--- (empty file)
+++ trunk/goffice/graph/gog-3d-box.c	Mon May 12 09:02:12 2008
@@ -0,0 +1,46 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * gog-3d-box.h :
+ *
+ * Copyright (C) 2007 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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/goffice-config.h>
+#include <goffice/graph/gog-3d-box.h>
+#include <goffice/math/go-math.h>
+#include <gsf/gsf-impl-utils.h>
+
+typedef GogObjectClass Gog3DBoxClass;
+
+static void
+gog_3d_box_class_init (Gog3DBoxClass *klass)
+{
+}
+
+static void
+gog_3d_box_init (Gog3DBox *box)
+{
+	box->fov = 10. / 180. * M_PI;
+	box->psi = 70. / 180. * M_PI;
+	box->theta = 10. / 180. * M_PI;
+	box->phi = -90. / 180. * M_PI;
+	go_matrix3x3_from_euler (&box->mat, box->psi, box->theta, box->phi);
+}
+
+GSF_CLASS (Gog3DBox, gog_3d_box,
+	   gog_3d_box_class_init, gog_3d_box_init,
+	   GOG_OBJECT_TYPE)

Added: trunk/goffice/graph/gog-3d-box.h
==============================================================================
--- (empty file)
+++ trunk/goffice/graph/gog-3d-box.h	Mon May 12 09:02:12 2008
@@ -0,0 +1,50 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * gog-3d-box.h :
+ *
+ * Copyright (C) 2007 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 GOG_3D_BOX_H
+#define GOG_3D_BOX_H
+
+#include <goffice/graph/goffice-graph.h>
+#include <goffice/graph/gog-object.h>
+#include <goffice/math/go-matrix3x3.h>
+
+G_BEGIN_DECLS
+
+struct _Gog3DBox {
+	GogObject base;
+
+	double fov, psi, theta, phi; /* field of view and orientation */
+	double dx, dy, dz; /* box size */
+	double r; /* distance from view point to the center of the box */
+	double ratio; /* ratio to use to be certain that everything fits
+	in the view */
+	GOMatrix3x3 mat; /* the matrix based on psi, theta, and phi */
+};
+
+#define GOG_3D_BOX_TYPE		(gog_3d_box_get_type ())
+#define GOG_3D_BOX(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GOG_3D_BOX_TYPE, Gog3DBox))
+#define IS_GOG_3D_BOX(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOG_3D_BOX_TYPE))
+
+GType 	gog_3d_box_get_type 	(void);
+
+G_END_DECLS
+
+#endif /* GOG_3D_BOX_H */

Modified: trunk/goffice/graph/gog-axis-line.c
==============================================================================
--- trunk/goffice/graph/gog-axis-line.c	(original)
+++ trunk/goffice/graph/gog-axis-line.c	Mon May 12 09:02:12 2008
@@ -1766,6 +1766,20 @@
 }
 
 static gboolean
+xyz_process (GogAxisBaseAction action, GogView *view, GogViewPadding *padding,
+	    GogViewAllocation const *plot_area, double x, double y)
+{
+    GogAxisBase *axis_base = GOG_AXIS_BASE (view->model);
+    GogAxisType axis_type = gog_axis_get_atype (axis_base->axis);
+    g_return_val_if_fail (axis_type == GOG_AXIS_X ||
+			  axis_type == GOG_AXIS_Y ||
+			  axis_type == GOG_AXIS_Z, FALSE);
+
+    return TRUE;
+
+}
+
+static gboolean
 gog_axis_base_view_point (GogView *view, double x, double y)
 {
 	GogAxisBase *axis_base = GOG_AXIS_BASE (view->model);
@@ -1800,6 +1814,9 @@
 		case GOG_AXIS_SET_RADAR:
 			pointed = radar_process (GOG_AXIS_BASE_POINT, view, NULL, plot_area, x, y);
 			break;
+		case GOG_AXIS_SET_XYZ:
+			xyz_process (GOG_AXIS_BASE_PADDING_REQUEST, view, NULL, plot_area, x, y);
+			break;
 		default:
 			g_warning ("[AxisBaseView::point] not implemented for this axis set (%i)",
 				   axis_set);
@@ -1834,6 +1851,8 @@
 		case GOG_AXIS_SET_RADAR:
 			radar_process (GOG_AXIS_BASE_PADDING_REQUEST, view, padding, bbox, 0., 0.);
 			break;
+		case GOG_AXIS_SET_XYZ:
+			break;
 		default:
 			g_warning ("[AxisBaseView::padding_request] not implemented for this axis set (%i)",
 				   axis_set);

Modified: trunk/goffice/graph/gog-axis.c
==============================================================================
--- trunk/goffice/graph/gog-axis.c	(original)
+++ trunk/goffice/graph/gog-axis.c	Mon May 12 09:02:12 2008
@@ -2317,6 +2317,9 @@
 	double const pad_h = gog_renderer_pt2r_y (view->renderer, PAD_HACK);
 	double const pad_w = gog_renderer_pt2r_x (view->renderer, PAD_HACK);
 
+	if (gog_chart_is_3d (GOG_CHART (gog_object_get_parent (view->model))))
+	    return;
+
 	available.w = bbox->w;
 	available.h = bbox->h;
 

Modified: trunk/goffice/graph/gog-chart-impl.h
==============================================================================
--- trunk/goffice/graph/gog-chart-impl.h	(original)
+++ trunk/goffice/graph/gog-chart-impl.h	Mon May 12 09:02:12 2008
@@ -29,6 +29,8 @@
 
 G_BEGIN_DECLS
 
+typedef struct _GogChart3dParms GogChart3dParms;
+
 struct _GogChart {
 	GogOutlinedObject	 base;
 
@@ -45,6 +47,7 @@
 
 	GogViewAllocation plot_area;
 	gboolean	  is_plot_area_manual;
+	GogChart3dParms *p3d;
 };
 typedef GogOutlinedObjectClass GogChartClass;
 

Added: trunk/goffice/graph/gog-chart-map-3d.c
==============================================================================
--- (empty file)
+++ trunk/goffice/graph/gog-chart-map-3d.c	Mon May 12 09:02:12 2008
@@ -0,0 +1,182 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * gog-chart-map-3d.c :
+ *
+ * Copyright (C) 2007 Jean Brefort <jean brefort normalesup org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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/graph/gog-chart-map-3d.h>
+#include <goffice/graph/gog-3d-box.h>
+#include <goffice/math/go-matrix3x3.h>
+
+struct _GogChartMap3D {
+	GogChart 		*chart;
+	GogViewAllocation	 area;
+	gpointer	 	 data;
+	GogAxisMap		*axis_map[3];
+	gboolean		 is_valid;
+	GOMatrix3x3		 mat;
+
+	void 	 (*map_3D_to_view) 	(GogChartMap3D *map, double x, double y, double z, double *u, double *v, double *w);
+};
+
+static void 
+null_map_3D (GogChartMap3D *map, double x, double y, double z, double *u, double *v, double *w)
+{
+	g_warning ("[GogChartMap::map_3D] not implemented");
+}
+
+static void 
+xyz_map_3D_to_view (GogChartMap3D *map, double x, double y, double z, double *u, double *v, double *w)
+{
+	Gog3DBox *box = GOG_3D_BOX (gog_object_get_child_by_name (GOG_OBJECT (map->chart), "3D-Box"));
+	x = gog_axis_map_to_view (map->axis_map[0], x);
+	y = gog_axis_map_to_view (map->axis_map[1], y);
+	z = gog_axis_map_to_view (map->axis_map[2], z);
+	go_matrix3x3_transform (&box->mat, x, y, z, &x, &y, &z);
+	if (box->fov > 0.) {
+	    x *= (1. + y / box->r) / box->ratio;
+	    z *= (1. + y / box->r) / box->ratio;
+	} else {
+	    x /= box->ratio;
+	    z /= box->ratio;
+	}
+	if (u)
+	    *u = map->area.x + map->area.w / 2. * (1. + x / box->dx);
+	if (v)
+	    *v = map->area.y + map->area.h / 2. * (1. - z / box->dz);
+	if (w)
+	    *w = y;
+}
+
+/**
+ * gog_chart_3d_map_new:
+ * @chart: a #GogChart with 3D support
+ * @area: area allocated to chart
+ * @axis0: 1st dimension axis
+ * @axis1: 2nd dimension axis
+ * @axis2: 3rd dimension axis
+ * @fill_area: does chart fill allocated area
+ *
+ * Creates a new #GogChartMap3D, used for conversion from data space 
+ * to canvas space.
+ *
+ * returns: a new #GogChartMap3D object. 
+ **/
+
+GogChartMap3D*
+gog_chart_map_3d_new (GogChart *chart, GogViewAllocation const *area,
+			GogAxis *axis0, GogAxis *axis1, GogAxis *axis2)
+{
+	GogChartMap3D *map;
+	GogAxisSet axis_set;
+	Gog3DBox *box;
+
+	g_return_val_if_fail (IS_GOG_CHART (chart), NULL);
+
+	map = g_new (GogChartMap3D, 1);
+	
+	g_object_ref (chart);
+	map->chart = chart;
+	map->area = *area;
+	map->data = NULL;
+	map->is_valid = FALSE;
+	box = GOG_3D_BOX (gog_object_get_child_by_name (GOG_OBJECT (chart), "3D-Box"));
+
+	axis_set = gog_chart_get_axis_set (chart);
+	switch (axis_set & GOG_AXIS_SET_FUNDAMENTAL) {
+	case GOG_AXIS_SET_XYZ: {
+		map->axis_map[0] = gog_axis_map_new (axis0, -box->dx, 2 * box->dx);
+		map->axis_map[1] = gog_axis_map_new (axis1, -box->dy, 2 * box->dy);
+		map->axis_map[2] = gog_axis_map_new (axis2, -box->dz, 2 * box->dz);
+
+		map->data = NULL;
+		map->map_3D_to_view = xyz_map_3D_to_view;
+
+		map->is_valid = gog_axis_map_is_valid (map->axis_map[0]) &&
+			gog_axis_map_is_valid (map->axis_map[1]) &&
+			gog_axis_map_is_valid (map->axis_map[2]);
+		
+		break;
+	}
+	default:
+		g_warning ("[Chart3D::map_new] not implemented for this axis set (%i)",
+			   axis_set);
+		map->map_3D_to_view = null_map_3D;
+		break;
+	}
+
+	return map;
+}
+
+/**
+ * gog_chart_map_3d_to_view:
+ * @map: a #GogChartMap3D
+ * @x: data x value
+ * @y: data y value
+ * @z: data y value
+ * @u: placeholder for x converted value
+ * @v: placeholder for y converted value
+ *
+ * Converts a 3D coordinate from data space to canvas space.
+ **/
+
+void
+gog_chart_map_3d_to_view (GogChartMap3D *map, double x, double y, double z, double *u, double *v, double *w)
+{
+	(map->map_3D_to_view) (map, x, y, z, u, v, w);
+}
+
+/**
+ * gog_chart_map_3d_is_valid:
+ * @map: a #GogChartMap3D
+ *
+ * Tests if @map was correctly initialized.
+ *
+ * returns: %TRUE if @map is valid.
+ **/
+
+gboolean
+gog_chart_map_3d_is_valid (GogChartMap3D *map)
+{
+	g_return_val_if_fail (map != NULL, FALSE);
+
+	return map->is_valid;
+}
+
+/**
+ * gog_chart_map_3d_free:
+ * @map: a #GogChartMap3D
+ *
+ * Frees @map object.
+ **/
+
+void
+gog_chart_map_3d_free (GogChartMap3D *map)
+{
+	int i;
+
+	g_return_if_fail (map != NULL);
+
+	for (i = 0; i < 3; i++)
+		if (map->axis_map[i] != NULL)
+			gog_axis_map_free (map->axis_map[i]);
+
+	g_free (map->data);
+	g_object_unref (map->chart);
+	g_free (map);
+}

Added: trunk/goffice/graph/gog-chart-map-3d.h
==============================================================================
--- (empty file)
+++ trunk/goffice/graph/gog-chart-map-3d.h	Mon May 12 09:02:12 2008
@@ -0,0 +1,43 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * gog-chart-map-3d.h :
+ *
+ * Copyright (C) 2007 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 GOG_CHART_MAP_3D_H
+#define GOG_CHART_MAP_3D_H
+
+#include <goffice/graph/gog-axis.h>
+#include <goffice/graph/gog-chart.h>
+#include <goffice/graph/gog-series.h>
+#include <goffice/utils/go-path.h>
+#include <goffice/utils/go-line.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GogChartMap3D GogChartMap3D;
+
+GogChartMap3D 	*gog_chart_map_3d_new 		(GogChart *chart, GogViewAllocation const *area,
+						 GogAxis *axis0, GogAxis *axis1, GogAxis *axis2);
+void 		 gog_chart_map_3d_to_view	(GogChartMap3D *map, double x, double y, double z, double *u, double *v, double *w);
+gboolean	 gog_chart_map_3d_is_valid 	(GogChartMap3D *map);
+void		 gog_chart_map_3d_free 		(GogChartMap3D *map);
+
+G_END_DECLS
+
+#endif /* GOG_CHART_MAP_3D_H */

Modified: trunk/goffice/graph/gog-chart.c
==============================================================================
--- trunk/goffice/graph/gog-chart.c	(original)
+++ trunk/goffice/graph/gog-chart.c	Mon May 12 09:02:12 2008
@@ -22,6 +22,8 @@
 #include <goffice/goffice-config.h>
 #include <goffice/graph/gog-chart-impl.h>
 #include <goffice/graph/gog-chart-map.h>
+#include <goffice/graph/gog-chart-map-3d.h>
+#include <goffice/graph/gog-3d-box.h>
 #include <goffice/graph/gog-plot-impl.h>
 #include <goffice/graph/gog-graph-impl.h>
 #include <goffice/graph/gog-style.h>
@@ -32,6 +34,7 @@
 #include <goffice/graph/gog-grid-line.h>
 #include <goffice/graph/gog-renderer.h>
 #include <goffice/math/go-math.h>
+#include <goffice/math/go-matrix3x3.h>
 
 #include <gsf/gsf-impl-utils.h>
 #include <glib/gi18n-lib.h>
@@ -80,7 +83,6 @@
 }
 
 /*****************************************************************************/
-
 enum {
 	CHART_PROP_0,
 	CHART_PROP_CARDINALITY_VALID,
@@ -351,6 +353,8 @@
 static void bubble_axis_post_add    (GogObject *parent, GogObject *child)  { axis_post_add   (child, GOG_AXIS_BUBBLE); }
 static gboolean color_axis_can_add (GogObject const *parent) { return axis_can_add (parent, GOG_AXIS_COLOR); }
 static void color_axis_post_add    (GogObject *parent, GogObject *child)  { axis_post_add   (child, GOG_AXIS_COLOR); }
+static gboolean role_3d_box_can_add	(GogObject const *parent) {return FALSE;}
+static gboolean role_3d_box_can_remove	(GogObject const *parent) {return FALSE;}
 
 static GogObjectRole const roles[] = {
 	{ N_("Backplane"), "GogGrid",	0,
@@ -400,7 +404,10 @@
 	  GOG_POSITION_COMPASS|GOG_POSITION_ANY_MANUAL, 
 	  GOG_POSITION_E|GOG_POSITION_ALIGN_CENTER, 
 	  GOG_OBJECT_NAME_BY_ROLE,
-	  NULL, NULL, NULL, NULL, NULL, NULL, { -1 } }
+	  NULL, NULL, NULL, NULL, NULL, NULL, { -1 } },
+	{ N_("3D-Box"), "Gog3DBox",	0,
+	  GOG_POSITION_SPECIAL, GOG_POSITION_SPECIAL, GOG_OBJECT_NAME_BY_ROLE,
+	  role_3d_box_can_add, role_3d_box_can_remove, NULL, NULL, NULL, NULL, { -1 } }
 };
 
 static void
@@ -760,6 +767,144 @@
 	return GOG_GRID (chart->grid);
 }
 
+gboolean
+gog_chart_is_3d (GogChart const *chart)
+{
+	return chart->axis_set == GOG_AXIS_SET_XYZ;
+}
+
+static void
+gog_chart_3d_process (GogChart *chart, GogViewAllocation const *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;
+	GSList *axes;
+	double xmin, xmax, ymin, ymax, zmin, zmax;
+	double o[3], x[3], y[3], z[3], tg, d;
+	Gog3DBox *box;
+	GogObject *obj = gog_object_get_child_by_name (GOG_OBJECT (chart), "3D-Box");
+
+	if (!obj) {
+		obj = g_object_new (GOG_3D_BOX_TYPE, NULL);
+		gog_object_add_by_name (GOG_OBJECT (chart), "3D-Box", obj);
+	}
+	box = GOG_3D_BOX (obj);
+
+	/* Only use the first of the axes. */
+	axes = gog_chart_get_axes (chart, GOG_AXIS_X);
+	axisX = GOG_AXIS (axes->data);
+	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);
+	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);
+	g_slist_free (axes);
+	gog_axis_get_bounds (axisZ, &zmin, &zmax);
+	/* define the 3d box */
+	/* FIXME: take axes into account */
+	box->dz = tmp.h;
+	if (ymax - ymin > xmax - xmin) {
+		box->dy = tmp.w;
+		box->dx = (xmax - xmin) / (ymax - ymin) * tmp.w;
+	} else {
+		box->dx = tmp.w;
+		box->dy = (ymax - ymin) / (xmax - xmin) * tmp.w;
+	}
+
+	/* now compute the position of each vertex, ignoring the fov */
+	go_matrix3x3_transform (&box->mat, -box->dx, -box->dy, -box->dz, o, o + 1, o + 2);
+	go_matrix3x3_transform (&box->mat, box->dx, -box->dy, -box->dz, x, x + 1, x + 2);
+	go_matrix3x3_transform (&box->mat, -box->dx, box->dy, -box->dz, y, y + 1, y + 2);
+	go_matrix3x3_transform (&box->mat, -box->dx, -box->dy, box->dz, z, z + 1, z + 2);
+	/* for each diagonal, we need to take the vertex closer to the view point */
+	if (o[1] > 0) {
+		o[0] = -o[0];
+		o[1] = -o[1];
+		o[2] = -o[2];
+	}
+	if (x[1] > 0) {
+		x[0] = -x[0];
+		x[1] = -x[1];
+		x[2] = -x[2];
+	}
+	if (y[1] > 0) {
+		y[0] = -y[0];
+		y[1] = -y[1];
+		y[2] = -y[2];
+	}
+	if (z[1] > 0) {
+		z[0] = -z[0];
+		z[1] = -z[1];
+		z[2] = -z[2];
+	}
+	/* if the fov is positive, calculate the position of the viewpoint */
+	if (box->fov > 0.) {
+		tg = tan (box->fov / 2.);
+		box->r = -sqrt (o[0] * o[0] + o[2] * o[2]) / tg + o[1];
+		d = -sqrt (x[0] * x[0] + x[2] * x[2]) / tg + x[1];
+		if (d < box->r)
+			box->r = d;
+		d = -sqrt (y[0] * y[0] + y[2] * y[2]) / tg + y[1];
+		if (d < box->r)
+			box->r = d;
+		d = -sqrt (z[0] *z[0] + z[2] * z[2]) / tg + z[1];
+		if (d < box->r)
+			box->r = d;
+		/* also calculate the reduction factor we need to make things fit in the bbox */
+		xmax = fabs (o[0]) * (1. + o[1] / box->r);
+		zmax = fabs (o[2]) * (1. + o[1] / box->r);
+		d = fabs (x[0]) * (1. + x[1] / box->r);
+		if (d > xmax)
+			xmax = d;
+		d = fabs (x[2]) * (1. + x[1] / box->r);
+		if (d > zmax)
+			zmax = d;
+		d = fabs (y[0]) * (1. + y[1] / box->r);
+		if (d > xmax)
+			xmax = d;
+		d = fabs (y[2]) * (1. + y[1] / box->r);
+		if (d > zmax)
+			zmax = d;
+		d = fabs (z[0]) * (1. + z[1] / box->r);
+		if (d > xmax)
+			xmax = d;
+		d = fabs (z[2]) * (1. + z[1] / box->r);
+		if (d > zmax)
+			zmax = d;
+	} else {
+	    /* calculate the reduction factor we need to make things fit in the bbox */
+		xmax = fabs (o[0]);
+		zmax = fabs (o[2]);
+		d = fabs (x[0]);
+		if (d > xmax)
+			xmax = d;
+		d = fabs (x[2]);
+		if (d > zmax)
+			zmax = d;
+		d = fabs (y[0]);
+		if (d > xmax)
+			xmax = d;
+		d = fabs (y[2]);
+		if (d > zmax)
+			zmax = d;
+		d = fabs (z[0]);
+		if (d > xmax)
+			xmax = d;
+		d = fabs (z[2]);
+		if (d > zmax)
+			zmax = d;
+	}
+	/* use d and tg as x and z ratios, respectively */
+	d = xmax / tmp.w;
+	tg = zmax / tmp.h;
+	box->ratio = (d > tg)? d: tg;
+}
+
 /*********************************************************************/
 
 typedef struct {
@@ -823,6 +968,10 @@
 		if (GOG_POSITION_IS_SPECIAL (child->model->position))
 			gog_view_size_allocate (child, plot_area);
 	}
+
+	/* special treatment for 3d charts */
+	if (gog_chart_is_3d (chart))
+	    gog_chart_3d_process (chart, plot_area);
 }
 
 static void
@@ -896,24 +1045,38 @@
 	GSList *ptr;
 	GogView *child_view;
 	gboolean grid_line_rendered = FALSE;
+	GogChart *chart = GOG_CHART (gog_view_get_model (view));
 
 	cview_parent_klass->render (view, bbox);
 
-	/* KLUDGE: render grid lines before axis */
-	for (ptr = view->children ; ptr != NULL ; ptr = ptr->next) {
-		child_view = ptr->data;
-		if (!grid_line_rendered && IS_GOG_AXIS (child_view->model)) {
-			grid_line_render (ptr, bbox);
-			plot_render (view, bbox);
-			grid_line_rendered = TRUE;
+	if (gog_chart_is_3d (chart)) {
+		for (ptr = view->children ; ptr != NULL ; ptr = ptr->next) {
+			child_view = ptr->data;
+			if (!IS_GOG_AXIS (child_view->model) && !IS_GOG_PLOT (child_view->model)) 
+			    gog_view_render	(ptr->data, bbox);
+		}
+		/* now render plot and axes */
+		for (ptr = view->children ; ptr != NULL ; ptr = ptr->next) {
+			child_view = ptr->data;
+			if (IS_GOG_PLOT (child_view->model)) 
+			    gog_view_render	(ptr->data, bbox);
+		}
+	} else {
+		/* KLUDGE: render grid lines before axis */
+		for (ptr = view->children ; ptr != NULL ; ptr = ptr->next) {
+			child_view = ptr->data;
+			if (!grid_line_rendered && IS_GOG_AXIS (child_view->model)) {
+				grid_line_render (ptr, bbox);
+				plot_render (view, bbox);
+				grid_line_rendered = TRUE;
+			}
+			if (IS_GOG_PLOT (child_view->model)) {
+			    if (!GOG_PLOT (child_view->model)->render_before_axes)
+				gog_view_render	(ptr->data, bbox);
+			} else
+				gog_view_render	(ptr->data, bbox);
 		}
-		if (IS_GOG_PLOT (child_view->model)) {
-		    if (!GOG_PLOT (child_view->model)->render_before_axes)
-			gog_view_render	(ptr->data, bbox);
-		} else
-			gog_view_render	(ptr->data, bbox);
 	}
-
 }
 
 static void

Modified: trunk/goffice/graph/gog-chart.h
==============================================================================
--- trunk/goffice/graph/gog-chart.h	(original)
+++ trunk/goffice/graph/gog-chart.h	Mon May 12 09:02:12 2008
@@ -29,7 +29,7 @@
 G_BEGIN_DECLS
 
 GogAxisSet gog_axis_set_from_str (char const *str);
-	
+
 #define GOG_CHART_TYPE	(gog_chart_get_type ())
 #define GOG_CHART(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOG_CHART_TYPE, GogChart))
 #define IS_GOG_CHART(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOG_CHART_TYPE))
@@ -60,6 +60,8 @@
 /* View utils */
 GogViewAllocation const *gog_chart_view_get_plot_area (GogView const *view);
 
+gboolean gog_chart_is_3d 	(GogChart const *chart);
+
 G_END_DECLS
 
 #endif /* GOG_CHART_H */

Modified: trunk/goffice/math/Makefile.am
==============================================================================
--- trunk/goffice/math/Makefile.am	(original)
+++ trunk/goffice/math/Makefile.am	Mon May 12 09:02:12 2008
@@ -6,7 +6,8 @@
 	go-regression.c	\
 	go-cspline.c	\
 	go-complex.c	\
-	go-fft.c
+	go-fft.c		\
+	go-matrix3x3.c
 
 libgoffice_math_ladir = $(goffice_include_dir)/math
 libgoffice_math_la_HEADERS = 	\
@@ -15,7 +16,8 @@
 	go-regression.h	\
 	go-cspline.h	\
 	go-complex.h	\
-	go-fft.h
+	go-fft.h		\
+	go-matrix3x3.h
 
 include $(top_srcdir)/goffice.mk
 

Added: trunk/goffice/math/go-matrix3x3.c
==============================================================================
--- (empty file)
+++ trunk/goffice/math/go-matrix3x3.c	Mon May 12 09:02:12 2008
@@ -0,0 +1,56 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * go-matrix3x3.c
+ *
+ * Copyright (C) 2007 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/goffice-config.h>
+#include <goffice/math/go-matrix3x3.h>
+#include <math.h>
+
+void
+go_matrix3x3_transform (GOMatrix3x3 *mat,
+				gdouble xo, gdouble yo, gdouble zo,
+				gdouble *x, gdouble *y, gdouble *z)
+{
+	*x = xo * mat->a11 + yo * mat->a12 + zo * mat->a13;
+	*y = xo * mat->a21 + yo * mat->a22 + zo * mat->a23;
+	*z = xo * mat->a31 + yo * mat->a32 + zo * mat->a33;
+}
+
+void
+go_matrix3x3_from_euler (GOMatrix3x3 *mat,
+				gdouble Psi, gdouble Theta, gdouble Phi)
+{
+	gdouble sp = sin(Psi);
+	gdouble cp = cos(Psi);
+	gdouble st = sin(Theta);
+	gdouble ct = cos(Theta);
+	gdouble sf = sin(Phi);
+	gdouble cf = cos(Phi);
+	mat->a11 = cf * cp - sf * sp * ct;
+	mat->a12 = - cp * sf - sp * cf * ct;
+	mat->a13 = st * sp;
+	mat->a21 =  sp * cf + cp * sf * ct;
+	mat->a22 = cf * cp * ct - sf * sp;
+	mat->a23 = - st * cp;
+	mat->a31 = st * sf;
+	mat->a32 = st * cf;
+	mat->a33 = ct;
+}

Added: trunk/goffice/math/go-matrix3x3.h
==============================================================================
--- (empty file)
+++ trunk/goffice/math/go-matrix3x3.h	Mon May 12 09:02:12 2008
@@ -0,0 +1,39 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * go-matrix3x3.h
+ *
+ * Copyright (C) 2007 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_MATRIX3X3_H
+#define GO_MATRIX3X3_H
+
+#include <glib/gtypes.h>
+
+typedef struct {
+	gdouble a11, a12, a13, a21, a22, a23, a31, a32, a33;
+} GOMatrix3x3;
+
+void go_matrix3x3_transform (GOMatrix3x3 *mat,
+				gdouble xo, gdouble yo, gdouble zo,
+				gdouble *x, gdouble *y, gdouble *z);
+
+void go_matrix3x3_from_euler (GOMatrix3x3 *mat,
+				gdouble Psi, gdouble Theta, gdouble Phi);
+
+#endif /* GO_MATRIX3X3_H */

Modified: trunk/goffice/math/go-rangefunc.c
==============================================================================
--- trunk/goffice/math/go-rangefunc.c	(original)
+++ trunk/goffice/math/go-rangefunc.c	Mon May 12 09:02:12 2008
@@ -233,3 +233,19 @@
 			return 0;
 	return 1;
 }
+
+int
+SUFFIX(go_range_decreasing) (DOUBLE const *xs, int n)
+{
+	int i;
+	for (i = 1; i < n; i++)
+		if (xs[i - 1] <= xs[i])
+			return 0;
+	return 1;
+}
+
+int
+SUFFIX(go_range_vary_uniformly) (DOUBLE const *xs, int n)
+{
+	return SUFFIX(go_range_increasing) (xs, n) || SUFFIX(go_range_decreasing) (xs, n);
+}

Modified: trunk/goffice/math/go-rangefunc.h
==============================================================================
--- trunk/goffice/math/go-rangefunc.h	(original)
+++ trunk/goffice/math/go-rangefunc.h	Mon May 12 09:02:12 2008
@@ -17,6 +17,8 @@
 int go_range_median_inter (double const *xs, int n, double *res);
 int go_range_median_inter_nonconst (double *xs, int n, double *res);
 int go_range_increasing (double const *xs, int n);
+int go_range_decreasing (double const *xs, int n);
+int go_range_vary_uniformly (double const *xs, int n);
 
 #ifdef GOFFICE_WITH_LONG_DOUBLE
 int go_range_suml (long double const *xs, int n, long double *res);
@@ -32,6 +34,8 @@
 int go_range_median_interl (long double const *xs, int n, long double *res);
 int go_range_median_inter_nonconstl (long double *xs, int n, long double *res);
 int go_range_increasingl (long double const *xs, int n);
+int go_range_decreasingl (long double const *xs, int n);
+int go_range_vary_uniformlyl (long double const *xs, int n);
 #endif
 
 G_END_DECLS

Modified: trunk/plugins/plot_surface/Makefile.am
==============================================================================
--- trunk/plugins/plot_surface/Makefile.am	(original)
+++ trunk/plugins/plot_surface/Makefile.am	Mon May 12 09:02:12 2008
@@ -7,6 +7,10 @@
 surface_la_LIBADD = $(GOFFICE_PLUGIN_LIBADD) 
 
 surface_la_SOURCES = \
+	gog-xyz.c		\
+	gog-xyz.h		\
+	gog-contour.c		\
+	gog-contour.h		\
 	gog-surface.c		\
 	gog-surface.h		\
 	xl-surface.c		\
@@ -18,8 +22,8 @@
 @INTLTOOL_XML_RULE@
 
 if WITH_GTK
-dist_glade_DATA = gog-contour-prefs.glade
-surface_la_SOURCES += gog-contour-prefs.c
+dist_glade_DATA = gog-xyz-prefs.glade
+surface_la_SOURCES += gog-xyz-prefs.c
 endif
 
 # do not use the intl-tool stuff to merge the text back

Added: trunk/plugins/plot_surface/gog-contour.c
==============================================================================
--- (empty file)
+++ trunk/plugins/plot_surface/gog-contour.c	Mon May 12 09:02:12 2008
@@ -0,0 +1,1146 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * gog-xyz.c
+ *
+ * Copyright (C) 2004-2007 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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/goffice-config.h>
+#include "gog-contour.h"
+#include <goffice/data/go-data.h>
+#include <goffice/graph/gog-chart.h>
+#include <goffice/graph/gog-renderer.h>
+#include <goffice/graph/gog-theme.h>
+#include <goffice/math/go-math.h>
+#include <goffice/utils/go-color.h>
+
+#include <gsf/gsf-impl-utils.h>
+#include <glib/gi18n-lib.h>
+
+#include <string.h>
+
+#define EPSILON 1e-13
+
+static GType gog_contour_view_get_type (void);
+
+/*-----------------------------------------------------------------------------
+ *
+ *  GogContourPlot
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static double *
+gog_contour_plot_build_matrix (GogXYZPlot const *plot, gboolean *cardinality_changed)
+{
+	unsigned i, j;
+	GogAxisMap *map;
+	GogAxisTick *zticks;
+	GogAxis *axis = plot->base.axis[GOG_AXIS_PSEUDO_3D];
+	unsigned nticks;
+	double *x, val;
+	GogSeries *series = GOG_SERIES (plot->base.series->data);
+	GODataMatrix *mat = GO_DATA_MATRIX (series->values[2].data);
+	unsigned n = plot->rows * plot->columns;
+	double *data, minimum, maximum, slope, offset = 0.;
+	unsigned max;
+
+	if (!gog_axis_get_bounds (axis, &minimum, &maximum))
+		return NULL;
+	data = g_new (double, n);
+	nticks = gog_axis_get_ticks (axis, &zticks);
+	map = gog_axis_map_new (axis, 0, 1);
+	x = g_new (double, nticks);
+	for (i = j = 0; i < nticks; i++)
+		if (zticks[i].type == GOG_AXIS_TICK_MAJOR) {
+			x[j++] = gog_axis_map_to_view (map, zticks[i].position);
+		}
+	max = --j;
+	if (x[1] > x[0]) {
+		if (x[0] > EPSILON) {
+			offset = 1.;
+			max++;
+		}
+		if (x[j] < 1. - EPSILON)
+			max++;
+		slope = 1 / (x[1] - x[0]);
+	} else {
+		offset = j;
+		if (x[0] < 1. - EPSILON)
+			max++;
+		if (x[j] > EPSILON) {
+			max++;
+			offset += 1.;
+		}
+		slope = 1 / (x[0] - x[1]);
+	}
+
+	for (i = 0; i < plot->rows; i++)
+		for (j = 0; j < plot->columns; j++) {
+			val = gog_axis_map_to_view (map,
+					go_data_matrix_get_value (mat, i, j));
+			if (fabs (val) == DBL_MAX)
+				val = go_nan;
+			else {
+				val = offset + slope * (val - x[0]);
+				if (val < 0)
+					val = (val < -EPSILON)? go_nan: 0.;
+			}
+			if (plot->transposed)
+				data[j * plot->rows + i] = val;
+			else
+				data[i * plot->columns + j] = val;
+		}
+	if (series->num_elements != max) {
+		series->num_elements = max;
+		*cardinality_changed = TRUE;
+	}
+	gog_axis_map_free (map);
+	g_free (x);
+	return data;
+}
+
+static char const *
+gog_contour_plot_type_name (G_GNUC_UNUSED GogObject const *item)
+{
+	/* xgettext : the base for how to name contour plot objects
+	*/
+	return N_("PlotContour");
+}
+
+static void 
+gog_contour_plot_foreach_elem  (GogPlot *plot, gboolean only_visible,
+				    GogEnumFunc func, gpointer data)
+{
+	unsigned i, j, nticks;
+	char *label;
+	static char separator = 0;
+	GogStyle *style = gog_style_new ();
+	GogTheme *theme = gog_object_get_theme (GOG_OBJECT (plot));
+	GogAxis *axis = plot->axis[GOG_AXIS_PSEUDO_3D];
+	GOColor *color;
+	GogAxisTick *zticks;
+	double *limits;
+	double minimum, maximum;
+
+	gog_axis_get_bounds (axis, &minimum, &maximum);
+
+	if (separator == 0) {
+		struct lconv *lc = localeconv ();
+		separator = (strcmp (lc->decimal_point, ","))? ',': ';';
+	}
+	nticks = gog_axis_get_ticks (axis, &zticks);
+	limits = g_new (double, nticks + 1);
+	for (i = j = 0; i < nticks; i++)
+		if (zticks[i].type == GOG_AXIS_TICK_MAJOR)
+			limits[j++] = zticks[i].position;
+	j--;
+	if (maximum > limits[j])
+		limits[++j] = maximum;
+	/* build the colors table */
+	color = g_new0 (GOColor, (j > 0)? j: 1);
+	if (j < 2)
+		color[0] = RGBA_WHITE;
+	else for (i = 0; i < j; i++) {
+		gog_theme_fillin_style (theme, style, GOG_OBJECT (plot->series->data), i, FALSE);
+		color[i] = style->fill.pattern.back;
+	}
+	g_object_unref (style);
+
+	style = gog_style_new ();
+	style->interesting_fields = GOG_STYLE_FILL;
+	style->disable_theming = GOG_STYLE_ALL;
+	style->fill.type = GOG_FILL_STYLE_PATTERN;
+	style->fill.pattern.pattern = GO_PATTERN_SOLID;
+
+	if (gog_axis_is_inverted (axis)) {
+		for (i = 0; i < j; i++) {
+			style->fill.pattern.back = color[i];
+			label = g_strdup_printf ("[%g%c %g%c", limits[j - i - 1], separator,
+						limits[j - i], (limits[i - j] > minimum)? '[':']');
+			(func) (i, style, label, data);
+			g_free (label);
+		}
+		if (limits[i - j] > minimum) {
+			gog_theme_fillin_style (theme, style, GOG_OBJECT (plot->series->data), i, FALSE);
+			label = g_strdup_printf ("[%g%c %g]", minimum, separator,
+						limits[i - j]);
+			(func) (i, style, label, data);
+			g_free (label);
+		}
+	} else {
+		if (minimum < limits[0]) {
+			style->fill.pattern.back = color[0];
+			label = g_strdup_printf ("[%g%c %g]", minimum, separator,
+						limits[0]);
+			(func) (0, style, label, data);
+			g_free (label);
+			i = 1;
+			j++;
+		} else
+			i = 0;
+		for (; i < j; i++) {
+			style->fill.pattern.back = color[i];
+			label = g_strdup_printf ("[%g%c %g%c", limits[i], separator,
+						limits[i + 1], (i == j - 1)? ']':'[');
+			(func) (i, style, label, data);
+			g_free (label);
+		}
+	}
+	g_free (limits);
+	g_object_unref (style);
+	g_free (color);
+}
+
+static void
+gog_contour_plot_class_init (GogContourPlotClass *klass)
+{
+	GogXYZPlotClass *gog_xyz_plot_klass = (GogXYZPlotClass *) klass;
+	GogPlotClass *gog_plot_klass = (GogPlotClass*) klass;
+	GogObjectClass *gog_object_klass = (GogObjectClass *) klass;
+
+	/* Fill in GogObject superclass values */
+	gog_object_klass->type_name	= gog_contour_plot_type_name;
+	gog_object_klass->view_type	= gog_contour_view_get_type ();
+
+	gog_plot_klass->axis_set = GOG_AXIS_SET_XY_pseudo_3d;
+	gog_plot_klass->foreach_elem = gog_contour_plot_foreach_elem;
+
+	gog_xyz_plot_klass->third_axis = GOG_AXIS_PSEUDO_3D;
+	gog_xyz_plot_klass->build_matrix = gog_contour_plot_build_matrix;
+}
+
+static void
+gog_contour_plot_init (GogContourPlot *contour)
+{
+	GogPlot *plot = GOG_PLOT (contour);
+
+	plot->render_before_axes = TRUE;
+}
+
+GSF_DYNAMIC_CLASS (GogContourPlot, gog_contour_plot,
+	gog_contour_plot_class_init, gog_contour_plot_init,
+	GOG_XYZ_PLOT_TYPE)
+
+/*****************************************************************************/
+
+typedef GogPlotView		GogContourView;
+typedef GogPlotViewClass	GogContourViewClass;
+#define CONTOUR_EPSILON 1e-10
+
+static void
+gog_contour_view_render (GogView *view, GogViewAllocation const *bbox)
+{
+	GogXYZPlot const *plot = GOG_XYZ_PLOT (view->model);
+	GogSeries const *series;
+	GODataVector *x_vec = NULL, *y_vec = NULL;
+	GogAxisMap *x_map, *y_map;
+	double zval0, zval1, zval2 = 0., zval3, t;
+	double x[4], y[4], zval[4];
+	int z[4];
+	int z0 = 0, z1 = 0, z2 = 0, z3 = 0, zmin, zmax, nans, nan = 0;
+	int k, kmax, r = 0, s, h;
+	unsigned i, imax, j, jmax, l, lmax, p;
+	GogRenderer *rend = view->renderer;
+	GogStyle *style;
+	GogTheme *theme = gog_object_get_theme (GOG_OBJECT (plot));
+	double x0, x1, y0, y1;
+	ArtVpath *path, *lines;
+	GOColor *color;
+	gboolean cw;
+	double *data;
+	int max;
+	gboolean xdiscrete, ydiscrete;
+
+	if (plot->base.series == NULL)
+		return;
+	series = GOG_SERIES (plot->base.series->data);
+	max = series->num_elements;
+	if (plot->transposed) {
+		imax = plot->columns;
+		jmax = plot->rows;
+	} else {
+		imax = plot->rows;
+		jmax = plot->columns;
+	}
+	if (imax ==0 || jmax == 0)
+		return;
+
+	x_map = gog_axis_map_new (plot->base.axis[0], 
+				  view->residual.x , view->residual.w);
+	y_map = gog_axis_map_new (plot->base.axis[1], 
+				  view->residual.y + view->residual.h, 
+				  -view->residual.h);
+
+	if (!(gog_axis_map_is_valid (x_map) &&
+	      gog_axis_map_is_valid (y_map))) {
+		gog_axis_map_free (x_map);
+		gog_axis_map_free (y_map);
+		return;
+	}
+
+	if (plot->plotted_data)
+		data = plot->plotted_data;
+	else
+		data = gog_xyz_plot_build_matrix (plot, &cw);
+
+	/* Set cw to ensure that polygons will allways be drawn clockwise */
+	xdiscrete = gog_axis_is_discrete (plot->base.axis[0]) ||
+			series->values[(plot->transposed)? 1: 0].data == NULL;
+	if (xdiscrete) {
+		x0 = gog_axis_map_to_view (x_map, 0.);
+		x1 = gog_axis_map_to_view (x_map, 1.);
+	}else {
+		x_vec = GO_DATA_VECTOR (series->values[(plot->transposed)? 1: 0].data);
+		x0 = gog_axis_map_to_view (x_map, go_data_vector_get_value (x_vec, 0));
+		x1 = gog_axis_map_to_view (x_map, go_data_vector_get_value (x_vec, 1));
+	}
+	ydiscrete = gog_axis_is_discrete (plot->base.axis[1]) ||
+			series->values[(plot->transposed)? 0: 1].data == NULL;
+	if (ydiscrete) {
+		y0 = gog_axis_map_to_view (y_map, 0.);
+		y1 = gog_axis_map_to_view (y_map, 1.);
+	}else {
+		y_vec = GO_DATA_VECTOR (series->values[(plot->transposed)? 0: 1].data);
+		y0 = gog_axis_map_to_view (y_map, go_data_vector_get_value (y_vec, 0));
+		y1 = gog_axis_map_to_view (y_map, go_data_vector_get_value (y_vec, 1));
+	}
+	cw = (x1 > x0) == (y1 > y0);
+
+	style = gog_style_new ();
+	path = art_new (ArtVpath, 10);
+	/* build the colors table */
+	color = g_new0 (GOColor, max);
+	if (max < 2)
+		color[0] = RGBA_WHITE;
+	else for (i = 0; i < (unsigned) max; i++) {
+		gog_theme_fillin_style (theme, style, GOG_OBJECT (series), i, FALSE);
+		color[i] = style->fill.pattern.back;
+	}
+	g_object_unref (style);
+
+	/* clip to avoid problems with logarithmic axes */
+	gog_renderer_push_clip_rectangle (rend, view->residual.x, view->residual.y,
+					  view->residual.w, view->residual.h);
+
+	style = gog_style_new ();
+	style->interesting_fields = GOG_STYLE_FILL | GOG_STYLE_OUTLINE;
+	style->disable_theming = GOG_STYLE_ALL;
+	style->fill.type = GOG_FILL_STYLE_PATTERN;
+	style->fill.pattern.pattern = GO_PATTERN_SOLID;
+	style->outline.dash_type = GO_LINE_SOLID;
+	style->outline.auto_dash = FALSE;
+	style->outline.auto_color = FALSE;
+	style->outline.width = 0.5;
+	style->outline.color = RGBA_BLACK;
+
+	lines = art_new (ArtVpath, lmax = 64);
+	l = 0;
+
+	for (j = 1; j < jmax; j++) {
+		if (xdiscrete) {
+			x0 = gog_axis_map_to_view (x_map, j);
+			x1 = gog_axis_map_to_view (x_map, j + 1);
+		}else {
+			x0 = gog_axis_map_to_view (x_map, go_data_vector_get_value (x_vec, j - 1));
+			x1 = gog_axis_map_to_view (x_map, go_data_vector_get_value (x_vec, j));
+		}
+		
+		for (i = 1; i < imax; i++) {
+			if (ydiscrete) {
+				y0 = gog_axis_map_to_view (y_map, i);
+				y1 = gog_axis_map_to_view (y_map, i + 1);
+			}else {
+				y0 = gog_axis_map_to_view (y_map, go_data_vector_get_value (y_vec, i - 1));
+				y1 = gog_axis_map_to_view (y_map, go_data_vector_get_value (y_vec, i));
+			}
+			nans = 0;
+			nan = 4;
+			zmin = max;
+			zmax = 0;
+			zval0 = data[(i - 1) * jmax + j - 1];
+			if (!isnan (zval0)) {
+				z0 = floor (zval0);
+				if (z0 > zmax)
+					zmax = z0;
+				if (z0 < zmin) {
+					zmin = z0;
+					r = 0;
+				}
+			} else {
+				nans++;
+				nan = 0;
+			}
+			zval1 = data[(i - 1) * jmax + j];
+			if (!isnan (zval1)) {
+				z1 = floor (zval1);
+				if (z1 > zmax)
+					zmax = z1;
+				if (z1 < zmin) {
+					zmin = z1;
+					r = 1;
+				}
+			} else {
+				nans++;
+				nan = 1;
+			}
+			zval2 = data[i * jmax + j];
+			if (!isnan (zval2)) {
+				z2 = floor (zval2);
+				if (z2 > zmax)
+					zmax = z2;
+				if (z2 < zmin) {
+					zmin = z2;
+					r = 2;
+				}
+			} else {
+				nans++;
+				nan = 2;
+			}
+			zval3 = data[i * jmax + j - 1];
+			if (!isnan (zval3)) {
+				z3 = floor (zval3);
+				if (z3 > zmax)
+					zmax = z3;
+				if (z3 < zmin) {
+					zmin = z3;
+					r = 3;
+				}
+			} else {
+				nans++;
+				nan = 3;
+			}
+			if (nans > 1)
+				continue;
+			/* Build the x, y and z arrays for the tile */
+			k = r;
+			s = 0;
+			do {
+				if (k != nan) {
+					switch (k) {
+					case 0:
+						x[s] = x0;
+						y[s] = y0;
+						z[s] = z0;
+						zval[s++] = zval0;
+						break;
+					case 1:
+						x[s] = x1;
+						y[s] = y0;
+						z[s] = z1;
+						zval[s++] = zval1;
+						break;
+					case 2:
+						x[s] = x1;
+						y[s] = y1;
+						z[s] = z2;
+						zval[s++] = zval2;
+						break;
+					default:
+						x[s] = x0;
+						y[s] = y1;
+						z[s] = z3;
+						zval[s++] = zval3;
+					}
+				}
+				if (cw) {
+					k++;
+					k %= 4;
+				} else {
+					if (k == 0)
+						k = 3;
+					else
+						k--;
+				}
+			} while (k != r);
+			if (zmin == zmax) {
+				/* paint everything with one color*/
+				style->outline.color = color[zmin];
+				style->fill.pattern.back = color[zmin];
+				gog_renderer_push_style (rend, style);
+				path[0].code = ART_MOVETO;
+				for (k = 0; k < s; ) {
+					path[k].x = x[k];
+					path[k].y = y[k];
+					path[++k].code = ART_LINETO;
+				}
+				path[k].x = x[0];
+				path[k].y = y[0];
+				path[k + 1].code = ART_END;
+				/* narrow parameter is TRUE below to avoid border effects */
+				gog_renderer_draw_polygon (rend, path, FALSE);
+				gog_renderer_pop_style (rend);
+			} else {
+				kmax = 3 - nans;
+				if (!nans && (((z0 < z1) && (z1 > z2) && (z2 < z3) && (z3 > z0)) ||
+					((z0 > z1) && (z1 < z2) && (z2 > z3) && (z3 < z0)))) {
+					/* we have a saddle point */
+					/* first find the most probable altitude of the saddle point */
+					int zn, zx;
+					gboolean crossing = FALSE, up = FALSE, odd;
+					double xl[8], yl[8];
+					/* crossing is TRUE if the saddle point occurs at a slices border */
+					zn = MAX (z[0], z[2]);
+					if (zval[1] > zval[3])
+						zx = (zval[3] == z[3])? z[3] - 1: z[3];
+					else
+						zx =  (zval[1] == z[1])? z[1] - 1: z[1];
+					odd = (zx - zn) % 2;
+					if (odd) {
+						if ((zx - zn) == 1) {
+							double sum = 0.;
+							sum += (z[0] == zn)? zval[0]: zn;
+							sum += (z[1] == zx)? zval[1]: zx + 1;
+							sum += (z[2] == zn)? zval[2]: zn;
+							sum += (z[3] == zx)? zval[3]: zx + 1;
+							sum /= 4.;
+							if (fabs ((sum - zx)) < DBL_EPSILON)
+								crossing = TRUE;
+							else
+								up = (sum - zx) < 0;
+						} else
+							crossing = TRUE;
+						zn = (zn + zx) / 2;
+						zx = zn + 1;
+					} else
+						zn = zx = (zn + zx) / 2;
+					/* low values slices */
+					if (z[0] < zn) {
+						k = z[0];
+						style->outline.color = color[k];
+						style->fill.pattern.back = color[k];
+						k++;
+						path[0].code = ART_MOVETO;
+						path[1].code = ART_LINETO;
+						path[2].code = ART_LINETO;
+						path[3].code = ART_LINETO;
+						path[4].code = ART_END;
+						path[0].x = path[3].x = x[0];
+						path[0].y = path[3].y = y[0];
+						if ((l + 3) >= lmax)
+							lines = art_renew (lines, ArtVpath, lmax += 64);
+						lines[l].code = ART_MOVETO_OPEN;
+						t = (k - zval[0]) / (zval[3] - zval[0]);
+						xl[7] = lines[l].x = path[1].x = x[0] + t * (x[3] - x[0]);
+						yl[7] = lines[l++].y = path[1].y = y[0] + t * (y[3] - y[0]);
+						lines[l].code = ART_LINETO;
+						t = (k - zval[0]) / (zval[1] - zval[0]);
+						xl[0] = lines[l].x = path[2].x = x[0] + t * (x[1] - x[0]);
+						yl[0] = lines[l++].y = path[2].y = y[0] + t * (y[1] - y[0]);
+						gog_renderer_push_style (rend, style);
+						gog_renderer_draw_polygon (rend, path, FALSE);
+						gog_renderer_pop_style (rend);
+						path[4].code = ART_LINETO;
+						path[5].code = ART_END;
+						while (k < zn) {
+							style->outline.color = color[k];
+							style->fill.pattern.back = color[k];
+							k++;
+							path[0].x = path[4].x = xl[7];
+							path[0].y = path[4].y = yl[7];
+							path[3].x = xl[0];
+							path[3].y = yl[0];
+							if ((l + 3) >= lmax)
+								lines = art_renew (lines, ArtVpath, lmax += 64);
+							lines[l].code = ART_MOVETO_OPEN;
+							t = (k - zval[0]) / (zval[3] - zval[0]);
+							xl[7] = lines[l].x = path[1].x = x[0] + t * (x[3] - x[0]);
+							yl[7] = lines[l++].y = path[1].y = y[0] + t * (y[3] - y[0]);
+							lines[l].code = ART_LINETO;
+							t = (k - zval[0]) / (zval[1] - zval[0]);
+							xl[0] = lines[l].x = path[2].x = x[0] + t * (x[1] - x[0]);
+							yl[0] = lines[l++].y = path[2].y = y[0] + t * (y[1] - y[0]);
+							gog_renderer_push_style (rend, style);
+							gog_renderer_draw_polygon (rend, path, FALSE);
+							gog_renderer_pop_style (rend);
+						}
+					} else
+						xl[0] = xl[7] = -1.;
+					if (z[2] < zn) {
+						k = z[2];
+						style->outline.color = color[k];
+						style->fill.pattern.back = color[k];
+						k++;
+						path[0].code = ART_MOVETO;
+						path[1].code = ART_LINETO;
+						path[2].code = ART_LINETO;
+						path[3].code = ART_LINETO;
+						path[4].code = ART_END;
+						path[0].x = path[3].x = x[2];
+						path[0].y = path[3].y = y[2];
+						if ((l + 3) >= lmax)
+							lines = art_renew (lines, ArtVpath, lmax += 64);
+						lines[l].code = ART_MOVETO_OPEN;
+						t = (k - zval[2]) / (zval[1] - zval[2]);
+						xl[3] = lines[l].x = path[1].x = x[2] + t * (x[1] - x[2]);
+						yl[3] = lines[l++].y = path[1].y = y[2] + t * (y[1] - y[2]);
+						lines[l].code = ART_LINETO;
+						t = (k - zval[2]) / (zval[3] - zval[2]);
+						xl[4] = lines[l].x = path[2].x = x[2] + t * (x[3] - x[2]);
+						yl[4] = lines[l++].y = path[2].y = y[2] + t * (y[3] - y[2]);
+						gog_renderer_push_style (rend, style);
+						gog_renderer_draw_polygon (rend, path, FALSE);
+						gog_renderer_pop_style (rend);
+						path[4].code = ART_LINETO;
+						path[5].code = ART_END;
+						while (k < zn) {
+							style->outline.color = color[k];
+							style->fill.pattern.back = color[k];
+							k++;
+							path[0].x = path[4].x = xl[3];
+							path[0].y = path[4].y = yl[3];
+							path[3].x = xl[4];
+							path[3].y = yl[4];
+							if ((l + 3) >= lmax)
+								lines = art_renew (lines, ArtVpath, lmax += 64);
+							lines[l].code = ART_MOVETO_OPEN;
+							t = (k - zval[2]) / (zval[1] - zval[2]);
+							xl[3] = lines[l].x = path[1].x = x[2] + t * (x[1] - x[2]);
+							yl[3] = lines[l++].y = path[1].y = y[2] + t * (y[1] - y[2]);
+							lines[l].code = ART_LINETO;
+							t = (k - zval[2]) / (zval[3] - zval[2]);
+							xl[4] = lines[l].x = path[2].x = x[2] + t * (x[3] - x[2]);
+							yl[4] = lines[l++].y = path[2].y = y[2] + t * (y[3] - y[2]);
+							gog_renderer_push_style (rend, style);
+							gog_renderer_draw_polygon (rend, path, FALSE);
+							gog_renderer_pop_style (rend);
+						}
+					} else
+						xl[3] = xl[4] = -1.;
+					/* high values slices */
+					k = z[1];
+					if (zval[1] == k)
+						k--;
+					if (k > zx) {
+						path[0].code = ART_MOVETO;
+						path[1].code = ART_LINETO;
+						path[2].code = ART_LINETO;
+						path[3].code = ART_LINETO;
+						path[4].code = ART_END;
+						path[0].x = path[3].x = x[1];
+						path[0].y = path[3].y = y[1];
+						if ((l + 3) >= lmax)
+							lines = art_renew (lines, ArtVpath, lmax += 64);
+						lines[l].code = ART_MOVETO_OPEN;
+						t = (k - zval[1]) / (zval[0] - zval[1]);
+						xl[1] = lines[l].x = path[1].x = x[1] + t * (x[0] - x[1]);
+						yl[1] = lines[l++].y = path[1].y = y[1] + t * (y[0] - y[1]);
+						lines[l].code = ART_LINETO;
+						t = (k - zval[1]) / (zval[2] - zval[1]);
+						xl[2] = lines[l].x = path[2].x = x[1] + t * (x[2] - x[1]);
+						yl[2] = lines[l++].y = path[2].y = y[1] + t * (y[2] - y[1]);
+						style->outline.color = color[k];
+						style->fill.pattern.back = color[k];
+						gog_renderer_push_style (rend, style);
+						gog_renderer_draw_polygon (rend, path, FALSE);
+						gog_renderer_pop_style (rend);
+						path[4].code = ART_LINETO;
+						path[5].code = ART_END;
+						k--;
+						while (k > zx) {
+							path[0].x = path[4].x = xl[1];
+							path[0].y = path[4].y = yl[1];
+							path[3].x = xl[2];
+							path[3].y = yl[2];
+							if ((l + 3) >= lmax)
+								lines = art_renew (lines, ArtVpath, lmax += 64);
+							lines[l].code = ART_MOVETO_OPEN;
+							t = (k - zval[1]) / (zval[0] - zval[1]);
+							xl[1] = lines[l].x = path[1].x = x[1] + t * (x[0] - x[1]);
+							yl[1] = lines[l++].y = path[1].y = y[1] + t * (y[0] - y[1]);
+							lines[l].code = ART_LINETO;
+							t = (k - zval[1]) / (zval[2] - zval[1]);
+							xl[2] = lines[l].x = path[2].x = x[1] + t * (x[2] - x[1]);
+							yl[2] = lines[l++].y = path[2].y = y[1] + t * (y[2] - y[1]);
+							style->outline.color = color[k];
+							style->fill.pattern.back = color[k];
+							gog_renderer_push_style (rend, style);
+							gog_renderer_draw_polygon (rend, path, FALSE);
+							gog_renderer_pop_style (rend);
+							k--;
+						}
+					} else
+						xl[1] = xl[2] = -1.;
+					k = z[3];
+					if (zval[3] == k)
+						k--;
+					if (k > zx) {
+						path[0].code = ART_MOVETO;
+						path[1].code = ART_LINETO;
+						path[2].code = ART_LINETO;
+						path[3].code = ART_LINETO;
+						path[4].code = ART_END;
+						path[0].x = path[3].x = x[3];
+						path[0].y = path[3].y = y[3];
+						if ((l + 3) >= lmax)
+							lines = art_renew (lines, ArtVpath, lmax += 64);
+						lines[l].code = ART_MOVETO_OPEN;
+						t = (k - zval[3]) / (zval[2] - zval[3]);
+						xl[5] = lines[l].x = path[1].x = x[3] + t * (x[2] - x[3]);
+						yl[5] = lines[l++].y = path[1].y = y[3] + t * (y[2] - y[3]);
+						lines[l].code = ART_LINETO;
+						t = (k - zval[3]) / (zval[0] - zval[3]);
+						xl[6] = lines[l].x = path[2].x = x[3] + t * (x[0] - x[3]);
+						yl[6] = lines[l++].y = path[2].y = y[3] + t * (y[0] - y[3]);
+						style->outline.color = color[k];
+						style->fill.pattern.back = color[k];
+						gog_renderer_push_style (rend, style);
+						gog_renderer_draw_polygon (rend, path, FALSE);
+						gog_renderer_pop_style (rend);
+						path[4].code = ART_LINETO;
+						path[5].code = ART_END;
+						k--;
+						while (k > zx) {
+							path[0].x = path[4].x = xl[5];
+							path[0].y = path[4].y = yl[5];
+							path[3].x = xl[6];
+							path[3].y = yl[6];
+							if ((l + 3) >= lmax)
+								lines = art_renew (lines, ArtVpath, lmax += 64);
+							lines[l].code = ART_MOVETO_OPEN;
+							t = (k - zval[3]) / (zval[2] - zval[3]);
+							xl[5] = lines[l].x = path[1].x = x[3] + t * (x[2] - x[3]);
+							yl[5] = lines[l++].y = path[1].y = y[3] + t * (y[2] - y[3]);
+							lines[l].code = ART_LINETO;
+							t = (k - zval[3]) / (zval[0] - zval[3]);
+							xl[6] = lines[l].x = path[2].x = x[3] + t * (x[0] - x[3]);
+							yl[6] = lines[l++].y = path[2].y = y[3] + t * (y[0] - y[3]);
+							style->outline.color = color[k];
+							style->fill.pattern.back = color[k];
+							gog_renderer_push_style (rend, style);
+							gog_renderer_draw_polygon (rend, path, FALSE);
+							gog_renderer_pop_style (rend);
+							k--;
+						}
+					} else
+						xl[5] = xl[6] = -1.;
+					/* middle values slices */
+					if (odd) {
+						if (crossing) {
+							double xb[4], yb[4], xc, yc;
+							for (k = 0; k < 4; k++) {
+								s = (k + 1) % 4;
+								t =  (zx - zval[s]) / (zval[k] - zval[s]);
+								xb[k] = x[s] + t * (x[k] - x[s]);
+								yb[k] = y[s] + t * (y[k] - y[s]);
+							}
+							if ((l + 5) >= lmax)
+								lines = art_renew (lines, ArtVpath, lmax += 64);
+							lines[l].code = ART_MOVETO_OPEN;
+							lines[l].x = xb[0];
+							lines[l++].y = yb[0];
+							lines[l].code = ART_LINETO;
+							lines[l].x = xb[2];
+							lines[l++].y = yb[2];
+							lines[l].code = ART_MOVETO_OPEN;
+							lines[l].x = xb[1];
+							lines[l++].y = yb[1];
+							lines[l].code = ART_LINETO;
+							lines[l].x = xb[3];
+							lines[l++].y = yb[3];
+							/* calculate the coordinates xc and yc of crossing point */
+							t = ((xb[1] - xb[0]) * (yb[3] - yb[1])
+								+ (xb[1] - xb[3]) * (yb[1] - yb[0])) /
+								((xb[2] - xb[0]) * (yb[3] - yb[1])
+								+ (xb[1] - xb[3]) * (yb[2] - yb[0]));
+							xc = xb[0] + t * (xb[2] - xb[0]);
+							yc = yb[0] + t * (yb[2] - yb[0]);
+							/* fill */
+							path[0].code = ART_MOVETO;
+							path[1].code = ART_LINETO;
+							path[2].code = ART_LINETO;
+							path[3].code = ART_LINETO;
+							path[4].code = ART_LINETO;
+							if (xl[0] < 0.) {
+								path[4].x = path[0].x = x[0];
+								path[4].y = path[0].y = y[0];
+								path[5].code = ART_END;
+							} else {
+								path[5].x = path[0].x = xl[7];
+								path[5].y = path[0].y = yl[7];
+								path[4].x = xl[0];
+								path[4].y = yl[0];
+								path[5].code = ART_LINETO;
+								path[6].code = ART_END;
+							}
+							path[1].x = xb[3];
+							path[1].y = yb[3];
+							path[2].x = xc;
+							path[2].y = yc;
+							path[3].x = xb[0];
+							path[3].y = yb[0];
+							style->outline.color = color[zn];
+							style->fill.pattern.back = color[zn];
+							gog_renderer_push_style (rend, style);
+							gog_renderer_draw_polygon (rend, path, FALSE);
+							if (xl[2] < 0.) {
+								path[4].x = path[0].x = x[2];
+								path[4].y = path[0].y = y[2];
+								path[5].code = ART_END;
+							} else {
+								path[5].x = path[0].x = xl[3];
+								path[5].y = path[0].y = yl[3];
+								path[4].x = xl[4];
+								path[4].y = yl[4];
+								path[5].code = ART_LINETO;
+								path[6].code = ART_END;
+							}
+							path[1].x = xb[1];
+							path[1].y = yb[1];
+							path[3].x = xb[2];
+							path[3].y = yb[2];
+							gog_renderer_draw_polygon (rend, path, FALSE);
+							gog_renderer_pop_style (rend);
+							if (xl[2] < 0.) {
+								path[4].x = path[0].x = x[1];
+								path[4].y = path[0].y = y[1];
+								path[5].code = ART_END;
+							} else {
+								path[5].x = path[0].x = xl[1];
+								path[5].y = path[0].y = yl[1];
+								path[4].x = xl[2];
+								path[4].y = yl[2];
+								path[5].code = ART_LINETO;
+								path[6].code = ART_END;
+							}
+							path[1].x = xb[0];
+							path[1].y = yb[0];
+							path[3].x = xb[1];
+							path[3].y = yb[1];
+							style->outline.color = color[zx];
+							style->fill.pattern.back = color[zx];
+							gog_renderer_push_style (rend, style);
+							gog_renderer_draw_polygon (rend, path, FALSE);
+							if (xl[6] < 0.) {
+								path[4].x = path[0].x = x[3];
+								path[4].y = path[0].y = y[3];
+								path[5].code = ART_END;
+							} else {
+								path[5].x = path[0].x = xl[5];
+								path[5].y = path[0].y = yl[5];
+								path[4].x = xl[6];
+								path[4].y = yl[6];
+								path[5].code = ART_LINETO;
+								path[6].code = ART_END;
+							}
+							path[1].x = xb[2];
+							path[1].y = yb[2];
+							path[3].x = xb[3];
+							path[3].y = yb[3];
+							gog_renderer_draw_polygon (rend, path, FALSE);
+							gog_renderer_pop_style (rend);
+						} else {
+							if (up) {
+								/* saddle point is in the lower slice */
+								/* draw the upper slices */
+								path[0].code = ART_MOVETO;
+								path[1].code = ART_LINETO;
+								path[2].code = ART_LINETO;
+								path[3].code = ART_LINETO;
+								if (xl[1] < 0.) {
+									path[4].code = ART_END;
+									path[0].x = path[3].x = x[1];
+									path[0].y = path[3].y = y[1];
+								} else {
+									path[4].code = ART_LINETO;
+									path[5].code = ART_END;
+									path[0].x = path[4].x = xl[1];
+									path[0].y = path[4].y = yl[1];
+									path[3].x = xl[2];
+									path[3].y = yl[2];
+								}
+								if ((l + 5) >= lmax)
+									lines = art_renew (lines, ArtVpath, lmax += 64);
+								lines[l].code = ART_MOVETO_OPEN;
+								t = (zx - zval[1]) / (zval[0] - zval[1]);
+								xl[1] = lines[l].x = path[1].x = x[1] + t * (x[0] - x[1]);
+								yl[1] = lines[l++].y = path[1].y = y[1] + t * (y[0] - y[1]);
+								lines[l].code = ART_LINETO;
+								t = (zx - zval[1]) / (zval[2] - zval[1]);
+								xl[2] = lines[l].x = path[2].x = x[1] + t * (x[2] - x[1]);
+								yl[2] = lines[l++].y = path[2].y = y[1] + t * (y[2] - y[1]);
+								style->outline.color = color[zx];
+								style->fill.pattern.back = color[zx];
+								gog_renderer_push_style (rend, style);
+								gog_renderer_draw_polygon (rend, path, FALSE);
+								if (xl[5] < 0.) {
+									path[4].code = ART_END;
+									path[0].x = path[3].x = x[3];
+									path[0].y = path[3].y = y[3];
+								} else {
+									path[4].code = ART_LINETO;
+									path[5].code = ART_END;
+									path[0].x = path[4].x = xl[5];
+									path[0].y = path[4].y = yl[5];
+									path[3].x = xl[6];
+									path[3].y = yl[6];
+								}
+								if ((l + 5) >= lmax)
+									lines = art_renew (lines, ArtVpath, lmax += 64);
+								lines[l].code = ART_MOVETO_OPEN;
+								t = (zx - zval[3]) / (zval[2] - zval[3]);
+								xl[5] = lines[l].x = path[1].x = x[3] + t * (x[2] - x[3]);
+								yl[5] = lines[l++].y = path[1].y = y[3] + t * (y[2] - y[3]);
+								lines[l].code = ART_LINETO;
+								t = (zx - zval[3]) / (zval[0] - zval[3]);
+								xl[6] = lines[l].x = path[2].x = x[3] + t * (x[0] - x[3]);
+								yl[6] = lines[l++].y = path[2].y = y[3] + t * (y[0] - y[3]);
+								gog_renderer_draw_polygon (rend, path, FALSE);
+								gog_renderer_pop_style (rend);
+							} else {
+								/* saddle point is in the upper slice */
+								path[0].code = ART_MOVETO;
+								path[1].code = ART_LINETO;
+								path[2].code = ART_LINETO;
+								path[3].code = ART_LINETO;
+								if (xl[0] < 0.) {
+									path[4].code = ART_END;
+									path[0].x = path[3].x = x[0];
+									path[0].y = path[3].y = y[0];
+								} else {
+									path[4].code = ART_LINETO;
+									path[5].code = ART_END;
+									path[0].x = path[4].x = xl[7];
+									path[0].y = path[4].y = yl[7];
+									path[3].x = xl[0];
+									path[3].y = yl[0];
+								}
+								if ((l + 5) >= lmax)
+									lines = art_renew (lines, ArtVpath, lmax += 64);
+								lines[l].code = ART_MOVETO_OPEN;
+								t = (k - zval[0]) / (zval[3] - zval[0]);
+								xl[7] = lines[l].x = path[1].x = x[0] + t * (x[3] - x[0]);
+								yl[7] = lines[l++].y = path[1].y = y[0] + t * (y[3] - y[0]);
+								lines[l].code = ART_LINETO;
+								t = (k - zval[0]) / (zval[1] - zval[0]);
+								xl[0] = lines[l].x = path[2].x = x[0] + t * (x[1] - x[0]);
+								yl[0] = lines[l++].y = path[2].y = y[0] + t * (y[1] - y[0]);
+								style->outline.color = color[zn];
+								style->fill.pattern.back = color[zn];
+								gog_renderer_push_style (rend, style);
+								gog_renderer_draw_polygon (rend, path, FALSE);
+								if (xl[4] < 0.) {
+									path[4].code = ART_END;
+									path[0].x = path[3].x = x[2];
+									path[0].y = path[3].y = y[2];
+								} else {
+									path[4].code = ART_LINETO;
+									path[5].code = ART_END;
+									path[0].x = path[4].x = xl[3];
+									path[0].y = path[4].y = yl[3];
+									path[3].x = xl[4];
+									path[3].y = yl[4];
+								}
+								lines[l].code = ART_MOVETO_OPEN;
+								t = (k - zval[2]) / (zval[1] - zval[2]);
+								xl[3] = lines[l].x = path[1].x = x[2] + t * (x[1] - x[2]);
+								yl[3] = lines[l++].y = path[1].y = y[2] + t * (y[1] - y[2]);
+								lines[l].code = ART_LINETO;
+								t = (k - zval[2]) / (zval[3] - zval[2]);
+								xl[4] = lines[l].x = path[2].x = x[2] + t * (x[3] - x[2]);
+								yl[4] = lines[l++].y = path[2].y = y[2] + t * (y[3] - y[2]);
+								gog_renderer_draw_polygon (rend, path, FALSE);
+								gog_renderer_pop_style (rend);
+								zn = zx;
+							}
+							/* draw the saddle containing slice */
+							k = 0;
+							for (s = 0; s < 8; s++) {
+								path[k].code = (k)? ART_LINETO: ART_MOVETO;
+								if (xl[s] < 0.) {
+									if (s == 7)
+										break;
+									else if (s > 0)
+										s++;
+									r = s / 2;
+									path[k].x = x[r];
+									path[k++].y = y[r];
+								} else {
+									path[k].x = xl[s];
+									path[k++].y = yl[s];
+								}
+							}
+							path[k].code = ART_LINETO;
+							path[k].x = path[0].x;
+							path[k++].y = path[0].y;
+							path[k].code = ART_END;
+							style->outline.color = color[zn];
+							style->fill.pattern.back = color[zn];
+							gog_renderer_push_style (rend, style);
+							gog_renderer_draw_polygon (rend, path, FALSE);
+							gog_renderer_pop_style (rend);
+						}
+					} else {
+						k = 0;
+						for (s = 0; s < 8; s++) {
+							path[k].code = (k)? ART_LINETO: ART_MOVETO;
+							if (xl[s] < 0.) {
+								if (s == 7)
+									break;
+								else if (s > 0)
+									s++;
+								r = s / 2;
+								path[k].x = x[r];
+								path[k++].y = y[r];
+							} else {
+								path[k].x = xl[s];
+								path[k++].y = yl[s];
+							}
+						}
+						path[k].code = ART_LINETO;
+						path[k].x = path[0].x;
+						path[k++].y = path[0].y;
+						path[k].code = ART_END;
+						style->outline.color = color[zx];
+						style->fill.pattern.back = color[zx];
+						gog_renderer_push_style (rend, style);
+						gog_renderer_draw_polygon (rend, path, FALSE);
+						gog_renderer_pop_style (rend);
+					}
+				} else {
+					/* no saddle point visible */
+					if ((l + (zmax - zmin) * 2 + 1) >= lmax)
+						lines = art_renew (lines, ArtVpath, lmax += 64);
+					path[0].code = ART_MOVETO;
+					path[0].x = x[0];
+					path[0].y = y[0];
+					p = 1;
+					k = 1;
+					s = 0;
+					r = kmax;
+					while (zmin < zmax) {
+						style->outline.color = color[zmin];
+						style->fill.pattern.back = color[zmin];
+						gog_renderer_push_style (rend, style);
+						while (z[k] <= zmin && k < kmax) {
+							if (fabs (path[p-1].x - x[k]) > CONTOUR_EPSILON ||
+								fabs (path[p-1].y - y[k]) > CONTOUR_EPSILON) {
+								path[p].code = ART_LINETO;
+								path[p].x = x[k];
+								path[p++].y = y[k++];
+							} else
+								k++;	
+						}
+						while (z[r] <= zmin && r > 0)
+							r--;
+						zmin++;
+						t = (zmin - zval[k - 1]) / (zval[k] - zval[k - 1]);
+						path[p].code = ART_LINETO;
+						lines[l].code = ART_MOVETO_OPEN;
+						lines[l].x = path[p].x = x[k - 1] + t * (x[k] - x[k - 1]);
+						lines[l++].y = path[p].y = y[k - 1] + t * (y[k] - y[k - 1]);
+						if (fabs (path[p-1].x - path[p].x) > CONTOUR_EPSILON ||
+							fabs (path[p-1].y - path[p].y) > CONTOUR_EPSILON)
+							p++;
+						path[p].code = ART_LINETO;
+						lines[l].code = ART_LINETO;
+						if (r < kmax) {
+							t = (zmin - zval[r]) / (zval[r + 1] - zval[r]);
+							lines[l].x = path[p].x = x[r] + t * (x[r + 1] - x[r]);
+							lines[l++].y = path[p].y = y[r] + t * (y[r + 1] - y[r]);
+						} else {
+							t = (zmin - zval[r]) / (zval[0] - zval[r]);
+							lines[l].x = path[p].x = x[r] + t * (x[0] - x[r]);
+							lines[l++].y = path[p].y = y[r] + t * (y[0] - y[r]);
+						}
+						if (fabs (path[p-1].x - path[p].x) > CONTOUR_EPSILON ||
+							fabs (path[p-1].y - path[p].y) > CONTOUR_EPSILON)
+							p++;
+						if (s == 0) {
+							for (h = r + 1; h <= kmax; h++) {
+								if (fabs (path[p-1].x - x[h]) > CONTOUR_EPSILON ||
+									fabs (path[p-1].y - y[h]) > CONTOUR_EPSILON) {
+									path[p].code = ART_LINETO;
+									path[p].x = x[h];
+									path[p++].y = y[h];
+								}
+							}
+						} else {
+							for (h = r + 1; h < s; h++) {
+								if (fabs (path[p-1].x - x[h]) > CONTOUR_EPSILON ||
+									fabs (path[p-1].y - y[h]) > CONTOUR_EPSILON) {
+									path[p].code = ART_LINETO;
+									path[p].x = x[h];
+									path[p++].y = y[h];
+								}
+							}
+						}
+						s = r + 1;
+						if (fabs (path[p-1].x - path[0].x) > CONTOUR_EPSILON ||
+							fabs (path[p-1].y -path[0].y) > CONTOUR_EPSILON) {
+							path[p].code = ART_LINETO;
+							path[p].x = path[0].x;
+							path[p++].y = path[0].y;
+						} else {
+							/* use the exact values so that the polygon is closed */
+							path[p-1].x = path[0].x;
+							path[p-1].y = path[0].y;
+						}
+						path[p].code = ART_END;
+						gog_renderer_draw_polygon (rend, path, FALSE);
+						gog_renderer_pop_style (rend);
+						path[0].x = lines[l - 1].x;
+						path[0].y = lines[l - 1].y;
+						path[1].x = lines[l - 2].x;
+						path[1].y = lines[l - 2].y;
+						p = (fabs (path[0].x - path[1].x) > CONTOUR_EPSILON ||
+							fabs (path[0].y - path[1].y) > CONTOUR_EPSILON)?
+							2: 1;
+					}
+					if (fabs (path[0].x - path[1].x) < CONTOUR_EPSILON
+						&& fabs (path[0].y - path[1].y) < CONTOUR_EPSILON)
+						continue;
+					while (k < s) {
+						path[p].code = ART_LINETO;
+						path[p].x = x[k];
+						path[p++].y = y[k++];
+					}
+					path[p].code = ART_LINETO;
+					path[p].x = path[0].x;
+					path[p++].y = path[0].y;
+					path[p].code = ART_END;
+					style->outline.color = color[zmin];
+					style->fill.pattern.back = color[zmin];
+					gog_renderer_push_style (rend, style);
+					gog_renderer_draw_polygon (rend, path, FALSE);
+					gog_renderer_pop_style (rend);
+				}
+			}
+		}
+	}
+	lines[l].code = ART_END;
+	gog_renderer_push_style (rend, GOG_STYLED_OBJECT (series)->style);
+	gog_renderer_draw_path  (rend, lines);
+	gog_renderer_pop_style (rend);
+	gog_renderer_pop_clip (rend);
+	art_free (lines);
+	art_free (path);
+	g_object_unref (style);
+	gog_axis_map_free (x_map);
+	gog_axis_map_free (y_map);
+}
+
+static void
+gog_contour_view_class_init (GogViewClass *view_klass)
+{
+	view_klass->render = gog_contour_view_render;
+}
+
+GSF_DYNAMIC_CLASS (GogContourView, gog_contour_view,
+	gog_contour_view_class_init, NULL,
+	GOG_PLOT_VIEW_TYPE)
+

Added: trunk/plugins/plot_surface/gog-contour.h
==============================================================================
--- (empty file)
+++ trunk/plugins/plot_surface/gog-contour.h	Mon May 12 09:02:12 2008
@@ -0,0 +1,50 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * gog-contour.h
+ *
+ * Copyright (C) 2004-2007 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 GOG_CONTOUR_H
+#define GOG_CONTOUR_H
+
+#include "gog-xyz.h"
+
+G_BEGIN_DECLS
+
+/*-----------------------------------------------------------------------------
+ *
+ * GogContourPlot
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+typedef GogXYZPlot GogContourPlot;
+typedef GogXYZPlotClass GogContourPlotClass;
+
+#define GOG_CONTOUR_PLOT_TYPE	(gog_contour_plot_get_type ())
+#define GOG_CONTOUR_PLOT(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOG_CONTOUR_PLOT_TYPE, GogContourPlot))
+#define GOG_IS_PLOT_CONTOUR(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOG_CONTOUR_PLOT_TYPE))
+
+GType gog_contour_plot_get_type (void);
+void  gog_contour_plot_register_type   (GTypeModule *module);
+
+void  gog_contour_view_register_type   (GTypeModule *module);
+
+G_END_DECLS
+
+#endif /* GOG_CONTOUR_H */

Modified: trunk/plugins/plot_surface/gog-surface.c
==============================================================================
--- trunk/plugins/plot_surface/gog-surface.c	(original)
+++ trunk/plugins/plot_surface/gog-surface.c	Mon May 12 09:02:12 2008
@@ -21,1548 +21,222 @@
 
 #include <goffice/goffice-config.h>
 #include "gog-surface.h"
-#include "xl-surface.h"
 
 #include <goffice/data/go-data.h>
-#include <goffice/graph/gog-axis.h>
-#include <goffice/graph/gog-chart.h>
+#include <goffice/graph/gog-chart-map-3d.h>
 #include <goffice/graph/gog-renderer.h>
-#include <goffice/graph/gog-theme.h>
-#include <goffice/math/go-math.h>
-#include <goffice/utils/go-format.h>
-#include <goffice/utils/go-color.h>
-#include <goffice/app/module-plugin-defs.h>
+#include <goffice/utils/go-path.h>
 
 #include <glib/gi18n-lib.h>
 #include <gsf/gsf-impl-utils.h>
 
-#include <locale.h>
-#include <string.h>
-
-GOFFICE_PLUGIN_MODULE_HEADER;
-
-enum {
-	CONTOUR_PROP_0,
-	CONTOUR_PROP_TRANSPOSED
-};
-
-#define EPSILON 1e-13
-
-static GogObjectClass *plot_contour_parent_klass;
-
-typedef struct {
-	GogSeries base;
-	
-	unsigned rows, columns;
-} GogSurfaceSeries;
-typedef GogSeriesClass GogSurfaceSeriesClass;
-
-#define GOG_SURFACE_SERIES_TYPE	(gog_surface_series_get_type ())
-#define GOG_SURFACE_SERIES(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOG_SURFACE_SERIES_TYPE, GogSurfaceSeries))
-#define GOG_IS_SURFACE_SERIES(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOG_SURFACE_SERIES_TYPE))
-
-static GType gog_surface_series_get_type (void);
-static GType gog_contour_view_get_type (void);
-
-static gboolean
-vary_uniformly (GODataVector *vec)
-{
-	int len = go_data_vector_get_len (vec), i = 0;
-	double x, x0;
-	if (len < 2)
-		return TRUE;
-	x0 = go_data_vector_get_value (vec, 0);
-	x = go_data_vector_get_value (vec, 1);
-	if (!go_finite( x0) || !go_finite (x))
-		return FALSE;
-	if (x > x0) {
-		for (i = 2; i < len; i++) {
-			x0 = go_data_vector_get_value (vec, i);
-			if (!go_finite (x0) || (x0 <= x))
-				return FALSE;
-			x = x0;
-		}
-	} else if (x < x0) {
-		for (i = 2; i < len; i++) {
-			x0 = go_data_vector_get_value (vec, i);
-			if (!go_finite (x0) || (x0 >= x))
-				return FALSE;
-			x = x0;
-		}
-	}
-	return TRUE;
-}
-
-/*-----------------------------------------------------------------------------
- *
- *  GogContourPlot
- *
- *-----------------------------------------------------------------------------
- */
-
-/**
- * gog_contour_plot_build_matrix :
- * @plot :
- *
- * builds a table of normalized values: first slice = 0-1 second = 1-2,...
- **/
+/*****************************************************************************/
 
-static double *
-gog_contour_plot_build_matrix (GogContourPlot const *plot, gboolean *cardinality_changed)
-{
-	GogContourPlotClass *klass = GOG_CONTOUR_PLOT_GET_CLASS (plot);
-	return klass->build_matrix (plot, cardinality_changed);
-}
+static GType gog_surface_view_get_type (void);
 
 static double *
-gog_contour_plot_real_build_matrix (GogContourPlot const *plot, gboolean *cardinality_changed)
+gog_surface_plot_build_matrix (GogXYZPlot const *plot, gboolean *cardinality_changed)
 {
 	unsigned i, j;
-	GogAxisMap *map;
-	GogAxisTick *zticks;
-	GogAxis *axis = plot->base.axis[GOG_AXIS_PSEUDO_3D];
-	unsigned nticks;
-	double *x, val;
+	double val;
 	GogSeries *series = GOG_SERIES (plot->base.series->data);
 	GODataMatrix *mat = GO_DATA_MATRIX (series->values[2].data);
 	unsigned n = plot->rows * plot->columns;
-	double *data, minimum, maximum, slope, offset = 0.;
-	unsigned max;
+	double *data;
 
-	if (!gog_axis_get_bounds (axis, &minimum, &maximum))
-		return NULL;
 	data = g_new (double, n);
-	nticks = gog_axis_get_ticks (axis, &zticks);
-	map = gog_axis_map_new (axis, 0, 1);
-	x = g_new (double, nticks);
-	for (i = j = 0; i < nticks; i++)
-		if (zticks[i].type == GOG_AXIS_TICK_MAJOR) {
-			x[j++] = gog_axis_map_to_view (map, zticks[i].position);
-		}
-	max = --j;
-	if (x[1] > x[0]) {
-		if (x[0] > EPSILON) {
-			offset = 1.;
-			max++;
-		}
-		if (x[j] < 1. - EPSILON)
-			max++;
-		slope = 1 / (x[1] - x[0]);
-	} else {
-		offset = j;
-		if (x[0] < 1. - EPSILON)
-			max++;
-		if (x[j] > EPSILON) {
-			max++;
-			offset += 1.;
-		}
-		slope = 1 / (x[0] - x[1]);
-	}
 
 	for (i = 0; i < plot->rows; i++)
 		for (j = 0; j < plot->columns; j++) {
-			val = gog_axis_map_to_view (map,
-					go_data_matrix_get_value (mat, i, j));
-			if (fabs (val) == DBL_MAX)
-				val = go_nan;
-			else {
-				val = offset + slope * (val - x[0]);
-				if (val < 0)
-					val = (val < -EPSILON)? go_nan: 0.;
-			}
+			val = go_data_matrix_get_value (mat, i, j);
 			if (plot->transposed)
 				data[j * plot->rows + i] = val;
 			else
 				data[i * plot->columns + j] = val;
 		}
-	if (series->num_elements != max) {
-		series->num_elements = max;
-		*cardinality_changed = TRUE;
-	}
-	gog_axis_map_free (map);
-	g_free (x);
+	*cardinality_changed = FALSE;
 	return data;
 }
 
-static void
-gog_contour_plot_update_3d (GogPlot *plot)
-{
-	GogContourPlot *contour = GOG_CONTOUR_PLOT (plot);
-	gboolean cardinality_changed = FALSE;
-
-	if (plot->series == NULL)
-		return;
-
-	contour->plotted_data = gog_contour_plot_build_matrix (contour, &cardinality_changed);
-	if (cardinality_changed) {
-		/*	gog_plot_request_cardinality_update can't be called from here
-		 *  since the plot might be updating.
-		 */
-		GogChart *chart = GOG_CHART (GOG_OBJECT (plot)->parent);
-		plot->cardinality_valid = FALSE;
-		if (chart != NULL)
-			gog_chart_request_cardinality_update (chart);
-	}
-}
-
 static char const *
-gog_contour_plot_type_name (G_GNUC_UNUSED GogObject const *item)
+gog_surface_plot_type_name (G_GNUC_UNUSED GogObject const *item)
 {
-	/* xgettext : the base for how to name contour plot objects
+	/* xgettext : the base for how to name surface plot objects
 	*/
-	return N_("PlotContour");
-}
-
-extern gpointer gog_contour_plot_pref (GogContourPlot *plot, GOCmdContext *cc);
-static void
-gog_contour_plot_populate_editor (GogObject *item,
-				  GogEditor *editor,
-				  G_GNUC_UNUSED GogDataAllocator *dalloc,
-				  GOCmdContext *cc)
-{
-	gog_editor_add_page (editor,
-			     gog_contour_plot_pref (GOG_CONTOUR_PLOT (item), cc),
-			     _("Properties"));
-
-	(GOG_OBJECT_CLASS (plot_contour_parent_klass)->populate_editor) (item, editor, dalloc, cc);
+	return N_("PlotSurface");
 }
 
 static void
-gog_contour_plot_clear_formats (GogContourPlot *plot)
-{
-	if (plot->x.fmt != NULL) {
-		go_format_unref (plot->x.fmt);
-		plot->x.fmt = NULL;
-	}
-	if (plot->y.fmt != NULL) {
-		go_format_unref (plot->y.fmt);
-		plot->y.fmt = NULL;
-	}
-	if (plot->z.fmt != NULL) {
-		go_format_unref (plot->z.fmt);
-		plot->z.fmt = NULL;
-	}
-}
-
-static void
-gog_contour_plot_update (GogObject *obj)
-{
-	GogContourPlot * model = GOG_CONTOUR_PLOT(obj);
-	GogSurfaceSeries * series;
-	GODataVector *vec;
-	GODataMatrix *mat;
-	double tmp_min, tmp_max;
-
-	if (model->base.series == NULL)
-		return;
-
-	series = GOG_SURFACE_SERIES (model->base.series->data);
-	if (!gog_series_is_valid (GOG_SERIES (series)))
-		return;
-
-	if ((vec = GO_DATA_VECTOR (series->base.values[0].data)) != NULL) {
-		if (model->x.fmt == NULL)
-			model->x.fmt = go_data_preferred_fmt (series->base.values[0].data);
-		if (vary_uniformly (vec))
-			go_data_vector_get_minmax (vec, &tmp_min, &tmp_max);
-		else
-			tmp_min = tmp_max = go_nan;
-	} else {
-		tmp_min = 0;
-		tmp_max = series->columns - 1;
-	}
-
-	if ((model->columns != series->columns)
-			|| (tmp_min != model->x.minima)
-			|| (tmp_max != model->x.maxima)) {
-		model->columns = series->columns;
-		model->x.minima = tmp_min;
-		model->x.maxima = tmp_max;
-		gog_axis_bound_changed (model->base.axis[(model->transposed)? GOG_AXIS_Y: GOG_AXIS_X],
-				GOG_OBJECT (model));
-	}
-
-	if ((vec = GO_DATA_VECTOR (series->base.values[1].data)) != NULL) {
-		if (model->y.fmt == NULL)
-			model->y.fmt = go_data_preferred_fmt (series->base.values[1].data);
-		if (vary_uniformly (vec))
-			go_data_vector_get_minmax (vec, &tmp_min, &tmp_max);
-		else
-			tmp_min = tmp_max = go_nan;
-	} else {
-		tmp_min = 0;
-		tmp_max = series->rows - 1;
-	}
-
-	if ((model->rows != series->rows)
-			|| (tmp_min != model->y.minima)
-			|| (tmp_max != model->y.maxima)) {
-		model->rows = series->rows;
-		model->y.minima = tmp_min;
-		model->y.maxima = tmp_max;
-		gog_axis_bound_changed (model->base.axis[(model->transposed)? GOG_AXIS_X: GOG_AXIS_Y],
-				GOG_OBJECT (model));
-	}
-
-	g_free (model->plotted_data);
-	model->plotted_data = NULL;
-	mat = GO_DATA_MATRIX (series->base.values[2].data);
-	go_data_matrix_get_minmax (mat, &tmp_min, &tmp_max);
-	if ((tmp_min != model->z.minima)
-			|| (tmp_max != model->z.maxima)) {
-		model->z.minima = tmp_min;
-		model->z.maxima = tmp_max;
-		gog_axis_bound_changed (model->base.axis[GOG_AXIS_PSEUDO_3D], GOG_OBJECT (model));
-	} else
-		gog_contour_plot_update_3d (GOG_PLOT (model));
-	
-	gog_object_emit_changed (GOG_OBJECT (obj), FALSE);
-	if (plot_contour_parent_klass->update)
-		plot_contour_parent_klass->update (obj);
-}
-
-static GOData *
-gog_contour_plot_axis_get_bounds (GogPlot *plot, GogAxisType axis, 
-				  GogPlotBoundInfo * bounds)
-{
-	GogSurfaceSeries *series;
-	GogContourPlot *contour = GOG_CONTOUR_PLOT (plot);
-	GODataVector *vec = NULL;
-	double min, max;
-	GOFormat *fmt;
-	if (!plot->series)
-		return NULL;
-	series = GOG_SURFACE_SERIES (plot->series->data);
-	if ((axis == GOG_AXIS_Y && contour->transposed) ||
-		(axis == GOG_AXIS_X && !contour->transposed)) {
-		vec = GO_DATA_VECTOR (series->base.values[0].data);
-		fmt = contour->x.fmt;
-		min = contour->x.minima;
-		max = contour->x.maxima;
-	} else if (axis == GOG_AXIS_X || axis == GOG_AXIS_Y) {
-		vec = GO_DATA_VECTOR (series->base.values[1].data);
-		fmt = contour->y.fmt;
-		min = contour->y.minima;
-		max = contour->y.maxima;
-	} else {
-		if (bounds->fmt == NULL && contour->z.fmt != NULL)
-			bounds->fmt = go_format_ref (contour->z.fmt);
-		bounds->val.minima = contour->z.minima;
-		bounds->val.maxima = contour->z.maxima;
-		return NULL;
-	}
-	if (bounds->fmt == NULL && fmt != NULL)
-		bounds->fmt = go_format_ref (fmt);
-	if (go_finite (min)) {
-		bounds->logical.minima = bounds->val.minima = min;
-		bounds->logical.maxima = bounds->val.maxima = max;
-		bounds->is_discrete = FALSE;
-	} else {
-		bounds->val.minima = 1.;
-		bounds->logical.minima = 1.;
-		bounds->logical.maxima = go_nan;
-		bounds->is_discrete    = TRUE;
-		bounds->center_on_ticks = TRUE;
-		bounds->val.maxima = ((axis == GOG_AXIS_Y && contour->transposed) ||
-		(axis == GOG_AXIS_X && !contour->transposed)) ?
-			series->columns:
-			series->rows;
-	}
-	return (GOData*) vec;
-}
-
-static void 
-gog_contour_plot_foreach_elem  (GogPlot *plot, gboolean only_visible,
-				    GogEnumFunc func, gpointer data)
-{
-	unsigned i, j, nticks;
-	char *label;
-	static char separator = 0;
-	GogStyle *style = gog_style_new ();
-	GogTheme *theme = gog_object_get_theme (GOG_OBJECT (plot));
-	GogAxis *axis = plot->axis[GOG_AXIS_PSEUDO_3D];
-	GOColor *color;
-	GogAxisTick *zticks;
-	double *limits;
-	double minimum, maximum;
-
-	gog_axis_get_bounds (axis, &minimum, &maximum);
-
-	if (separator == 0) {
-		struct lconv *lc = localeconv ();
-		separator = (strcmp (lc->decimal_point, ","))? ',': ';';
-	}
-	nticks = gog_axis_get_ticks (axis, &zticks);
-	limits = g_new (double, nticks + 1);
-	for (i = j = 0; i < nticks; i++)
-		if (zticks[i].type == GOG_AXIS_TICK_MAJOR)
-			limits[j++] = zticks[i].position;
-	j--;
-	if (maximum > limits[j])
-		limits[++j] = maximum;
-	/* build the colors table */
-	color = g_new0 (GOColor, (j > 0)? j: 1);
-	if (j < 2)
-		color[0] = RGBA_WHITE;
-	else for (i = 0; i < j; i++) {
-		gog_theme_fillin_style (theme, style, GOG_OBJECT (plot->series->data), i, FALSE);
-		color[i] = style->fill.pattern.back;
-	}
-	g_object_unref (style);
-
-	style = gog_style_new ();
-	style->interesting_fields = GOG_STYLE_FILL;
-	style->disable_theming = GOG_STYLE_ALL;
-	style->fill.type = GOG_FILL_STYLE_PATTERN;
-	style->fill.pattern.pattern = GO_PATTERN_SOLID;
-
-	if (gog_axis_is_inverted (axis)) {
-		for (i = 0; i < j; i++) {
-			style->fill.pattern.back = color[i];
-			label = g_strdup_printf ("[%g%c %g%c", limits[j - i - 1], separator,
-						limits[j - i], (limits[i - j] > minimum)? '[':']');
-			(func) (i, style, label, data);
-			g_free (label);
-		}
-		if (limits[i - j] > minimum) {
-			gog_theme_fillin_style (theme, style, GOG_OBJECT (plot->series->data), i, FALSE);
-			label = g_strdup_printf ("[%g%c %g]", minimum, separator,
-						limits[i - j]);
-			(func) (i, style, label, data);
-			g_free (label);
-		}
-	} else {
-		if (minimum < limits[0]) {
-			style->fill.pattern.back = color[0];
-			label = g_strdup_printf ("[%g%c %g]", minimum, separator,
-						limits[0]);
-			(func) (0, style, label, data);
-			g_free (label);
-			i = 1;
-			j++;
-		} else
-			i = 0;
-		for (; i < j; i++) {
-			style->fill.pattern.back = color[i];
-			label = g_strdup_printf ("[%g%c %g%c", limits[i], separator,
-						limits[i + 1], (i == j - 1)? ']':'[');
-			(func) (i, style, label, data);
-			g_free (label);
-		}
-	}
-	g_free (limits);
-	g_object_unref (style);
-	g_free (color);
-}
-
-static void
-gog_contour_plot_finalize (GObject *obj)
-{
-	GogContourPlot *plot = GOG_CONTOUR_PLOT (obj);
-	gog_contour_plot_clear_formats (plot);
-	g_free (plot->plotted_data);
-	G_OBJECT_CLASS (plot_contour_parent_klass)->finalize (obj);
-}
-
-static void
-gog_contour_plot_set_property (GObject *obj, guint param_id,
-			     GValue const *value, GParamSpec *pspec)
-{
-	GogContourPlot *plot = GOG_CONTOUR_PLOT (obj);
-
-	switch (param_id) {
-	case CONTOUR_PROP_TRANSPOSED :
-		if (!plot->transposed != !g_value_get_boolean (value)) {
-			plot->transposed = g_value_get_boolean (value);
-			if (NULL != plot->base.axis[GOG_AXIS_X])
-				gog_axis_bound_changed (plot->base.axis[GOG_AXIS_X], GOG_OBJECT (plot));
-			if (NULL != plot->base.axis[GOG_AXIS_Y])
-				gog_axis_bound_changed (plot->base.axis[GOG_AXIS_Y], GOG_OBJECT (plot));
-			g_free (plot->plotted_data);
-			plot->plotted_data = NULL;
-		}
-		break;
-
-	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
-		 return; /* NOTE : RETURN */
-	}
-	gog_object_emit_changed (GOG_OBJECT (obj), FALSE);
-}
-
-static void
-gog_contour_plot_get_property (GObject *obj, guint param_id,
-			     GValue *value, GParamSpec *pspec)
-{
-	GogContourPlot *plot = GOG_CONTOUR_PLOT (obj);
-
-	switch (param_id) {
-	case CONTOUR_PROP_TRANSPOSED :
-		g_value_set_boolean (value, plot->transposed);
-		break;
-
-	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
-		 break;
-	}
-}
-
-static void
-gog_contour_plot_class_init (GogContourPlotClass *klass)
+gog_surface_plot_class_init (GogSurfacePlotClass *klass)
 {
+	GogXYZPlotClass *gog_xyz_plot_klass = (GogXYZPlotClass *) klass;
 	GogPlotClass *gog_plot_klass = (GogPlotClass*) klass;
-	GObjectClass   *gobject_klass = (GObjectClass *) klass;
 	GogObjectClass *gog_object_klass = (GogObjectClass *) klass;
 
-	plot_contour_parent_klass = g_type_class_peek_parent (klass);
-
-	gobject_klass->finalize     = gog_contour_plot_finalize;
-	gobject_klass->set_property = gog_contour_plot_set_property;
-	gobject_klass->get_property = gog_contour_plot_get_property;
-	g_object_class_install_property (gobject_klass, CONTOUR_PROP_TRANSPOSED,
-		g_param_spec_boolean ("transposed", 
-			_("Transposed"),
-			_("Transpose the plot"),
-			FALSE, 
-			GSF_PARAM_STATIC | G_PARAM_READWRITE|GOG_PARAM_PERSISTENT));
-
-	/* Fill in GOGObject superclass values */
-	gog_object_klass->update	= gog_contour_plot_update;
-	gog_object_klass->type_name	= gog_contour_plot_type_name;
-	gog_object_klass->view_type	= gog_contour_view_get_type ();
-	gog_object_klass->populate_editor	= gog_contour_plot_populate_editor;
-
-	{
-		static GogSeriesDimDesc dimensions[] = {
-			{ N_("X"), GOG_SERIES_SUGGESTED, FALSE,
-			  GOG_DIM_LABEL, GOG_MS_DIM_CATEGORIES },
-			{ N_("Y"), GOG_SERIES_SUGGESTED, FALSE,
-			  GOG_DIM_LABEL, GOG_MS_DIM_CATEGORIES },
-			{ N_("Z"), GOG_SERIES_REQUIRED, FALSE,
-			  GOG_DIM_MATRIX, GOG_MS_DIM_VALUES },
-		};
-		gog_plot_klass->desc.series.dim = dimensions;
-		gog_plot_klass->desc.series.num_dim = G_N_ELEMENTS (dimensions);
-		gog_plot_klass->desc.series.style_fields = GOG_STYLE_LINE;
-	}
+	gog_object_klass->type_name	= gog_surface_plot_type_name;
+	gog_object_klass->view_type	= gog_surface_view_get_type ();
 
 	/* Fill in GogPlotClass methods */
-	gog_plot_klass->desc.num_series_min = 1;
-	gog_plot_klass->desc.num_series_max = 1;
-	gog_plot_klass->series_type = gog_surface_series_get_type();
-	gog_plot_klass->axis_set = GOG_AXIS_SET_XY_pseudo_3d;
-	gog_plot_klass->axis_get_bounds	= gog_contour_plot_axis_get_bounds;
-	gog_plot_klass->foreach_elem = gog_contour_plot_foreach_elem;
-	gog_plot_klass->update_3d = gog_contour_plot_update_3d;
+	gog_plot_klass->axis_set = GOG_AXIS_SET_XYZ;
+	gog_plot_klass->desc.series.style_fields = GOG_STYLE_LINE | GOG_STYLE_FILL;
 
-	klass->build_matrix = gog_contour_plot_real_build_matrix;
+	gog_xyz_plot_klass->third_axis = GOG_AXIS_Z;
+	gog_xyz_plot_klass->build_matrix = gog_surface_plot_build_matrix;
 }
 
 static void
-gog_contour_plot_init (GogContourPlot *contour)
+gog_surface_plot_init (GogSurfacePlot *surface)
 {
-	GogPlot *plot = GOG_PLOT (contour);
+	GogPlot *plot = GOG_PLOT (surface);
 
-	contour->rows = contour->columns = 0;
-	contour->transposed = FALSE;
-	contour->base.vary_style_by_element = TRUE;
-	contour->x.minima = contour->x.maxima = contour->y.minima
-		= contour->y.maxima = contour->z.minima = contour->z.maxima = go_nan;
-	contour->x.fmt = contour->y.fmt = contour->z.fmt = NULL;
-	contour->plotted_data = NULL;
-
-	plot->render_before_axes = TRUE;
+	plot->render_before_axes = FALSE;
 }
 
-GSF_DYNAMIC_CLASS (GogContourPlot, gog_contour_plot,
-	gog_contour_plot_class_init, gog_contour_plot_init,
-	GOG_PLOT_TYPE)
+GSF_DYNAMIC_CLASS (GogSurfacePlot, gog_surface_plot,
+	gog_surface_plot_class_init, gog_surface_plot_init,
+	GOG_XYZ_PLOT_TYPE)
 
 /*****************************************************************************/
 
-typedef GogPlotView		GogContourView;
-typedef GogPlotViewClass	GogContourViewClass;
-#define CONTOUR_EPSILON 1e-10
+typedef GogPlotView		GogSurfaceView;
+typedef GogPlotViewClass	GogSurfaceViewClass;
 
 static void
-gog_contour_view_render (GogView *view, GogViewAllocation const *bbox)
+gog_surface_view_render (GogView *view, GogViewAllocation const *bbox)
 {
-	GogContourPlot const *plot = GOG_CONTOUR_PLOT (view->model);
+	GogSurfacePlot const *plot = GOG_SURFACE_PLOT (view->model);
 	GogSeries const *series;
-	GODataVector *x_vec = NULL, *y_vec = NULL;
-	GogAxisMap *x_map, *y_map;
-	double zval0, zval1, zval2 = 0., zval3, t;
-	double x[4], y[4], zval[4];
-	int z[4];
-	int z0 = 0, z1 = 0, z2 = 0, z3 = 0, zmin, zmax, nans, nan = 0;
-	int k, kmax, r = 0, s, h;
-	unsigned i, imax, j, jmax, l, lmax, p;
+	GogChartMap3D *chart_map;
+	GogChart *chart = GOG_CHART (view->model->parent);
+	GogViewAllocation const *area;
+	int i, imax, j, jmax, max, istep, jstep, jstart, iend, jend;
+	double x[2], y[2], z[3], x0, y0, x1, y1;
 	GogRenderer *rend = view->renderer;
 	GogStyle *style;
-	GogTheme *theme = gog_object_get_theme (GOG_OBJECT (plot));
-	double x0, x1, y0, y1;
-	ArtVpath *path, *lines;
-	GOColor *color;
-	gboolean cw;
 	double *data;
-	int max;
+	GODataVector *x_vec = NULL, *y_vec = NULL;
 	gboolean xdiscrete, ydiscrete;
+	GOPath *path;
+	gboolean cw;
 
 	if (plot->base.series == NULL)
 		return;
 	series = GOG_SERIES (plot->base.series->data);
 	max = series->num_elements;
 	if (plot->transposed) {
-		imax = plot->columns;
-		jmax = plot->rows;
-	} else {
 		imax = plot->rows;
 		jmax = plot->columns;
+	} else {
+		imax = plot->columns;
+		jmax = plot->rows;
 	}
 	if (imax ==0 || jmax == 0)
 		return;
-
-	x_map = gog_axis_map_new (plot->base.axis[0], 
-				  view->residual.x , view->residual.w);
-	y_map = gog_axis_map_new (plot->base.axis[1], 
-				  view->residual.y + view->residual.h, 
-				  -view->residual.h);
-
-	if (!(gog_axis_map_is_valid (x_map) &&
-	      gog_axis_map_is_valid (y_map))) {
-		gog_axis_map_free (x_map);
-		gog_axis_map_free (y_map);
+	area = gog_chart_view_get_plot_area (view->parent);
+	chart_map = gog_chart_map_3d_new (chart, area,
+				       GOG_PLOT (plot)->axis[GOG_AXIS_X],
+				       GOG_PLOT (plot)->axis[GOG_AXIS_Y],
+				       GOG_PLOT (plot)->axis[GOG_AXIS_Z]);
+	if (!gog_chart_map_3d_is_valid (chart_map)) {
+		gog_chart_map_3d_free (chart_map);
 		return;
 	}
 
+
+	style = gog_styled_object_get_style (GOG_STYLED_OBJECT (series));
+
 	if (plot->plotted_data)
 		data = plot->plotted_data;
 	else
-		data = gog_contour_plot_build_matrix (plot, &cw);
+		data = gog_xyz_plot_build_matrix (plot, &cw);
 
-	/* Set cw to ensure that polygons will allways be drawn clockwise */
+	/* check the drawing order */
 	xdiscrete = gog_axis_is_discrete (plot->base.axis[0]) ||
 			series->values[(plot->transposed)? 1: 0].data == NULL;
 	if (xdiscrete) {
-		x0 = gog_axis_map_to_view (x_map, 0.);
-		x1 = gog_axis_map_to_view (x_map, 1.);
+		x[0] = 0.;
+		x[1] = 1.;
 	}else {
 		x_vec = GO_DATA_VECTOR (series->values[(plot->transposed)? 1: 0].data);
-		x0 = gog_axis_map_to_view (x_map, go_data_vector_get_value (x_vec, 0));
-		x1 = gog_axis_map_to_view (x_map, go_data_vector_get_value (x_vec, 1));
+		x[0] = go_data_vector_get_value (x_vec, 0);
+		x[1] = go_data_vector_get_value (x_vec, 1);
 	}
 	ydiscrete = gog_axis_is_discrete (plot->base.axis[1]) ||
 			series->values[(plot->transposed)? 0: 1].data == NULL;
 	if (ydiscrete) {
-		y0 = gog_axis_map_to_view (y_map, 0.);
-		y1 = gog_axis_map_to_view (y_map, 1.);
+		y[0] = 0.;
+		y[1] = 1.;
 	}else {
 		y_vec = GO_DATA_VECTOR (series->values[(plot->transposed)? 0: 1].data);
-		y0 = gog_axis_map_to_view (y_map, go_data_vector_get_value (y_vec, 0));
-		y1 = gog_axis_map_to_view (y_map, go_data_vector_get_value (y_vec, 1));
+		y[0] = go_data_vector_get_value (y_vec, 0);
+		y[1] = go_data_vector_get_value (y_vec, 1);
 	}
-	cw = (x1 > x0) == (y1 > y0);
-
-	style = gog_style_new ();
-	path = art_new (ArtVpath, 10);
-	/* build the colors table */
-	color = g_new0 (GOColor, max);
-	if (max < 2)
-		color[0] = RGBA_WHITE;
-	else for (i = 0; i < (unsigned) max; i++) {
-		gog_theme_fillin_style (theme, style, GOG_OBJECT (series), i, FALSE);
-		color[i] = style->fill.pattern.back;
-	}
-	g_object_unref (style);
-
-	/* clip to avoid problems with logarithmic axes */
-	gog_renderer_push_clip_rectangle (rend, view->residual.x, view->residual.y,
-					  view->residual.w, view->residual.h);
-
-	style = gog_style_new ();
-	style->interesting_fields = GOG_STYLE_FILL | GOG_STYLE_OUTLINE;
-	style->disable_theming = GOG_STYLE_ALL;
-	style->fill.type = GOG_FILL_STYLE_PATTERN;
-	style->fill.pattern.pattern = GO_PATTERN_SOLID;
-	style->outline.dash_type = GO_LINE_SOLID;
-	style->outline.auto_dash = FALSE;
-	style->outline.auto_color = FALSE;
-	style->outline.width = 0.5;
-	style->outline.color = RGBA_BLACK;
-
-	lines = art_new (ArtVpath, lmax = 64);
-	l = 0;
-
-	for (j = 1; j < jmax; j++) {
-		if (xdiscrete) {
-			x0 = gog_axis_map_to_view (x_map, j);
-			x1 = gog_axis_map_to_view (x_map, j + 1);
-		}else {
-			x0 = gog_axis_map_to_view (x_map, go_data_vector_get_value (x_vec, j - 1));
-			x1 = gog_axis_map_to_view (x_map, go_data_vector_get_value (x_vec, j));
-		}
-		
-		for (i = 1; i < imax; i++) {
-			if (ydiscrete) {
-				y0 = gog_axis_map_to_view (y_map, i);
-				y1 = gog_axis_map_to_view (y_map, i + 1);
-			}else {
-				y0 = gog_axis_map_to_view (y_map, go_data_vector_get_value (y_vec, i - 1));
-				y1 = gog_axis_map_to_view (y_map, go_data_vector_get_value (y_vec, i));
-			}
-			nans = 0;
-			nan = 4;
-			zmin = max;
-			zmax = 0;
-			zval0 = data[(i - 1) * jmax + j - 1];
-			if (!isnan (zval0)) {
-				z0 = floor (zval0);
-				if (z0 > zmax)
-					zmax = z0;
-				if (z0 < zmin) {
-					zmin = z0;
-					r = 0;
-				}
-			} else {
-				nans++;
-				nan = 0;
-			}
-			zval1 = data[(i - 1) * jmax + j];
-			if (!isnan (zval1)) {
-				z1 = floor (zval1);
-				if (z1 > zmax)
-					zmax = z1;
-				if (z1 < zmin) {
-					zmin = z1;
-					r = 1;
-				}
+	gog_chart_map_3d_to_view (chart_map, x[0], y[0], data[0], NULL, NULL, z + 1); 
+	gog_chart_map_3d_to_view (chart_map, x[1], y[0], data[0], NULL, NULL, z + 2);
+	if (z[2] > z[1]) {
+		i = imax - 1;
+		iend = 0;
+		istep = -1;
+	} else {
+		i = 1;
+		iend = imax;
+		istep = 1;
+	}
+	gog_chart_map_3d_to_view (chart_map, x[0], y[1], data[0], NULL, NULL, z + 2);
+	if (z[2] > z[1]) {
+		jstart = jmax - 1;
+		jend = 0;
+		jstep = -1;
+	} else {
+		jstart = 1;
+		jstep = 1;
+		jend = jmax;
+	}
+	gog_renderer_push_style (rend, style);
+	for (; i != iend; i +=istep)
+		for (j = jstart; j != jend; j += jstep) {
+			path = go_path_new ();
+			if (xdiscrete) {
+				x0 = i;
+				x1 = i + 1;
 			} else {
-				nans++;
-				nan = 1;
+				x0 = go_data_vector_get_value (x_vec, i - 1);
+				x1 = go_data_vector_get_value (x_vec, i);
 			}
-			zval2 = data[i * jmax + j];
-			if (!isnan (zval2)) {
-				z2 = floor (zval2);
-				if (z2 > zmax)
-					zmax = z2;
-				if (z2 < zmin) {
-					zmin = z2;
-					r = 2;
-				}
-			} else {
-				nans++;
-				nan = 2;
-			}
-			zval3 = data[i * jmax + j - 1];
-			if (!isnan (zval3)) {
-				z3 = floor (zval3);
-				if (z3 > zmax)
-					zmax = z3;
-				if (z3 < zmin) {
-					zmin = z3;
-					r = 3;
-				}
-			} else {
-				nans++;
-				nan = 3;
-			}
-			if (nans > 1)
-				continue;
-			/* Build the x, y and z arrays for the tile */
-			k = r;
-			s = 0;
-			do {
-				if (k != nan) {
-					switch (k) {
-					case 0:
-						x[s] = x0;
-						y[s] = y0;
-						z[s] = z0;
-						zval[s++] = zval0;
-						break;
-					case 1:
-						x[s] = x1;
-						y[s] = y0;
-						z[s] = z1;
-						zval[s++] = zval1;
-						break;
-					case 2:
-						x[s] = x1;
-						y[s] = y1;
-						z[s] = z2;
-						zval[s++] = zval2;
-						break;
-					default:
-						x[s] = x0;
-						y[s] = y1;
-						z[s] = z3;
-						zval[s++] = zval3;
-					}
-				}
-				if (cw) {
-					k++;
-					k %= 4;
-				} else {
-					if (k == 0)
-						k = 3;
-					else
-						k--;
-				}
-			} while (k != r);
-			if (zmin == zmax) {
-				/* paint everything with one color*/
-				style->outline.color = color[zmin];
-				style->fill.pattern.back = color[zmin];
-				gog_renderer_push_style (rend, style);
-				path[0].code = ART_MOVETO;
-				for (k = 0; k < s; ) {
-					path[k].x = x[k];
-					path[k].y = y[k];
-					path[++k].code = ART_LINETO;
-				}
-				path[k].x = x[0];
-				path[k].y = y[0];
-				path[k + 1].code = ART_END;
-				/* narrow parameter is TRUE below to avoid border effects */
-				gog_renderer_draw_polygon (rend, path, FALSE);
-				gog_renderer_pop_style (rend);
+			if (ydiscrete) {
+				y0 = j;
+				y1 = j + 1;
 			} else {
-				kmax = 3 - nans;
-				if (!nans && (((z0 < z1) && (z1 > z2) && (z2 < z3) && (z3 > z0)) ||
-					((z0 > z1) && (z1 < z2) && (z2 > z3) && (z3 < z0)))) {
-					/* we have a saddle point */
-					/* first find the most probable altitude of the saddle point */
-					int zn, zx;
-					gboolean crossing = FALSE, up = FALSE, odd;
-					double xl[8], yl[8];
-					/* crossing is TRUE if the saddle point occurs at a slices border */
-					zn = MAX (z[0], z[2]);
-					if (zval[1] > zval[3])
-						zx = (zval[3] == z[3])? z[3] - 1: z[3];
-					else
-						zx =  (zval[1] == z[1])? z[1] - 1: z[1];
-					odd = (zx - zn) % 2;
-					if (odd) {
-						if ((zx - zn) == 1) {
-							double sum = 0.;
-							sum += (z[0] == zn)? zval[0]: zn;
-							sum += (z[1] == zx)? zval[1]: zx + 1;
-							sum += (z[2] == zn)? zval[2]: zn;
-							sum += (z[3] == zx)? zval[3]: zx + 1;
-							sum /= 4.;
-							if (fabs ((sum - zx)) < DBL_EPSILON)
-								crossing = TRUE;
-							else
-								up = (sum - zx) < 0;
-						} else
-							crossing = TRUE;
-						zn = (zn + zx) / 2;
-						zx = zn + 1;
-					} else
-						zn = zx = (zn + zx) / 2;
-					/* low values slices */
-					if (z[0] < zn) {
-						k = z[0];
-						style->outline.color = color[k];
-						style->fill.pattern.back = color[k];
-						k++;
-						path[0].code = ART_MOVETO;
-						path[1].code = ART_LINETO;
-						path[2].code = ART_LINETO;
-						path[3].code = ART_LINETO;
-						path[4].code = ART_END;
-						path[0].x = path[3].x = x[0];
-						path[0].y = path[3].y = y[0];
-						if ((l + 3) >= lmax)
-							lines = art_renew (lines, ArtVpath, lmax += 64);
-						lines[l].code = ART_MOVETO_OPEN;
-						t = (k - zval[0]) / (zval[3] - zval[0]);
-						xl[7] = lines[l].x = path[1].x = x[0] + t * (x[3] - x[0]);
-						yl[7] = lines[l++].y = path[1].y = y[0] + t * (y[3] - y[0]);
-						lines[l].code = ART_LINETO;
-						t = (k - zval[0]) / (zval[1] - zval[0]);
-						xl[0] = lines[l].x = path[2].x = x[0] + t * (x[1] - x[0]);
-						yl[0] = lines[l++].y = path[2].y = y[0] + t * (y[1] - y[0]);
-						gog_renderer_push_style (rend, style);
-						gog_renderer_draw_polygon (rend, path, FALSE);
-						gog_renderer_pop_style (rend);
-						path[4].code = ART_LINETO;
-						path[5].code = ART_END;
-						while (k < zn) {
-							style->outline.color = color[k];
-							style->fill.pattern.back = color[k];
-							k++;
-							path[0].x = path[4].x = xl[7];
-							path[0].y = path[4].y = yl[7];
-							path[3].x = xl[0];
-							path[3].y = yl[0];
-							if ((l + 3) >= lmax)
-								lines = art_renew (lines, ArtVpath, lmax += 64);
-							lines[l].code = ART_MOVETO_OPEN;
-							t = (k - zval[0]) / (zval[3] - zval[0]);
-							xl[7] = lines[l].x = path[1].x = x[0] + t * (x[3] - x[0]);
-							yl[7] = lines[l++].y = path[1].y = y[0] + t * (y[3] - y[0]);
-							lines[l].code = ART_LINETO;
-							t = (k - zval[0]) / (zval[1] - zval[0]);
-							xl[0] = lines[l].x = path[2].x = x[0] + t * (x[1] - x[0]);
-							yl[0] = lines[l++].y = path[2].y = y[0] + t * (y[1] - y[0]);
-							gog_renderer_push_style (rend, style);
-							gog_renderer_draw_polygon (rend, path, FALSE);
-							gog_renderer_pop_style (rend);
-						}
-					} else
-						xl[0] = xl[7] = -1.;
-					if (z[2] < zn) {
-						k = z[2];
-						style->outline.color = color[k];
-						style->fill.pattern.back = color[k];
-						k++;
-						path[0].code = ART_MOVETO;
-						path[1].code = ART_LINETO;
-						path[2].code = ART_LINETO;
-						path[3].code = ART_LINETO;
-						path[4].code = ART_END;
-						path[0].x = path[3].x = x[2];
-						path[0].y = path[3].y = y[2];
-						if ((l + 3) >= lmax)
-							lines = art_renew (lines, ArtVpath, lmax += 64);
-						lines[l].code = ART_MOVETO_OPEN;
-						t = (k - zval[2]) / (zval[1] - zval[2]);
-						xl[3] = lines[l].x = path[1].x = x[2] + t * (x[1] - x[2]);
-						yl[3] = lines[l++].y = path[1].y = y[2] + t * (y[1] - y[2]);
-						lines[l].code = ART_LINETO;
-						t = (k - zval[2]) / (zval[3] - zval[2]);
-						xl[4] = lines[l].x = path[2].x = x[2] + t * (x[3] - x[2]);
-						yl[4] = lines[l++].y = path[2].y = y[2] + t * (y[3] - y[2]);
-						gog_renderer_push_style (rend, style);
-						gog_renderer_draw_polygon (rend, path, FALSE);
-						gog_renderer_pop_style (rend);
-						path[4].code = ART_LINETO;
-						path[5].code = ART_END;
-						while (k < zn) {
-							style->outline.color = color[k];
-							style->fill.pattern.back = color[k];
-							k++;
-							path[0].x = path[4].x = xl[3];
-							path[0].y = path[4].y = yl[3];
-							path[3].x = xl[4];
-							path[3].y = yl[4];
-							if ((l + 3) >= lmax)
-								lines = art_renew (lines, ArtVpath, lmax += 64);
-							lines[l].code = ART_MOVETO_OPEN;
-							t = (k - zval[2]) / (zval[1] - zval[2]);
-							xl[3] = lines[l].x = path[1].x = x[2] + t * (x[1] - x[2]);
-							yl[3] = lines[l++].y = path[1].y = y[2] + t * (y[1] - y[2]);
-							lines[l].code = ART_LINETO;
-							t = (k - zval[2]) / (zval[3] - zval[2]);
-							xl[4] = lines[l].x = path[2].x = x[2] + t * (x[3] - x[2]);
-							yl[4] = lines[l++].y = path[2].y = y[2] + t * (y[3] - y[2]);
-							gog_renderer_push_style (rend, style);
-							gog_renderer_draw_polygon (rend, path, FALSE);
-							gog_renderer_pop_style (rend);
-						}
-					} else
-						xl[3] = xl[4] = -1.;
-					/* high values slices */
-					k = z[1];
-					if (zval[1] == k)
-						k--;
-					if (k > zx) {
-						path[0].code = ART_MOVETO;
-						path[1].code = ART_LINETO;
-						path[2].code = ART_LINETO;
-						path[3].code = ART_LINETO;
-						path[4].code = ART_END;
-						path[0].x = path[3].x = x[1];
-						path[0].y = path[3].y = y[1];
-						if ((l + 3) >= lmax)
-							lines = art_renew (lines, ArtVpath, lmax += 64);
-						lines[l].code = ART_MOVETO_OPEN;
-						t = (k - zval[1]) / (zval[0] - zval[1]);
-						xl[1] = lines[l].x = path[1].x = x[1] + t * (x[0] - x[1]);
-						yl[1] = lines[l++].y = path[1].y = y[1] + t * (y[0] - y[1]);
-						lines[l].code = ART_LINETO;
-						t = (k - zval[1]) / (zval[2] - zval[1]);
-						xl[2] = lines[l].x = path[2].x = x[1] + t * (x[2] - x[1]);
-						yl[2] = lines[l++].y = path[2].y = y[1] + t * (y[2] - y[1]);
-						style->outline.color = color[k];
-						style->fill.pattern.back = color[k];
-						gog_renderer_push_style (rend, style);
-						gog_renderer_draw_polygon (rend, path, FALSE);
-						gog_renderer_pop_style (rend);
-						path[4].code = ART_LINETO;
-						path[5].code = ART_END;
-						k--;
-						while (k > zx) {
-							path[0].x = path[4].x = xl[1];
-							path[0].y = path[4].y = yl[1];
-							path[3].x = xl[2];
-							path[3].y = yl[2];
-							if ((l + 3) >= lmax)
-								lines = art_renew (lines, ArtVpath, lmax += 64);
-							lines[l].code = ART_MOVETO_OPEN;
-							t = (k - zval[1]) / (zval[0] - zval[1]);
-							xl[1] = lines[l].x = path[1].x = x[1] + t * (x[0] - x[1]);
-							yl[1] = lines[l++].y = path[1].y = y[1] + t * (y[0] - y[1]);
-							lines[l].code = ART_LINETO;
-							t = (k - zval[1]) / (zval[2] - zval[1]);
-							xl[2] = lines[l].x = path[2].x = x[1] + t * (x[2] - x[1]);
-							yl[2] = lines[l++].y = path[2].y = y[1] + t * (y[2] - y[1]);
-							style->outline.color = color[k];
-							style->fill.pattern.back = color[k];
-							gog_renderer_push_style (rend, style);
-							gog_renderer_draw_polygon (rend, path, FALSE);
-							gog_renderer_pop_style (rend);
-							k--;
-						}
-					} else
-						xl[1] = xl[2] = -1.;
-					k = z[3];
-					if (zval[3] == k)
-						k--;
-					if (k > zx) {
-						path[0].code = ART_MOVETO;
-						path[1].code = ART_LINETO;
-						path[2].code = ART_LINETO;
-						path[3].code = ART_LINETO;
-						path[4].code = ART_END;
-						path[0].x = path[3].x = x[3];
-						path[0].y = path[3].y = y[3];
-						if ((l + 3) >= lmax)
-							lines = art_renew (lines, ArtVpath, lmax += 64);
-						lines[l].code = ART_MOVETO_OPEN;
-						t = (k - zval[3]) / (zval[2] - zval[3]);
-						xl[5] = lines[l].x = path[1].x = x[3] + t * (x[2] - x[3]);
-						yl[5] = lines[l++].y = path[1].y = y[3] + t * (y[2] - y[3]);
-						lines[l].code = ART_LINETO;
-						t = (k - zval[3]) / (zval[0] - zval[3]);
-						xl[6] = lines[l].x = path[2].x = x[3] + t * (x[0] - x[3]);
-						yl[6] = lines[l++].y = path[2].y = y[3] + t * (y[0] - y[3]);
-						style->outline.color = color[k];
-						style->fill.pattern.back = color[k];
-						gog_renderer_push_style (rend, style);
-						gog_renderer_draw_polygon (rend, path, FALSE);
-						gog_renderer_pop_style (rend);
-						path[4].code = ART_LINETO;
-						path[5].code = ART_END;
-						k--;
-						while (k > zx) {
-							path[0].x = path[4].x = xl[5];
-							path[0].y = path[4].y = yl[5];
-							path[3].x = xl[6];
-							path[3].y = yl[6];
-							if ((l + 3) >= lmax)
-								lines = art_renew (lines, ArtVpath, lmax += 64);
-							lines[l].code = ART_MOVETO_OPEN;
-							t = (k - zval[3]) / (zval[2] - zval[3]);
-							xl[5] = lines[l].x = path[1].x = x[3] + t * (x[2] - x[3]);
-							yl[5] = lines[l++].y = path[1].y = y[3] + t * (y[2] - y[3]);
-							lines[l].code = ART_LINETO;
-							t = (k - zval[3]) / (zval[0] - zval[3]);
-							xl[6] = lines[l].x = path[2].x = x[3] + t * (x[0] - x[3]);
-							yl[6] = lines[l++].y = path[2].y = y[3] + t * (y[0] - y[3]);
-							style->outline.color = color[k];
-							style->fill.pattern.back = color[k];
-							gog_renderer_push_style (rend, style);
-							gog_renderer_draw_polygon (rend, path, FALSE);
-							gog_renderer_pop_style (rend);
-							k--;
-						}
-					} else
-						xl[5] = xl[6] = -1.;
-					/* middle values slices */
-					if (odd) {
-						if (crossing) {
-							double xb[4], yb[4], xc, yc;
-							for (k = 0; k < 4; k++) {
-								s = (k + 1) % 4;
-								t =  (zx - zval[s]) / (zval[k] - zval[s]);
-								xb[k] = x[s] + t * (x[k] - x[s]);
-								yb[k] = y[s] + t * (y[k] - y[s]);
-							}
-							if ((l + 5) >= lmax)
-								lines = art_renew (lines, ArtVpath, lmax += 64);
-							lines[l].code = ART_MOVETO_OPEN;
-							lines[l].x = xb[0];
-							lines[l++].y = yb[0];
-							lines[l].code = ART_LINETO;
-							lines[l].x = xb[2];
-							lines[l++].y = yb[2];
-							lines[l].code = ART_MOVETO_OPEN;
-							lines[l].x = xb[1];
-							lines[l++].y = yb[1];
-							lines[l].code = ART_LINETO;
-							lines[l].x = xb[3];
-							lines[l++].y = yb[3];
-							/* calculate the coordinates xc and yc of crossing point */
-							t = ((xb[1] - xb[0]) * (yb[3] - yb[1])
-								+ (xb[1] - xb[3]) * (yb[1] - yb[0])) /
-								((xb[2] - xb[0]) * (yb[3] - yb[1])
-								+ (xb[1] - xb[3]) * (yb[2] - yb[0]));
-							xc = xb[0] + t * (xb[2] - xb[0]);
-							yc = yb[0] + t * (yb[2] - yb[0]);
-							/* fill */
-							path[0].code = ART_MOVETO;
-							path[1].code = ART_LINETO;
-							path[2].code = ART_LINETO;
-							path[3].code = ART_LINETO;
-							path[4].code = ART_LINETO;
-							if (xl[0] < 0.) {
-								path[4].x = path[0].x = x[0];
-								path[4].y = path[0].y = y[0];
-								path[5].code = ART_END;
-							} else {
-								path[5].x = path[0].x = xl[7];
-								path[5].y = path[0].y = yl[7];
-								path[4].x = xl[0];
-								path[4].y = yl[0];
-								path[5].code = ART_LINETO;
-								path[6].code = ART_END;
-							}
-							path[1].x = xb[3];
-							path[1].y = yb[3];
-							path[2].x = xc;
-							path[2].y = yc;
-							path[3].x = xb[0];
-							path[3].y = yb[0];
-							style->outline.color = color[zn];
-							style->fill.pattern.back = color[zn];
-							gog_renderer_push_style (rend, style);
-							gog_renderer_draw_polygon (rend, path, FALSE);
-							if (xl[2] < 0.) {
-								path[4].x = path[0].x = x[2];
-								path[4].y = path[0].y = y[2];
-								path[5].code = ART_END;
-							} else {
-								path[5].x = path[0].x = xl[3];
-								path[5].y = path[0].y = yl[3];
-								path[4].x = xl[4];
-								path[4].y = yl[4];
-								path[5].code = ART_LINETO;
-								path[6].code = ART_END;
-							}
-							path[1].x = xb[1];
-							path[1].y = yb[1];
-							path[3].x = xb[2];
-							path[3].y = yb[2];
-							gog_renderer_draw_polygon (rend, path, FALSE);
-							gog_renderer_pop_style (rend);
-							if (xl[2] < 0.) {
-								path[4].x = path[0].x = x[1];
-								path[4].y = path[0].y = y[1];
-								path[5].code = ART_END;
-							} else {
-								path[5].x = path[0].x = xl[1];
-								path[5].y = path[0].y = yl[1];
-								path[4].x = xl[2];
-								path[4].y = yl[2];
-								path[5].code = ART_LINETO;
-								path[6].code = ART_END;
-							}
-							path[1].x = xb[0];
-							path[1].y = yb[0];
-							path[3].x = xb[1];
-							path[3].y = yb[1];
-							style->outline.color = color[zx];
-							style->fill.pattern.back = color[zx];
-							gog_renderer_push_style (rend, style);
-							gog_renderer_draw_polygon (rend, path, FALSE);
-							if (xl[6] < 0.) {
-								path[4].x = path[0].x = x[3];
-								path[4].y = path[0].y = y[3];
-								path[5].code = ART_END;
-							} else {
-								path[5].x = path[0].x = xl[5];
-								path[5].y = path[0].y = yl[5];
-								path[4].x = xl[6];
-								path[4].y = yl[6];
-								path[5].code = ART_LINETO;
-								path[6].code = ART_END;
-							}
-							path[1].x = xb[2];
-							path[1].y = yb[2];
-							path[3].x = xb[3];
-							path[3].y = yb[3];
-							gog_renderer_draw_polygon (rend, path, FALSE);
-							gog_renderer_pop_style (rend);
-						} else {
-							if (up) {
-								/* saddle point is in the lower slice */
-								/* draw the upper slices */
-								path[0].code = ART_MOVETO;
-								path[1].code = ART_LINETO;
-								path[2].code = ART_LINETO;
-								path[3].code = ART_LINETO;
-								if (xl[1] < 0.) {
-									path[4].code = ART_END;
-									path[0].x = path[3].x = x[1];
-									path[0].y = path[3].y = y[1];
-								} else {
-									path[4].code = ART_LINETO;
-									path[5].code = ART_END;
-									path[0].x = path[4].x = xl[1];
-									path[0].y = path[4].y = yl[1];
-									path[3].x = xl[2];
-									path[3].y = yl[2];
-								}
-								if ((l + 5) >= lmax)
-									lines = art_renew (lines, ArtVpath, lmax += 64);
-								lines[l].code = ART_MOVETO_OPEN;
-								t = (zx - zval[1]) / (zval[0] - zval[1]);
-								xl[1] = lines[l].x = path[1].x = x[1] + t * (x[0] - x[1]);
-								yl[1] = lines[l++].y = path[1].y = y[1] + t * (y[0] - y[1]);
-								lines[l].code = ART_LINETO;
-								t = (zx - zval[1]) / (zval[2] - zval[1]);
-								xl[2] = lines[l].x = path[2].x = x[1] + t * (x[2] - x[1]);
-								yl[2] = lines[l++].y = path[2].y = y[1] + t * (y[2] - y[1]);
-								style->outline.color = color[zx];
-								style->fill.pattern.back = color[zx];
-								gog_renderer_push_style (rend, style);
-								gog_renderer_draw_polygon (rend, path, FALSE);
-								if (xl[5] < 0.) {
-									path[4].code = ART_END;
-									path[0].x = path[3].x = x[3];
-									path[0].y = path[3].y = y[3];
-								} else {
-									path[4].code = ART_LINETO;
-									path[5].code = ART_END;
-									path[0].x = path[4].x = xl[5];
-									path[0].y = path[4].y = yl[5];
-									path[3].x = xl[6];
-									path[3].y = yl[6];
-								}
-								if ((l + 5) >= lmax)
-									lines = art_renew (lines, ArtVpath, lmax += 64);
-								lines[l].code = ART_MOVETO_OPEN;
-								t = (zx - zval[3]) / (zval[2] - zval[3]);
-								xl[5] = lines[l].x = path[1].x = x[3] + t * (x[2] - x[3]);
-								yl[5] = lines[l++].y = path[1].y = y[3] + t * (y[2] - y[3]);
-								lines[l].code = ART_LINETO;
-								t = (zx - zval[3]) / (zval[0] - zval[3]);
-								xl[6] = lines[l].x = path[2].x = x[3] + t * (x[0] - x[3]);
-								yl[6] = lines[l++].y = path[2].y = y[3] + t * (y[0] - y[3]);
-								gog_renderer_draw_polygon (rend, path, FALSE);
-								gog_renderer_pop_style (rend);
-							} else {
-								/* saddle point is in the upper slice */
-								path[0].code = ART_MOVETO;
-								path[1].code = ART_LINETO;
-								path[2].code = ART_LINETO;
-								path[3].code = ART_LINETO;
-								if (xl[0] < 0.) {
-									path[4].code = ART_END;
-									path[0].x = path[3].x = x[0];
-									path[0].y = path[3].y = y[0];
-								} else {
-									path[4].code = ART_LINETO;
-									path[5].code = ART_END;
-									path[0].x = path[4].x = xl[7];
-									path[0].y = path[4].y = yl[7];
-									path[3].x = xl[0];
-									path[3].y = yl[0];
-								}
-								if ((l + 5) >= lmax)
-									lines = art_renew (lines, ArtVpath, lmax += 64);
-								lines[l].code = ART_MOVETO_OPEN;
-								t = (k - zval[0]) / (zval[3] - zval[0]);
-								xl[7] = lines[l].x = path[1].x = x[0] + t * (x[3] - x[0]);
-								yl[7] = lines[l++].y = path[1].y = y[0] + t * (y[3] - y[0]);
-								lines[l].code = ART_LINETO;
-								t = (k - zval[0]) / (zval[1] - zval[0]);
-								xl[0] = lines[l].x = path[2].x = x[0] + t * (x[1] - x[0]);
-								yl[0] = lines[l++].y = path[2].y = y[0] + t * (y[1] - y[0]);
-								style->outline.color = color[zn];
-								style->fill.pattern.back = color[zn];
-								gog_renderer_push_style (rend, style);
-								gog_renderer_draw_polygon (rend, path, FALSE);
-								if (xl[4] < 0.) {
-									path[4].code = ART_END;
-									path[0].x = path[3].x = x[2];
-									path[0].y = path[3].y = y[2];
-								} else {
-									path[4].code = ART_LINETO;
-									path[5].code = ART_END;
-									path[0].x = path[4].x = xl[3];
-									path[0].y = path[4].y = yl[3];
-									path[3].x = xl[4];
-									path[3].y = yl[4];
-								}
-								lines[l].code = ART_MOVETO_OPEN;
-								t = (k - zval[2]) / (zval[1] - zval[2]);
-								xl[3] = lines[l].x = path[1].x = x[2] + t * (x[1] - x[2]);
-								yl[3] = lines[l++].y = path[1].y = y[2] + t * (y[1] - y[2]);
-								lines[l].code = ART_LINETO;
-								t = (k - zval[2]) / (zval[3] - zval[2]);
-								xl[4] = lines[l].x = path[2].x = x[2] + t * (x[3] - x[2]);
-								yl[4] = lines[l++].y = path[2].y = y[2] + t * (y[3] - y[2]);
-								gog_renderer_draw_polygon (rend, path, FALSE);
-								gog_renderer_pop_style (rend);
-								zn = zx;
-							}
-							/* draw the saddle containing slice */
-							k = 0;
-							for (s = 0; s < 8; s++) {
-								path[k].code = (k)? ART_LINETO: ART_MOVETO;
-								if (xl[s] < 0.) {
-									if (s == 7)
-										break;
-									else if (s > 0)
-										s++;
-									r = s / 2;
-									path[k].x = x[r];
-									path[k++].y = y[r];
-								} else {
-									path[k].x = xl[s];
-									path[k++].y = yl[s];
-								}
-							}
-							path[k].code = ART_LINETO;
-							path[k].x = path[0].x;
-							path[k++].y = path[0].y;
-							path[k].code = ART_END;
-							style->outline.color = color[zn];
-							style->fill.pattern.back = color[zn];
-							gog_renderer_push_style (rend, style);
-							gog_renderer_draw_polygon (rend, path, FALSE);
-							gog_renderer_pop_style (rend);
-						}
-					} else {
-						k = 0;
-						for (s = 0; s < 8; s++) {
-							path[k].code = (k)? ART_LINETO: ART_MOVETO;
-							if (xl[s] < 0.) {
-								if (s == 7)
-									break;
-								else if (s > 0)
-									s++;
-								r = s / 2;
-								path[k].x = x[r];
-								path[k++].y = y[r];
-							} else {
-								path[k].x = xl[s];
-								path[k++].y = yl[s];
-							}
-						}
-						path[k].code = ART_LINETO;
-						path[k].x = path[0].x;
-						path[k++].y = path[0].y;
-						path[k].code = ART_END;
-						style->outline.color = color[zx];
-						style->fill.pattern.back = color[zx];
-						gog_renderer_push_style (rend, style);
-						gog_renderer_draw_polygon (rend, path, FALSE);
-						gog_renderer_pop_style (rend);
-					}
-				} else {
-					/* no saddle point visible */
-					if ((l + (zmax - zmin) * 2 + 1) >= lmax)
-						lines = art_renew (lines, ArtVpath, lmax += 64);
-					path[0].code = ART_MOVETO;
-					path[0].x = x[0];
-					path[0].y = y[0];
-					p = 1;
-					k = 1;
-					s = 0;
-					r = kmax;
-					while (zmin < zmax) {
-						style->outline.color = color[zmin];
-						style->fill.pattern.back = color[zmin];
-						gog_renderer_push_style (rend, style);
-						while (z[k] <= zmin && k < kmax) {
-							if (fabs (path[p-1].x - x[k]) > CONTOUR_EPSILON ||
-								fabs (path[p-1].y - y[k]) > CONTOUR_EPSILON) {
-								path[p].code = ART_LINETO;
-								path[p].x = x[k];
-								path[p++].y = y[k++];
-							} else
-								k++;	
-						}
-						while (z[r] <= zmin && r > 0)
-							r--;
-						zmin++;
-						t = (zmin - zval[k - 1]) / (zval[k] - zval[k - 1]);
-						path[p].code = ART_LINETO;
-						lines[l].code = ART_MOVETO_OPEN;
-						lines[l].x = path[p].x = x[k - 1] + t * (x[k] - x[k - 1]);
-						lines[l++].y = path[p].y = y[k - 1] + t * (y[k] - y[k - 1]);
-						if (fabs (path[p-1].x - path[p].x) > CONTOUR_EPSILON ||
-							fabs (path[p-1].y - path[p].y) > CONTOUR_EPSILON)
-							p++;
-						path[p].code = ART_LINETO;
-						lines[l].code = ART_LINETO;
-						if (r < kmax) {
-							t = (zmin - zval[r]) / (zval[r + 1] - zval[r]);
-							lines[l].x = path[p].x = x[r] + t * (x[r + 1] - x[r]);
-							lines[l++].y = path[p].y = y[r] + t * (y[r + 1] - y[r]);
-						} else {
-							t = (zmin - zval[r]) / (zval[0] - zval[r]);
-							lines[l].x = path[p].x = x[r] + t * (x[0] - x[r]);
-							lines[l++].y = path[p].y = y[r] + t * (y[0] - y[r]);
-						}
-						if (fabs (path[p-1].x - path[p].x) > CONTOUR_EPSILON ||
-							fabs (path[p-1].y - path[p].y) > CONTOUR_EPSILON)
-							p++;
-						if (s == 0) {
-							for (h = r + 1; h <= kmax; h++) {
-								if (fabs (path[p-1].x - x[h]) > CONTOUR_EPSILON ||
-									fabs (path[p-1].y - y[h]) > CONTOUR_EPSILON) {
-									path[p].code = ART_LINETO;
-									path[p].x = x[h];
-									path[p++].y = y[h];
-								}
-							}
-						} else {
-							for (h = r + 1; h < s; h++) {
-								if (fabs (path[p-1].x - x[h]) > CONTOUR_EPSILON ||
-									fabs (path[p-1].y - y[h]) > CONTOUR_EPSILON) {
-									path[p].code = ART_LINETO;
-									path[p].x = x[h];
-									path[p++].y = y[h];
-								}
-							}
-						}
-						s = r + 1;
-						if (fabs (path[p-1].x - path[0].x) > CONTOUR_EPSILON ||
-							fabs (path[p-1].y -path[0].y) > CONTOUR_EPSILON) {
-							path[p].code = ART_LINETO;
-							path[p].x = path[0].x;
-							path[p++].y = path[0].y;
-						} else {
-							/* use the exact values so that the polygon is closed */
-							path[p-1].x = path[0].x;
-							path[p-1].y = path[0].y;
-						}
-						path[p].code = ART_END;
-						gog_renderer_draw_polygon (rend, path, FALSE);
-						gog_renderer_pop_style (rend);
-						path[0].x = lines[l - 1].x;
-						path[0].y = lines[l - 1].y;
-						path[1].x = lines[l - 2].x;
-						path[1].y = lines[l - 2].y;
-						p = (fabs (path[0].x - path[1].x) > CONTOUR_EPSILON ||
-							fabs (path[0].y - path[1].y) > CONTOUR_EPSILON)?
-							2: 1;
-					}
-					if (fabs (path[0].x - path[1].x) < CONTOUR_EPSILON
-						&& fabs (path[0].y - path[1].y) < CONTOUR_EPSILON)
-						continue;
-					while (k < s) {
-						path[p].code = ART_LINETO;
-						path[p].x = x[k];
-						path[p++].y = y[k++];
-					}
-					path[p].code = ART_LINETO;
-					path[p].x = path[0].x;
-					path[p++].y = path[0].y;
-					path[p].code = ART_END;
-					style->outline.color = color[zmin];
-					style->fill.pattern.back = color[zmin];
-					gog_renderer_push_style (rend, style);
-					gog_renderer_draw_polygon (rend, path, FALSE);
-					gog_renderer_pop_style (rend);
-				}
+				y0 = go_data_vector_get_value (y_vec, j - 1);
+				y1 = go_data_vector_get_value (y_vec, j);
 			}
+			gog_chart_map_3d_to_view (chart_map, x0, y0,
+						  data[(j - 1) * imax + i - 1], x, y, NULL);
+			go_path_move_to (path, *x, *y);
+			gog_chart_map_3d_to_view (chart_map, x1, y0,
+						  data[(j - 1) * imax + i], x, y, NULL);
+			go_path_line_to (path, *x, *y);
+			gog_chart_map_3d_to_view (chart_map, x1, y1,
+						  data[j * imax + i], x, y, NULL);
+			go_path_line_to (path, *x, *y);
+			gog_chart_map_3d_to_view (chart_map, x0, y1,
+						  data[j * imax + i - 1], x, y, NULL);
+			go_path_line_to (path, *x, *y);
+			go_path_close (path);
+			gog_renderer_draw_shape (rend, path);
+			go_path_free (path);
+			//break;
 		}
-	}
-	lines[l].code = ART_END;
-	gog_renderer_push_style (rend, GOG_STYLED_OBJECT (series)->style);
-	gog_renderer_draw_path  (rend, lines);
 	gog_renderer_pop_style (rend);
-	gog_renderer_pop_clip (rend);
-	art_free (lines);
-	art_free (path);
-	g_object_unref (style);
-	gog_axis_map_free (x_map);
-	gog_axis_map_free (y_map);
+	gog_chart_map_3d_free (chart_map);
 }
 
 static void
-gog_contour_view_class_init (GogViewClass *view_klass)
+gog_surface_view_class_init (GogViewClass *view_klass)
 {
-	view_klass->render = gog_contour_view_render;
+	view_klass->render = gog_surface_view_render;
 }
 
-GSF_DYNAMIC_CLASS (GogContourView, gog_contour_view,
-	gog_contour_view_class_init, NULL,
+GSF_DYNAMIC_CLASS (GogSurfaceView, gog_surface_view,
+	gog_surface_view_class_init, NULL,
 	GOG_PLOT_VIEW_TYPE)
-
-/*****************************************************************************/
-
-static GogStyledObjectClass *series_parent_klass;
-
-static void
-gog_surface_series_update (GogObject *obj)
-{
-	GogSurfaceSeries *series = GOG_SURFACE_SERIES (obj);
-	GODataMatrixSize size, old_size;
-	GODataMatrix *mat;
-	GODataVector *vec;
-	int length;
-	size.rows = 0;
-	size.columns = 0;
-	if (series->base.values[2].data != NULL) {
-		old_size.rows = series->rows;
-		old_size.columns = series->columns;
-		mat = GO_DATA_MATRIX (series->base.values[2].data);
-		go_data_matrix_get_values (mat);
-		size = go_data_matrix_get_size (mat);
-	}
-	if (series->base.values[0].data != NULL) {
-		vec = GO_DATA_VECTOR (series->base.values[0].data);
-		go_data_vector_get_values (vec);
-		length = go_data_vector_get_len (vec);
-		if (length < size.columns)
-			size.columns = length;
-	}
-	if (series->base.values[1].data != NULL) {
-		vec = GO_DATA_VECTOR (series->base.values[1].data);
-		go_data_vector_get_values (vec);
-		length = go_data_vector_get_len (vec);
-		if (length < size.rows)
-			size.rows = length;
-	}
-	series->rows = size.rows;
-	series->columns = size.columns;
-
-	/* queue plot for redraw */
-	gog_object_request_update (GOG_OBJECT (series->base.plot));
-/*	gog_plot_request_cardinality_update (series->base.plot);*/
-
-	if (series_parent_klass->base.update)
-		series_parent_klass->base.update (obj);
-}
-
-static void
-gog_surface_series_init_style (GogStyledObject *gso, GogStyle *style)
-{
-	series_parent_klass->init_style (gso, style);
-}
-
-static void
-gog_surface_series_class_init (GogStyledObjectClass *gso_klass)
-{
-	GogObjectClass * obj_klass = (GogObjectClass *) gso_klass;
-
-	series_parent_klass = g_type_class_peek_parent (gso_klass);
-	gso_klass->init_style = gog_surface_series_init_style;
-	obj_klass->update = gog_surface_series_update;
-}
-
-
-GSF_DYNAMIC_CLASS (GogSurfaceSeries, gog_surface_series,
-	gog_surface_series_class_init, NULL,
-	GOG_SERIES_TYPE)
-
-G_MODULE_EXPORT void
-go_plugin_init (GOPlugin *plugin, GOCmdContext *cc)
-{
-	GTypeModule *module = go_plugin_get_type_module (plugin);
-	gog_contour_plot_register_type (module);
-	gog_contour_view_register_type (module);
-	gog_surface_series_register_type (module);
-	xl_contour_plot_register_type (module);
-	xl_surface_series_register_type (module);
-}
-
-G_MODULE_EXPORT void
-go_plugin_shutdown (GOPlugin *plugin, GOCmdContext *cc)
-{
-}

Modified: trunk/plugins/plot_surface/gog-surface.h
==============================================================================
--- trunk/plugins/plot_surface/gog-surface.h	(original)
+++ trunk/plugins/plot_surface/gog-surface.h	Mon May 12 09:02:12 2008
@@ -22,42 +22,28 @@
 #ifndef GOG_SURFACE_H
 #define GOG_SURFACE_H
 
-#include <goffice/graph/gog-plot-impl.h>
+#include "gog-xyz.h"
 
 G_BEGIN_DECLS
 
 /*-----------------------------------------------------------------------------
  *
- * GogContourPlot
+ * GogSurfacePlot
  *
  *-----------------------------------------------------------------------------
  */
 
-typedef struct {
-	GogPlot	base;
-	
-	unsigned rows, columns;
-	gboolean transposed;
-	struct {
-		double minima, maxima;
-		GOFormat *fmt;
-	} x, y, z;
-	double *plotted_data;
-} GogContourPlot;
-
-#define GOG_CONTOUR_PLOT_TYPE	(gog_contour_plot_get_type ())
-#define GOG_CONTOUR_PLOT(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOG_CONTOUR_PLOT_TYPE, GogContourPlot))
-#define GOG_IS_PLOT_CONTOUR(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOG_CONTOUR_PLOT_TYPE))
-
-GType gog_contour_plot_get_type (void);
+typedef GogXYZPlot GogSurfacePlot;
+typedef GogXYZPlotClass GogSurfacePlotClass;
+ 
+#define GOG_SURFACE_PLOT_TYPE	(gog_surface_plot_get_type ())
+#define GOG_SURFACE_PLOT(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOG_SURFACE_PLOT_TYPE, GogSurfacePlot))
+#define GOG_IS_SURFACE_PLOT(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOG_SURFACE_PLOT_TYPE))
 
-typedef struct {
-	GogPlotClass	base;
+GType gog_surface_plot_get_type (void);
+void  gog_surface_plot_register_type   (GTypeModule *module);
 
-	double * (*build_matrix) (GogContourPlot const *plot, gboolean *cardinality_changed);
-} GogContourPlotClass;
-
-#define GOG_CONTOUR_PLOT_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GOG_CONTOUR_PLOT_TYPE, GogContourPlotClass))
+void  gog_surface_view_register_type   (GTypeModule *module);
 
 G_END_DECLS
 

Copied: trunk/plugins/plot_surface/gog-xyz-prefs.c (from r2048, /trunk/plugins/plot_surface/gog-contour-prefs.c)
==============================================================================
--- /trunk/plugins/plot_surface/gog-contour-prefs.c	(original)
+++ trunk/plugins/plot_surface/gog-xyz-prefs.c	Mon May 12 09:02:12 2008
@@ -1,64 +0,0 @@
-/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * gog-bubble-prefs.c
- *
- * Copyright (C) 2004 Jean Brefort (jean brefort normalesup org)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * 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/goffice-config.h>
-#include "gog-surface.h"
-#include <goffice/gtk/goffice-gtk.h>
-#include <goffice/app/go-plugin.h>
-
-#include <gtk/gtktogglebutton.h>
-
-#include <string.h>
-
-GtkWidget *gog_contour_plot_pref   (GogContourPlot *plot, GOCmdContext *cc);
-
-static void
-cb_transpose (GtkToggleButton *btn, GObject *plot)
-{
-	g_object_set (plot, "transposed", gtk_toggle_button_get_active (btn), NULL);
-}
-
-GtkWidget *
-gog_contour_plot_pref (GogContourPlot *plot, GOCmdContext *cc)
-{
-	GtkWidget  *w;
-	char const *dir = go_plugin_get_dir_name (
-		go_plugins_get_plugin_by_id ("GOffice_plot_surface"));
-	char	 *path = g_build_filename (dir, "gog-contour-prefs.glade", NULL);
-	GladeXML *gui = go_libglade_new (path, "gog_contour_prefs", GETTEXT_PACKAGE, cc);
-
-	g_free (path);
-        if (gui == NULL)
-                return NULL;
-
-
-	w = glade_xml_get_widget (gui, "transpose");
-	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), plot->transposed);
-	g_signal_connect (G_OBJECT (w),
-		"toggled",
-		G_CALLBACK (cb_transpose), plot);
-
-	w = glade_xml_get_widget (gui, "gog_contour_prefs");
-	g_object_set_data_full (G_OBJECT (w),
-		"state", gui, (GDestroyNotify)g_object_unref);
-
-	return w;
-}

Copied: trunk/plugins/plot_surface/gog-xyz-prefs.glade (from r2048, /trunk/plugins/plot_surface/gog-contour-prefs.glade)
==============================================================================
--- /trunk/plugins/plot_surface/gog-contour-prefs.glade	(original)
+++ trunk/plugins/plot_surface/gog-xyz-prefs.glade	Mon May 12 09:02:12 2008
@@ -1,54 +0,0 @@
-<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
-<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd";>
-
-<glade-interface>
-
-<widget class="GtkWindow" id="window1">
-  <property name="title" translatable="yes">window1</property>
-  <property name="type">GTK_WINDOW_TOPLEVEL</property>
-  <property name="window_position">GTK_WIN_POS_NONE</property>
-  <property name="modal">False</property>
-  <property name="resizable">True</property>
-  <property name="destroy_with_parent">False</property>
-  <property name="decorated">True</property>
-  <property name="skip_taskbar_hint">False</property>
-  <property name="skip_pager_hint">False</property>
-  <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
-  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
-
-  <child>
-    <widget class="GtkTable" id="gog_contour_prefs">
-      <property name="border_width">5</property>
-      <property name="visible">True</property>
-      <property name="n_rows">1</property>
-      <property name="n_columns">1</property>
-      <property name="homogeneous">False</property>
-      <property name="row_spacing">5</property>
-      <property name="column_spacing">5</property>
-
-      <child>
-	<widget class="GtkCheckButton" id="transpose">
-	  <property name="visible">True</property>
-	  <property name="can_focus">True</property>
-	  <property name="label" translatable="yes">Transpose</property>
-	  <property name="use_underline">True</property>
-	  <property name="relief">GTK_RELIEF_NORMAL</property>
-	  <property name="focus_on_click">True</property>
-	  <property name="active">False</property>
-	  <property name="inconsistent">False</property>
-	  <property name="draw_indicator">True</property>
-	</widget>
-	<packing>
-	  <property name="left_attach">0</property>
-	  <property name="right_attach">1</property>
-	  <property name="top_attach">0</property>
-	  <property name="bottom_attach">1</property>
-	  <property name="x_options">fill</property>
-	  <property name="y_options"></property>
-	</packing>
-      </child>
-    </widget>
-  </child>
-</widget>
-
-</glade-interface>

Added: trunk/plugins/plot_surface/gog-xyz.c
==============================================================================
--- (empty file)
+++ trunk/plugins/plot_surface/gog-xyz.c	Mon May 12 09:02:12 2008
@@ -0,0 +1,448 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * gog-xyz.c
+ *
+ * Copyright (C) 2004-2007 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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/goffice-config.h>
+#include "gog-xyz.h"
+#include "gog-contour.h"
+#include "gog-surface.h"
+#include "xl-surface.h"
+#include <goffice/app/module-plugin-defs.h>
+#include <goffice/data/go-data.h>
+#include <goffice/graph/gog-chart.h>
+#include <goffice/math/go-math.h>
+#include <goffice/utils/go-format.h>
+
+#include <glib/gi18n-lib.h>
+#include <gsf/gsf-impl-utils.h>
+
+GOFFICE_PLUGIN_MODULE_HEADER;
+/*-----------------------------------------------------------------------------
+ *
+ *  GogContourPlot
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+enum {
+	XYZ_PROP_0,
+	XYZ_PROP_TRANSPOSED
+};
+
+static GogObjectClass *plot_xyz_parent_klass;
+
+/**
+ * gog_xyz_plot_build_matrix :
+ * @plot :
+ *
+ * builds a table of normalized values: first slice = 0-1 second = 1-2,... if any.
+ **/
+
+double *
+gog_xyz_plot_build_matrix (GogXYZPlot const *plot, gboolean *cardinality_changed)
+{
+	GogXYZPlotClass *klass = GOG_XYZ_PLOT_GET_CLASS (plot);
+	return klass->build_matrix (plot, cardinality_changed);
+}
+
+static void
+gog_xyz_plot_update_3d (GogPlot *plot)
+{
+	GogXYZPlot *xyz = GOG_XYZ_PLOT (plot);
+	gboolean cardinality_changed = FALSE;
+
+	if (plot->series == NULL)
+		return;
+
+	xyz->plotted_data = gog_xyz_plot_build_matrix (xyz, &cardinality_changed);
+	if (cardinality_changed) {
+		/*	gog_plot_request_cardinality_update can't be called from here
+		 *  since the plot might be updating.
+		 */
+		GogChart *chart = GOG_CHART (GOG_OBJECT (plot)->parent);
+		plot->cardinality_valid = FALSE;
+		if (chart != NULL)
+			gog_chart_request_cardinality_update (chart);
+	}
+}
+
+#ifdef GOFFICE_WITH_GTK
+extern gpointer gog_xyz_plot_pref (GogXYZPlot *plot, GOCmdContext *cc);
+static void
+gog_xyz_plot_populate_editor (GogObject *item,
+				  GogEditor *editor,
+				  G_GNUC_UNUSED GogDataAllocator *dalloc,
+				  GOCmdContext *cc)
+{
+	gog_editor_add_page (editor,
+			     gog_xyz_plot_pref (GOG_XYZ_PLOT (item), cc),
+			     _("Properties"));
+
+	(GOG_OBJECT_CLASS (plot_xyz_parent_klass)->populate_editor) (item, editor, dalloc, cc);
+}
+#endif
+
+static void
+gog_xyz_plot_clear_formats (GogXYZPlot *plot)
+{
+	if (plot->x.fmt != NULL) {
+		go_format_unref (plot->x.fmt);
+		plot->x.fmt = NULL;
+	}
+	if (plot->y.fmt != NULL) {
+		go_format_unref (plot->y.fmt);
+		plot->y.fmt = NULL;
+	}
+	if (plot->z.fmt != NULL) {
+		go_format_unref (plot->z.fmt);
+		plot->z.fmt = NULL;
+	}
+}
+
+static void
+gog_xyz_plot_update (GogObject *obj)
+{
+	GogXYZPlot * model = GOG_XYZ_PLOT(obj);
+	GogXYZSeries * series;
+	GODataVector *vec;
+	GODataMatrix *mat;
+	double tmp_min, tmp_max;
+
+	if (model->base.series == NULL)
+		return;
+
+	series = GOG_XYZ_SERIES (model->base.series->data);
+	if (!gog_series_is_valid (GOG_SERIES (series)))
+		return;
+
+	if ((vec = GO_DATA_VECTOR (series->base.values[0].data)) != NULL) {
+		if (model->x.fmt == NULL)
+			model->x.fmt = go_data_preferred_fmt (series->base.values[0].data);
+		if (go_data_vector_vary_uniformly (vec))
+			go_data_vector_get_minmax (vec, &tmp_min, &tmp_max);
+		else
+			tmp_min = tmp_max = go_nan;
+	} else {
+		tmp_min = 0;
+		tmp_max = series->columns - 1;
+	}
+
+	if ((model->columns != series->columns)
+			|| (tmp_min != model->x.minima)
+			|| (tmp_max != model->x.maxima)) {
+		model->columns = series->columns;
+		model->x.minima = tmp_min;
+		model->x.maxima = tmp_max;
+		gog_axis_bound_changed (model->base.axis[(model->transposed)? GOG_AXIS_Y: GOG_AXIS_X],
+				GOG_OBJECT (model));
+	}
+
+	if ((vec = GO_DATA_VECTOR (series->base.values[1].data)) != NULL) {
+		if (model->y.fmt == NULL)
+			model->y.fmt = go_data_preferred_fmt (series->base.values[1].data);
+		if (go_data_vector_vary_uniformly (vec))
+			go_data_vector_get_minmax (vec, &tmp_min, &tmp_max);
+		else
+			tmp_min = tmp_max = go_nan;
+	} else {
+		tmp_min = 0;
+		tmp_max = series->rows - 1;
+	}
+
+	if ((model->rows != series->rows)
+			|| (tmp_min != model->y.minima)
+			|| (tmp_max != model->y.maxima)) {
+		model->rows = series->rows;
+		model->y.minima = tmp_min;
+		model->y.maxima = tmp_max;
+		gog_axis_bound_changed (model->base.axis[(model->transposed)? GOG_AXIS_X: GOG_AXIS_Y],
+				GOG_OBJECT (model));
+	}
+
+	g_free (model->plotted_data);
+	model->plotted_data = NULL;
+	mat = GO_DATA_MATRIX (series->base.values[2].data);
+	go_data_matrix_get_minmax (mat, &tmp_min, &tmp_max);
+	if ((tmp_min != model->z.minima)
+			|| (tmp_max != model->z.maxima)) {
+		model->z.minima = tmp_min;
+		model->z.maxima = tmp_max;
+		gog_axis_bound_changed (
+			model->base.axis[GOG_XYZ_PLOT_GET_CLASS (model)->third_axis],
+			GOG_OBJECT (model));
+	} else
+		gog_xyz_plot_update_3d (GOG_PLOT (model));
+	
+	gog_object_emit_changed (GOG_OBJECT (obj), FALSE);
+	if (plot_xyz_parent_klass->update)
+		plot_xyz_parent_klass->update (obj);
+}
+
+static GOData *
+gog_xyz_plot_axis_get_bounds (GogPlot *plot, GogAxisType axis, 
+				  GogPlotBoundInfo * bounds)
+{
+	GogXYZSeries *series;
+	GogXYZPlot *xyz = GOG_XYZ_PLOT (plot);
+	GODataVector *vec = NULL;
+	double min, max;
+	GOFormat *fmt;
+	if (!plot->series)
+		return NULL;
+	series = GOG_XYZ_SERIES (plot->series->data);
+	if ((axis == GOG_AXIS_Y && xyz->transposed) ||
+		(axis == GOG_AXIS_X && !xyz->transposed)) {
+		vec = GO_DATA_VECTOR (series->base.values[0].data);
+		fmt = xyz->x.fmt;
+		min = xyz->x.minima;
+		max = xyz->x.maxima;
+	} else if (axis == GOG_AXIS_X || axis == GOG_AXIS_Y) {
+		vec = GO_DATA_VECTOR (series->base.values[1].data);
+		fmt = xyz->y.fmt;
+		min = xyz->y.minima;
+		max = xyz->y.maxima;
+	} else {
+		if (bounds->fmt == NULL && xyz->z.fmt != NULL)
+			bounds->fmt = go_format_ref (xyz->z.fmt);
+		bounds->val.minima = xyz->z.minima;
+		bounds->val.maxima = xyz->z.maxima;
+		return NULL;
+	}
+	if (bounds->fmt == NULL && fmt != NULL)
+		bounds->fmt = go_format_ref (fmt);
+	if (go_finite (min)) {
+		bounds->logical.minima = bounds->val.minima = min;
+		bounds->logical.maxima = bounds->val.maxima = max;
+		bounds->is_discrete = FALSE;
+	} else {
+		bounds->val.minima = 1.;
+		bounds->logical.minima = 1.;
+		bounds->logical.maxima = go_nan;
+		bounds->is_discrete    = TRUE;
+		bounds->center_on_ticks = TRUE;
+		bounds->val.maxima = ((axis == GOG_AXIS_Y && xyz->transposed) ||
+		(axis == GOG_AXIS_X && !xyz->transposed)) ?
+			series->columns:
+			series->rows;
+	}
+	return (GOData*) vec;
+}
+
+static void
+gog_xyz_plot_finalize (GObject *obj)
+{
+	GogXYZPlot *plot = GOG_XYZ_PLOT (obj);
+	gog_xyz_plot_clear_formats (plot);
+	g_free (plot->plotted_data);
+	G_OBJECT_CLASS (plot_xyz_parent_klass)->finalize (obj);
+}
+
+static void
+gog_xyz_plot_set_property (GObject *obj, guint param_id,
+			     GValue const *value, GParamSpec *pspec)
+{
+	GogXYZPlot *plot = GOG_XYZ_PLOT (obj);
+
+	switch (param_id) {
+	case XYZ_PROP_TRANSPOSED :
+		if (!plot->transposed != !g_value_get_boolean (value)) {
+			plot->transposed = g_value_get_boolean (value);
+			if (NULL != plot->base.axis[GOG_AXIS_X])
+				gog_axis_bound_changed (plot->base.axis[GOG_AXIS_X], GOG_OBJECT (plot));
+			if (NULL != plot->base.axis[GOG_AXIS_Y])
+				gog_axis_bound_changed (plot->base.axis[GOG_AXIS_Y], GOG_OBJECT (plot));
+			g_free (plot->plotted_data);
+			plot->plotted_data = NULL;
+		}
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+		 return; /* NOTE : RETURN */
+	}
+	gog_object_emit_changed (GOG_OBJECT (obj), FALSE);
+}
+
+static void
+gog_xyz_plot_get_property (GObject *obj, guint param_id,
+			     GValue *value, GParamSpec *pspec)
+{
+	GogXYZPlot *plot = GOG_XYZ_PLOT (obj);
+
+	switch (param_id) {
+	case XYZ_PROP_TRANSPOSED :
+		g_value_set_boolean (value, plot->transposed);
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+		 break;
+	}
+}
+
+static void
+gog_xyz_plot_class_init (GogXYZPlotClass *klass)
+{
+	GogPlotClass *gog_plot_klass = (GogPlotClass*) klass;
+	GObjectClass   *gobject_klass = (GObjectClass *) klass;
+	GogObjectClass *gog_object_klass = (GogObjectClass *) klass;
+
+	plot_xyz_parent_klass = g_type_class_peek_parent (klass);
+
+	gobject_klass->finalize     = gog_xyz_plot_finalize;
+	gobject_klass->set_property = gog_xyz_plot_set_property;
+	gobject_klass->get_property = gog_xyz_plot_get_property;
+	g_object_class_install_property (gobject_klass, XYZ_PROP_TRANSPOSED,
+		g_param_spec_boolean ("transposed", 
+			_("Transposed"),
+			_("Transpose the plot"),
+			FALSE, 
+			GSF_PARAM_STATIC | G_PARAM_READWRITE|GOG_PARAM_PERSISTENT));
+
+	/* Fill in GOGObject superclass values */
+	gog_object_klass->update	= gog_xyz_plot_update;
+#ifdef GOFFICE_WITH_GTK
+	gog_object_klass->populate_editor	= gog_xyz_plot_populate_editor;
+#endif
+
+	{
+		static GogSeriesDimDesc dimensions[] = {
+			{ N_("X"), GOG_SERIES_SUGGESTED, FALSE,
+			  GOG_DIM_LABEL, GOG_MS_DIM_CATEGORIES },
+			{ N_("Y"), GOG_SERIES_SUGGESTED, FALSE,
+			  GOG_DIM_LABEL, GOG_MS_DIM_CATEGORIES },
+			{ N_("Z"), GOG_SERIES_REQUIRED, FALSE,
+			  GOG_DIM_MATRIX, GOG_MS_DIM_VALUES },
+		};
+		gog_plot_klass->desc.series.dim = dimensions;
+		gog_plot_klass->desc.series.num_dim = G_N_ELEMENTS (dimensions);
+		gog_plot_klass->desc.series.style_fields = GOG_STYLE_LINE;
+	}
+
+	/* Fill in GogPlotClass methods */
+	gog_plot_klass->desc.num_series_min = 1;
+	gog_plot_klass->desc.num_series_max = 1;
+	gog_plot_klass->series_type = gog_xyz_series_get_type();
+	gog_plot_klass->axis_get_bounds	= gog_xyz_plot_axis_get_bounds;
+	gog_plot_klass->update_3d = gog_xyz_plot_update_3d;
+}
+
+static void
+gog_xyz_plot_init (GogXYZPlot *xyz)
+{
+	xyz->rows = xyz->columns = 0;
+	xyz->transposed = FALSE;
+	xyz->x.minima = xyz->x.maxima = xyz->y.minima
+		= xyz->y.maxima = xyz->z.minima = xyz->z.maxima = go_nan;
+	xyz->x.fmt = xyz->y.fmt = xyz->z.fmt = NULL;
+	xyz->plotted_data = NULL;
+}
+
+GSF_DYNAMIC_CLASS_ABSTRACT (GogXYZPlot, gog_xyz_plot,
+	gog_xyz_plot_class_init, gog_xyz_plot_init,
+	GOG_PLOT_TYPE)
+
+/*****************************************************************************/
+
+static GogStyledObjectClass *series_parent_klass;
+
+static void
+gog_xyz_series_update (GogObject *obj)
+{
+	GogXYZSeries *series = GOG_XYZ_SERIES (obj);
+	GODataMatrixSize size, old_size;
+	GODataMatrix *mat;
+	GODataVector *vec;
+	int length;
+	size.rows = 0;
+	size.columns = 0;
+	if (series->base.values[2].data != NULL) {
+		old_size.rows = series->rows;
+		old_size.columns = series->columns;
+		mat = GO_DATA_MATRIX (series->base.values[2].data);
+		go_data_matrix_get_values (mat);
+		size = go_data_matrix_get_size (mat);
+	}
+	if (series->base.values[0].data != NULL) {
+		vec = GO_DATA_VECTOR (series->base.values[0].data);
+		go_data_vector_get_values (vec);
+		length = go_data_vector_get_len (vec);
+		if (length < size.columns)
+			size.columns = length;
+	}
+	if (series->base.values[1].data != NULL) {
+		vec = GO_DATA_VECTOR (series->base.values[1].data);
+		go_data_vector_get_values (vec);
+		length = go_data_vector_get_len (vec);
+		if (length < size.rows)
+			size.rows = length;
+	}
+	series->rows = size.rows;
+	series->columns = size.columns;
+
+	/* queue plot for redraw */
+	gog_object_request_update (GOG_OBJECT (series->base.plot));
+/*	gog_plot_request_cardinality_update (series->base.plot);*/
+
+	if (series_parent_klass->base.update)
+		series_parent_klass->base.update (obj);
+}
+
+static void
+gog_xyz_series_init_style (GogStyledObject *gso, GogStyle *style)
+{
+	series_parent_klass->init_style (gso, style);
+}
+
+static void
+gog_xyz_series_class_init (GogStyledObjectClass *gso_klass)
+{
+	GogObjectClass * obj_klass = (GogObjectClass *) gso_klass;
+
+	series_parent_klass = g_type_class_peek_parent (gso_klass);
+	gso_klass->init_style = gog_xyz_series_init_style;
+	obj_klass->update = gog_xyz_series_update;
+}
+
+
+GSF_DYNAMIC_CLASS (GogXYZSeries, gog_xyz_series,
+	gog_xyz_series_class_init, NULL,
+	GOG_SERIES_TYPE)
+
+/*****************************************************************************/
+
+G_MODULE_EXPORT void
+go_plugin_init (GOPlugin *plugin, GOCmdContext *cc)
+{
+	GTypeModule *module = go_plugin_get_type_module (plugin);
+	gog_xyz_plot_register_type (module);
+	gog_contour_plot_register_type (module);
+	gog_contour_view_register_type (module);
+	gog_surface_plot_register_type (module);
+	gog_surface_view_register_type (module);
+	gog_xyz_series_register_type (module);
+	xl_y_labels_register_type (module);
+	xl_xyz_series_register_type (module);
+	xl_contour_plot_register_type (module);
+	xl_surface_plot_register_type (module);
+}
+
+G_MODULE_EXPORT void
+go_plugin_shutdown (GOPlugin *plugin, GOCmdContext *cc)
+{
+}

Added: trunk/plugins/plot_surface/gog-xyz.h
==============================================================================
--- (empty file)
+++ trunk/plugins/plot_surface/gog-xyz.h	Mon May 12 09:02:12 2008
@@ -0,0 +1,81 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * gog-xyz.h
+ *
+ * Copyright (C) 2004-2007 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 GOG_XYZ_H
+#define GOG_XYZ_H
+
+#include <goffice/graph/gog-plot-impl.h>
+
+G_BEGIN_DECLS
+
+/*-----------------------------------------------------------------------------
+ *
+ * GogContourPlot
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+typedef struct {
+	GogPlot	base;
+	
+	unsigned rows, columns;
+	gboolean transposed;
+	struct {
+		double minima, maxima;
+		GOFormat *fmt;
+	} x, y, z;
+	double *plotted_data;
+} GogXYZPlot;
+
+#define GOG_XYZ_PLOT_TYPE	(gog_xyz_plot_get_type ())
+#define GOG_XYZ_PLOT(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOG_XYZ_PLOT_TYPE, GogXYZPlot))
+#define GOG_IS_PLOT_XYZ(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOG_XYZ_PLOT_TYPE))
+
+GType gog_xyz_plot_get_type (void);
+
+typedef struct {
+	GogPlotClass	base;
+
+	GogAxisType third_axis;
+
+	double * (*build_matrix) (GogXYZPlot const *plot, gboolean *cardinality_changed);
+} GogXYZPlotClass;
+
+#define GOG_XYZ_PLOT_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GOG_XYZ_PLOT_TYPE, GogXYZPlotClass))
+
+double *gog_xyz_plot_build_matrix (GogXYZPlot const *plot, gboolean *cardinality_changed);
+
+typedef struct {
+	GogSeries base;
+	
+	unsigned rows, columns;
+} GogXYZSeries;
+typedef GogSeriesClass GogXYZSeriesClass;
+
+#define GOG_XYZ_SERIES_TYPE	(gog_xyz_series_get_type ())
+#define GOG_XYZ_SERIES(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOG_XYZ_SERIES_TYPE, GogXYZSeries))
+#define GOG_IS_XYZ_SERIES(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOG_XYZ_SERIES_TYPE))
+
+GType gog_xyz_series_get_type (void);
+
+G_END_DECLS
+
+#endif /* GOG_XYZ_H */

Modified: trunk/plugins/plot_surface/plot-types.xml.in
==============================================================================
--- trunk/plugins/plot_surface/plot-types.xml.in	(original)
+++ trunk/plugins/plot_surface/plot-types.xml.in	Mon May 12 09:02:12 2008
@@ -7,4 +7,9 @@
 		_description="Contour plot."
 		sample_image_file="chart_contour_1_1.png">
 	</Type>
+	<Type _name="Surface" row="2" col="1"
+		engine="GogSurfacePlot" family="Surface"
+		_description="Surface plot."
+		sample_image_file="chart_surface_2_1.png">
+	</Type>
 </Types>

Modified: trunk/plugins/plot_surface/plugin.xml.in
==============================================================================
--- trunk/plugins/plot_surface/plugin.xml.in	(original)
+++ trunk/plugins/plot_surface/plugin.xml.in	Mon May 12 09:02:12 2008
@@ -18,6 +18,16 @@
 				<description>Excel (TM) compatibility contour plotting engine</description>
 			</information>
 		</service>
+		<service type="plot_engine" id="GogSurfacePlot">
+			<information>
+				<_description>Surface plotting engine</_description>
+			</information>
+		</service>
+		<service type="plot_engine" id="XLSurfacePlot">
+			<information>
+				<description>Excel (TM) compatibility surface plotting engine</description>
+			</information>
+		</service>
 		<service type="plot_type" id="surface">
 			<file>plot-types.xml</file>
 			<information>

Modified: trunk/plugins/plot_surface/xl-surface.c
==============================================================================
--- trunk/plugins/plot_surface/xl-surface.c	(original)
+++ trunk/plugins/plot_surface/xl-surface.c	Mon May 12 09:02:12 2008
@@ -30,91 +30,91 @@
 #include <goffice/math/go-math.h>
 #include <goffice/utils/go-format.h>
 
-static GogObjectClass *xl_contour_parent_klass;
-typedef GogSeries XLSurfaceSeries;
-typedef GogSeriesClass XLSurfaceSeriesClass;
+typedef struct {
+	char const **y_labels;
+} XlYLabels;
+
+typedef GTypeInterface XlYLabelsClass;
+
+#define XL_Y_LABELS_TYPE		(xl_y_labels_get_type ())
+#define XL_Y_LABELS(o)			(G_TYPE_CHECK_INSTANCE_CAST ((o), XL_Y_LABELS_TYPE, XlYLabels))
+//#define IS_XL_Y_LABELS(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), XL_Y_LABELS_TYPE))
+//#define XL_Y_LABELS_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST ((k), XL_Y_LABELS_TYPE, XlYLabelsClass))
+//#define IS_XL_Y_LABELS_CLASS(k)		(G_TYPE_CHECK_CLASS_TYPE ((k), XL_Y_LABELS))
+//#define XL_Y_LABELS_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_INTERFACE ((o), XL_Y_LABELS, XlYLabelsClass))
 
-#define XL_SURFACE_SERIES_TYPE	(xl_surface_series_get_type ())
-#define XL_SURFACE_SERIES(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), XL_SURFACE_SERIES_TYPE, XLSurfaceSeries))
-#define XL_IS_SURFACE_SERIES(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), XL_SURFACE_SERIES_TYPE))
+GSF_DYNAMIC_CLASS (XlYLabels, xl_y_labels, NULL, NULL, G_TYPE_INTERFACE);
 
-static GType xl_surface_series_get_type (void);
+static void
+xl_labels_init (XlYLabels *labels)
+{
+	labels->y_labels = NULL;
+}
 
 /*****************************************************************************/
 
-typedef GogContourPlotClass XLContourPlotClass;
+typedef GogSeries XlXYZSeries;
+typedef GogSeriesClass XlXYZSeriesClass;
 
-static double *
-xl_contour_plot_build_matrix (GogContourPlot const *plot,
-			gboolean *cardinality_changed)
+#define XL_XYZ_SERIES_TYPE	(xl_xyz_series_get_type ())
+#define XL_XYZ_SERIES(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), XL_XYZ_SERIES_TYPE, XlXYZSeries))
+#define XL_IS_XYZ_SERIES(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), XL_XYZ_SERIES_TYPE))
+
+static GType xl_xyz_series_get_type (void);
+
+static GogStyledObjectClass *series_parent_klass;
+
+static void
+xl_xyz_series_update (GogObject *obj)
 {
-	unsigned i, j, length;
-	GogAxisMap *map;
-	GogAxisTick *zticks;
-	GogAxis *axis = plot->base.axis[GOG_AXIS_PSEUDO_3D];
-	unsigned nticks;
-	double x[2], val;
-	GogSeries *series = NULL;
-	GODataVector *vec;
-	unsigned n = plot->rows * plot->columns;
-	double *data, minimum, maximum;
-	unsigned max;
-	GSList *ptr;
+	XlXYZSeries *series = XL_XYZ_SERIES (obj);
+	int x_len = 0, z_len = 0;
 
-	if (!gog_axis_get_bounds (axis, &minimum, &maximum))
-		return NULL;
-	data = g_new (double, n);
-	nticks = gog_axis_get_ticks (axis, &zticks);
-	map = gog_axis_map_new (axis, 0, 1);
-	for (i = j = 0; i < nticks; i++)
-		if (zticks[i].type == GOG_AXIS_TICK_MAJOR) {
-			x[j++] = gog_axis_map_to_view (map, zticks[i].position);
-			if (j > 1)
-				break;
-		}
-	x[1] -= x[0];
+	if (series->values[1].data != NULL)
+		z_len = go_data_vector_get_len (
+			GO_DATA_VECTOR (series->values[1].data));
+	if (series->values[0].data != NULL)
+		x_len = go_data_vector_get_len (
+			GO_DATA_VECTOR (series->values[0].data));
+	else
+		x_len = z_len;
+	series->num_elements = MIN (x_len, z_len);
 
-	for (i = 0, ptr = plot->base.series ; ptr != NULL ; ptr = ptr->next) {
-		series = ptr->data;
-		if (!gog_series_is_valid (GOG_SERIES (series)))
-			continue;
-		vec = GO_DATA_VECTOR (series->values[1].data);
-		length = go_data_vector_get_len (vec);
-		for (j = 0; j < plot->columns; j++) {
-			/* The vector might be too short, excel is so ugly ;-) */
-			val = (j < length)? gog_axis_map_to_view (map,
-					go_data_vector_get_value (vec, j)): 0.;
-			/* This is an excel compatible plot, so let's be compatible */
-			if (val == go_nan || !go_finite (val))
-				val = 0.;
-			if (fabs (val) == DBL_MAX)
-				val = go_nan;
-			else {
-				val = val/ x[1] - x[0];
-				if (val < 0) {
-					val = go_nan;
-				}
-			}
-			data[i * plot->columns + j] = val;
-		}
-		i++;
-	}
-	g_return_val_if_fail (series != NULL, NULL);
-	max = (unsigned) ceil (1 / x[1]);
-	series = plot->base.series->data;
-	if (series->num_elements != max) {
-		series->num_elements = max;
-		*cardinality_changed = TRUE;
-	}
-	gog_axis_map_free (map);
-	return data;
+	/* queue plot for redraw */
+	gog_object_request_update (GOG_OBJECT (series->plot));
+
+	if (series_parent_klass->base.update)
+		series_parent_klass->base.update (obj);
 }
 
 static void
-xl_contour_plot_update (GogObject *obj)
+xl_xyz_series_init_style (GogStyledObject *gso, GogStyle *style)
 {
-	GogContourPlot * model = GOG_CONTOUR_PLOT(obj);
-	XLSurfaceSeries * series;
+	series_parent_klass->init_style (gso, style);
+}
+
+static void
+xl_xyz_series_class_init (GogStyledObjectClass *gso_klass)
+{
+	GogObjectClass * obj_klass = (GogObjectClass *) gso_klass;
+
+	series_parent_klass = g_type_class_peek_parent (gso_klass);
+	gso_klass->init_style = xl_xyz_series_init_style;
+	obj_klass->update = xl_xyz_series_update;
+}
+
+
+GSF_DYNAMIC_CLASS (XlXYZSeries, xl_xyz_series,
+	xl_xyz_series_class_init, NULL,
+	GOG_SERIES_TYPE)
+
+/*****************************************************************************/
+
+static void
+xl_xyz_plot_update (GogObject *obj)
+{
+	GogXYZPlot * model = GOG_XYZ_PLOT(obj);
+	XlXYZSeries * series;
 	double zmin =  DBL_MAX, zmax = -DBL_MAX, tmp_min, tmp_max;
 	GSList *ptr;
 	model->rows = 0;
@@ -161,7 +161,7 @@
 			|| (zmax != model->z.maxima)) {
 		model->z.minima = zmin;
 		model->z.maxima = zmax;
-		gog_axis_bound_changed (model->base.axis[GOG_AXIS_PSEUDO_3D], GOG_OBJECT (model));
+		gog_axis_bound_changed (model->base.axis[GOG_XYZ_PLOT_GET_CLASS (model)->third_axis], obj);
 	} else
 		gog_plot_update_3d (GOG_PLOT (model));
 
@@ -172,47 +172,48 @@
 static GODataVector *
 get_y_vector (GogPlot *plot)
 {
-	XLContourPlot *contour = XL_CONTOUR_PLOT (plot);
+	GogXYZPlot *xyz = GOG_XYZ_PLOT (plot);
+	XlYLabels *labels = XL_Y_LABELS (plot);
 	GSList *ptr;
 	int i;
 
-	g_free (contour->y_labels);
-	contour->y_labels = g_new0 (char const *, contour->base.rows);
+	g_free (labels->y_labels);
+	labels->y_labels = g_new0 (char const *, xyz->rows);
 
 	for (ptr = plot->series, i = 0 ; ptr != NULL ; ptr = ptr->next, i++) {
-		XLSurfaceSeries *series = ptr->data;
+		XlXYZSeries *series = ptr->data;
 
 		if (!gog_series_is_valid (GOG_SERIES (series)))
 			continue;
-		contour->y_labels[i] = go_data_scalar_get_str (GO_DATA_SCALAR (
+		labels->y_labels[i] = go_data_scalar_get_str (GO_DATA_SCALAR (
 				series->values[-1].data));
 	}
 
-	return GO_DATA_VECTOR (go_data_vector_str_new (contour->y_labels, i, NULL));
+	return GO_DATA_VECTOR (go_data_vector_str_new (labels->y_labels, i, NULL));
 }
 
 static GOData *
-xl_contour_plot_axis_get_bounds (GogPlot *plot, GogAxisType axis, 
+xl_xyz_plot_axis_get_bounds (GogPlot *plot, GogAxisType axis, 
 				GogPlotBoundInfo * bounds)
 {
-	XLContourPlot *contour = XL_CONTOUR_PLOT (plot);
+	GogXYZPlot *xyz = GOG_XYZ_PLOT (plot);
 	GODataVector *vec = NULL;
 	GOFormat *fmt;
 
 	if (axis == GOG_AXIS_X) {
-		XLSurfaceSeries *series = XL_SURFACE_SERIES (plot->series->data);
+		XlXYZSeries *series = XL_XYZ_SERIES (plot->series->data);
 		vec = GO_DATA_VECTOR (series->values[0].data);
-		fmt = contour->base.x.fmt;
+		fmt = xyz->x.fmt;
 	} else if (axis == GOG_AXIS_Y) {
-		if (!contour->base.rows)
+		if (!xyz->rows)
 			return NULL;
 		vec = get_y_vector (plot);
-		fmt = contour->base.y.fmt;
+		fmt = xyz->y.fmt;
 	} else {
-		if (bounds->fmt == NULL && contour->base.z.fmt != NULL)
-			bounds->fmt = go_format_ref (contour->base.z.fmt);
-		bounds->val.minima = contour->base.z.minima;
-		bounds->val.maxima = contour->base.z.maxima;
+		if (bounds->fmt == NULL && xyz->z.fmt != NULL)
+			bounds->fmt = go_format_ref (xyz->z.fmt);
+		bounds->val.minima = xyz->z.minima;
+		bounds->val.maxima = xyz->z.maxima;
 		return NULL;
 	}
 	if (bounds->fmt == NULL && fmt != NULL)
@@ -223,16 +224,87 @@
 	bounds->is_discrete    = TRUE;
 	bounds->center_on_ticks = TRUE;
 	bounds->val.maxima = (axis == GOG_AXIS_X)? 
-		contour->base.columns: 
-		contour->base.rows;
+		xyz->columns: 
+		xyz->rows;
 	return (GOData*) vec;
 }
+/*****************************************************************************/
+
+static GogObjectClass *xl_contour_parent_klass;
+
+typedef GogContourPlotClass XlContourPlotClass;
+
+static double *
+xl_contour_plot_build_matrix (GogXYZPlot const *plot,
+			gboolean *cardinality_changed)
+{
+	unsigned i, j, length;
+	GogAxisMap *map;
+	GogAxisTick *zticks;
+	GogAxis *axis = plot->base.axis[GOG_AXIS_PSEUDO_3D];
+	unsigned nticks;
+	double x[2], val;
+	GogSeries *series = NULL;
+	GODataVector *vec;
+	unsigned n = plot->rows * plot->columns;
+	double *data, minimum, maximum;
+	unsigned max;
+	GSList *ptr;
+
+	if (!gog_axis_get_bounds (axis, &minimum, &maximum))
+		return NULL;
+	data = g_new (double, n);
+	nticks = gog_axis_get_ticks (axis, &zticks);
+	map = gog_axis_map_new (axis, 0, 1);
+	for (i = j = 0; i < nticks; i++)
+		if (zticks[i].type == GOG_AXIS_TICK_MAJOR) {
+			x[j++] = gog_axis_map_to_view (map, zticks[i].position);
+			if (j > 1)
+				break;
+		}
+	x[1] -= x[0];
+
+	for (i = 0, ptr = plot->base.series ; ptr != NULL ; ptr = ptr->next) {
+		series = ptr->data;
+		if (!gog_series_is_valid (GOG_SERIES (series)))
+			continue;
+		vec = GO_DATA_VECTOR (series->values[1].data);
+		length = go_data_vector_get_len (vec);
+		for (j = 0; j < plot->columns; j++) {
+			/* The vector might be too short, excel is so ugly ;-) */
+			val = (j < length)? gog_axis_map_to_view (map,
+					go_data_vector_get_value (vec, j)): 0.;
+			/* This is an excel compatible plot, so let's be compatible */
+			if (val == go_nan || !go_finite (val))
+				val = 0.;
+			if (fabs (val) == DBL_MAX)
+				val = go_nan;
+			else {
+				val = val/ x[1] - x[0];
+				if (val < 0) {
+					val = go_nan;
+				}
+			}
+			data[i * plot->columns + j] = val;
+		}
+		i++;
+	}
+	g_return_val_if_fail (series != NULL, NULL);
+	max = (unsigned) ceil (1 / x[1]);
+	series = plot->base.series->data;
+	if (series->num_elements != max) {
+		series->num_elements = max;
+		*cardinality_changed = TRUE;
+	}
+	gog_axis_map_free (map);
+	return data;
+}
 
 static void
 xl_contour_plot_finalize (GObject *obj)
 {
-	XLContourPlot *plot = XL_CONTOUR_PLOT (obj);
-	g_free (plot->y_labels);
+	XlYLabels *labels = XL_Y_LABELS (obj);
+	g_free (labels->y_labels);
 	G_OBJECT_CLASS (xl_contour_parent_klass)->finalize (obj);
 }
 
@@ -248,7 +320,7 @@
 	gobject_klass->finalize     = xl_contour_plot_finalize;
 
 	/* Fill in GOGObject superclass values */
-	gog_object_klass->update	= xl_contour_plot_update;
+	gog_object_klass->update	= xl_xyz_plot_update;
 	gog_object_klass->populate_editor	= NULL;
 
 	{
@@ -263,69 +335,101 @@
 		gog_plot_klass->desc.series.style_fields = 0;
 	}
 	/* Fill in GogPlotClass methods */
-	gog_plot_klass->axis_get_bounds	= xl_contour_plot_axis_get_bounds;
-	gog_plot_klass->series_type = xl_surface_series_get_type();
+	gog_plot_klass->axis_get_bounds	= xl_xyz_plot_axis_get_bounds;
+	gog_plot_klass->series_type = xl_xyz_series_get_type();
 
 	klass->build_matrix = xl_contour_plot_build_matrix;
 }
 
-static void
-xl_contour_plot_init (XLContourPlot *contour)
-{
-	contour->y_labels = NULL;
-}
-
-GSF_DYNAMIC_CLASS (XLContourPlot, xl_contour_plot,
-	xl_contour_plot_class_init, xl_contour_plot_init,
-	GOG_CONTOUR_PLOT_TYPE)
+GSF_DYNAMIC_CLASS_FULL (XlContourPlot, xl_contour_plot,
+		NULL, NULL, xl_contour_plot_class_init, NULL,
+		NULL, GOG_CONTOUR_PLOT_TYPE, 0,
+		GSF_INTERFACE (xl_labels_init, XL_Y_LABELS_TYPE))
 
 /*****************************************************************************/
 
-static GogStyledObjectClass *series_parent_klass;
+static GogObjectClass *xl_surface_parent_klass;
 
-static void
-xl_surface_series_update (GogObject *obj)
-{
-	XLSurfaceSeries *series = XL_SURFACE_SERIES (obj);
-	int x_len = 0, z_len = 0;
-/*	unsigned old_num = series->num_elements;*/
-
-	if (series->values[1].data != NULL)
-		z_len = go_data_vector_get_len (
-			GO_DATA_VECTOR (series->values[1].data));
-	if (series->values[0].data != NULL)
-		x_len = go_data_vector_get_len (
-			GO_DATA_VECTOR (series->values[0].data));
-	else
-		x_len = z_len;
-	series->num_elements = MIN (x_len, z_len);
+typedef GogSurfacePlotClass XlSurfacePlotClass;
 
-	/* queue plot for redraw */
-	gog_object_request_update (GOG_OBJECT (series->plot));
-/*	if (old_num != series->base.num_elements)
-		gog_plot_request_cardinality_update (series->plot);*/
+static double *
+xl_surface_plot_build_matrix (GogXYZPlot const *plot,
+			gboolean *cardinality_changed)
+{
+	unsigned i, j, length;
+	double val;
+	GogSeries *series = NULL;
+	GODataVector *vec;
+	unsigned n = plot->rows * plot->columns;
+	double *data;
+	GSList *ptr;
 
-	if (series_parent_klass->base.update)
-		series_parent_klass->base.update (obj);
+	data = g_new (double, n);
+	for (i = 0, ptr = plot->base.series ; ptr != NULL ; ptr = ptr->next) {
+		series = ptr->data;
+		if (!gog_series_is_valid (GOG_SERIES (series)))
+			continue;
+		vec = GO_DATA_VECTOR (series->values[1].data);
+		length = go_data_vector_get_len (vec);
+		for (j = 0; j < plot->columns; j++) {
+			/* The vector might be too short, excel is so ugly ;-) */
+			val = (j < length)? go_data_vector_get_value (vec, j): 0.;
+			/* This is an excel compatible plot, so let's be compatible */
+			if (val == go_nan || !go_finite (val))
+				val = 0.;
+			if (fabs (val) == DBL_MAX)
+				val = go_nan;
+			data[i * plot->columns + j] = val;
+		}
+		i++;
+	}
+	*cardinality_changed = FALSE;
+	return data;
 }
 
 static void
-xl_surface_series_init_style (GogStyledObject *gso, GogStyle *style)
+xl_surface_plot_finalize (GObject *obj)
 {
-	series_parent_klass->init_style (gso, style);
+	XlYLabels *labels = XL_Y_LABELS (obj);
+	g_free (labels->y_labels);
+	G_OBJECT_CLASS (xl_surface_parent_klass)->finalize (obj);
 }
 
 static void
-xl_surface_series_class_init (GogStyledObjectClass *gso_klass)
+xl_surface_plot_class_init (GogSurfacePlotClass *klass)
 {
-	GogObjectClass * obj_klass = (GogObjectClass *) gso_klass;
+	GogPlotClass *gog_plot_klass = (GogPlotClass*) klass;
+	GogObjectClass *gog_object_klass = (GogObjectClass *) klass;
+	GObjectClass   *gobject_klass = (GObjectClass *) klass;
 
-	series_parent_klass = g_type_class_peek_parent (gso_klass);
-	gso_klass->init_style = xl_surface_series_init_style;
-	obj_klass->update = xl_surface_series_update;
+	xl_surface_parent_klass = g_type_class_peek_parent (klass);
+
+	gobject_klass->finalize     = xl_surface_plot_finalize;
+
+	/* Fill in GOGObject superclass values */
+	gog_object_klass->update	= xl_xyz_plot_update;
+	gog_object_klass->populate_editor	= NULL;
+
+	{
+		static GogSeriesDimDesc dimensions[] = {
+			{ N_("X"), GOG_SERIES_REQUIRED, FALSE,
+			  GOG_DIM_LABEL, GOG_MS_DIM_CATEGORIES },
+			{ N_("Z"), GOG_SERIES_REQUIRED, FALSE,
+			  GOG_DIM_VALUE, GOG_MS_DIM_VALUES },
+		};
+		gog_plot_klass->desc.series.dim = dimensions;
+		gog_plot_klass->desc.series.num_dim = G_N_ELEMENTS (dimensions);
+		gog_plot_klass->desc.series.style_fields = 0;
+	}
+	/* Fill in GogPlotClass methods */
+	gog_plot_klass->axis_get_bounds	= xl_xyz_plot_axis_get_bounds;
+	gog_plot_klass->series_type = xl_xyz_series_get_type();
+
+	klass->build_matrix = xl_surface_plot_build_matrix;
 }
 
+GSF_DYNAMIC_CLASS_FULL (XlSurfacePlot, xl_surface_plot,
+		NULL, NULL, xl_surface_plot_class_init, NULL,
+		NULL, GOG_SURFACE_PLOT_TYPE, 0,
+		GSF_INTERFACE (xl_labels_init, XL_Y_LABELS_TYPE))
 
-GSF_DYNAMIC_CLASS (XLSurfaceSeries, xl_surface_series,
-	xl_surface_series_class_init, NULL,
-	GOG_SERIES_TYPE)

Modified: trunk/plugins/plot_surface/xl-surface.h
==============================================================================
--- trunk/plugins/plot_surface/xl-surface.h	(original)
+++ trunk/plugins/plot_surface/xl-surface.h	Mon May 12 09:02:12 2008
@@ -1,6 +1,6 @@
 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * xl-contour.h
+ * xl-surface.h
  *
  * Copyright (C) 2005 Jean Brefort (jean brefort normalesup org)
  *
@@ -19,13 +19,17 @@
  * USA
  */
 
-#ifndef XL_CONTOUR_H
-#define XL_CONTOUR_H
+#ifndef XL_SURFACE_H
+#define XL_SURFACE_H
 
+#include "gog-contour.h"
 #include "gog-surface.h"
 
 G_BEGIN_DECLS
 
+void  xl_y_labels_register_type (GTypeModule *plugin);
+void  xl_xyz_series_register_type (GTypeModule *plugin);
+
 /*-----------------------------------------------------------------------------
  *
  * XLContourPlot
@@ -33,19 +37,31 @@
  *-----------------------------------------------------------------------------
  */
 
-typedef struct {
-	GogContourPlot base;
-	char const **y_labels;
-} XLContourPlot;
+typedef GogContourPlot XlContourPlot;
 
 #define XL_CONTOUR_PLOT_TYPE	(xl_contour_plot_get_type ())
-#define XL_CONTOUR_PLOT(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), XL_CONTOUR_PLOT_TYPE, XLContourPlot))
+#define XL_CONTOUR_PLOT(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), XL_CONTOUR_PLOT_TYPE, XlContourPlot))
 #define XL_PLOT_CONTOUR(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), XL_CONTOUR_PLOT_TYPE))
 
 GType xl_contour_plot_get_type (void);
 void  xl_contour_plot_register_type (GTypeModule *plugin);
-void  xl_surface_series_register_type (GTypeModule *plugin);
+
+/*-----------------------------------------------------------------------------
+ *
+ * XLSurfacePlot
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+typedef GogSurfacePlot XlSurfacePlot;
+
+#define XL_SURFACE_PLOT_TYPE	(xl_surface_plot_get_type ())
+#define XL_SURFACE_PLOT(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), XL_SURFACE_PLOT_TYPE, XlSurfacePlot))
+#define XL_PLOT_SURFACE(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), XL_SURFACE_PLOT_TYPE))
+
+GType xl_surface_plot_get_type (void);
+void  xl_surface_plot_register_type (GTypeModule *plugin);
 
 G_END_DECLS
 
-#endif /* XL_CONTOUR_H */
+#endif /* XL_SURFACE_H */



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