goffice r2135 - in trunk: . goffice/graph goffice/gtk
- From: jbrefort svn gnome org
- To: svn-commits-list gnome org
- Subject: goffice r2135 - in trunk: . goffice/graph goffice/gtk
- Date: Mon, 7 Jul 2008 06:41:37 +0000 (UTC)
Author: jbrefort
Date: Mon Jul 7 06:41:37 2008
New Revision: 2135
URL: http://svn.gnome.org/viewvc/goffice?rev=2135&view=rev
Log:
2008-07-07 Mariusz Adamski <mariusz adamski gmail com>
* goffice/graph/Makefile.am: add new glade file.
* goffice/graph/gog-3d-box-prefs.glade: new glade file for setting
the 3d view.
* goffice/graph/gog-3d-box.c: ditto and make the settings persistant.
* goffice/gtk/Makefile.am: new 3d related widget
* goffice/gtk/go-3d-rotation-sel.c: ditto.
* goffice/gtk/go-3d-rotation-sel.glade: ditto.
* goffice/gtk/go-3d-rotation-sel.h: ditto.
Added:
trunk/goffice/graph/gog-3d-box-prefs.glade
trunk/goffice/gtk/go-3d-rotation-sel.c
trunk/goffice/gtk/go-3d-rotation-sel.glade
trunk/goffice/gtk/go-3d-rotation-sel.h
Modified:
trunk/ChangeLog
trunk/goffice/graph/Makefile.am
trunk/goffice/graph/gog-3d-box.c
trunk/goffice/gtk/Makefile.am
Modified: trunk/goffice/graph/Makefile.am
==============================================================================
--- trunk/goffice/graph/Makefile.am (original)
+++ trunk/goffice/graph/Makefile.am Mon Jul 7 06:41:37 2008
@@ -96,7 +96,8 @@
gog-error-bar-prefs.glade \
gog-reg-curve-prefs.glade \
gog-reg-eqn-prefs.glade \
- gog-series-prefs.glade
+ gog-series-prefs.glade \
+ gog-3d-box-prefs.glade
include $(top_srcdir)/goffice.mk
Added: trunk/goffice/graph/gog-3d-box-prefs.glade
==============================================================================
--- (empty file)
+++ trunk/goffice/graph/gog-3d-box-prefs.glade Mon Jul 7 06:41:37 2008
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
+<glade-interface>
+ <widget class="GtkWindow" id="window1">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">window2</property>
+ <child>
+ <widget class="GtkHBox" id="gog_3d_box_prefs">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="spacing">24</property>
+ <child>
+ <widget class="GtkVBox" id="vbox7">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <widget class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes"><b>Euler angles</b></property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <widget class="GtkHScale" id="phi_scale">
+ <property name="width_request">180</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="adjustment">0 0 370 1 10 10</property>
+ <property name="digits">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Phi:</property>
+ <property name="use_underline">True</property>
+ </widget>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Theta:</property>
+ <property name="use_underline">True</property>
+ </widget>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Psi:</property>
+ <property name="use_underline">True</property>
+ </widget>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHScale" id="psi_scale">
+ <property name="width_request">180</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="adjustment">0 0 370 1 10 10</property>
+ <property name="digits">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHScale" id="theta_scale">
+ <property name="width_request">180</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="adjustment">0 0 370 1 10 10</property>
+ <property name="digits">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
Modified: trunk/goffice/graph/gog-3d-box.c
==============================================================================
--- trunk/goffice/graph/gog-3d-box.c (original)
+++ trunk/goffice/graph/gog-3d-box.c Mon Jul 7 06:41:37 2008
@@ -23,12 +23,298 @@
#include <goffice/graph/gog-3d-box.h>
#include <goffice/math/go-math.h>
#include <gsf/gsf-impl-utils.h>
+#include <glib/gi18n-lib.h>
+#include <goffice/graph/gog-chart.h>
+
+#ifdef GOFFICE_WITH_GTK
+#include <goffice/gtk/goffice-gtk.h>
+#include <goffice/gtk/go-3d-rotation-sel.h>
+#endif
typedef GogObjectClass Gog3DBoxClass;
+enum {
+ BOX3D_PROP_0,
+ BOX3D_PROP_PSI,
+ BOX3D_PROP_THETA,
+ BOX3D_PROP_PHI,
+ BOX3D_PROP_FOV,
+};
+
+#ifdef GOFFICE_WITH_GTK
+
+static gboolean
+cb_g3d_update (GO3DRotationSel *g3d, GdkEventExpose *event, GObject *gobj)
+{
+ Gog3DBox *box = GOG_3D_BOX (gobj);
+ go_3d_rotation_sel_set_matrix (g3d, &box->mat);
+ return FALSE;
+}
+
+static void
+cb_matrix_changed (GO3DRotationSel *g3d, GObject *gobj)
+{
+ Gog3DBox *box = GOG_3D_BOX (gobj);
+
+ go_3d_rotation_sel_get_matrix (g3d, &box->mat);
+ box->psi = go_3d_rotation_sel_get_psi (g3d);
+ box->theta = go_3d_rotation_sel_get_theta (g3d);
+ box->phi = go_3d_rotation_sel_get_phi (g3d);
+
+ gog_object_emit_changed (gog_object_get_parent (GOG_OBJECT (gobj)),
+ TRUE);
+}
+
+static void
+cb_fov_changed (GO3DRotationSel *g3d, int angle, GObject *gobj)
+{
+ Gog3DBox *box = GOG_3D_BOX (gobj);
+
+ box->fov = angle * M_PI / 180;
+
+ gog_object_emit_changed (gog_object_get_parent (GOG_OBJECT (gobj)),
+ TRUE);
+}
+
+static gboolean
+cb_box_psi_changed (GtkHScale *scale_widget, GdkEventButton *event,
+ GObject *gobj)
+{
+ Gog3DBox *box = GOG_3D_BOX (gobj);
+
+ box->psi = gtk_range_get_value (GTK_RANGE (scale_widget)) * M_PI / 180;
+ go_matrix3x3_from_euler (&box->mat, box->psi, box->theta, box->phi);
+
+ gog_object_emit_changed (gog_object_get_parent (GOG_OBJECT (gobj)),
+ TRUE);
+ return FALSE;
+}
+
+static gboolean
+cb_box_theta_changed (GtkHScale *scale_widget, GdkEventButton *event,
+ GObject *gobj)
+{
+ Gog3DBox *box = GOG_3D_BOX (gobj);
+
+ box->theta = gtk_range_get_value (GTK_RANGE (scale_widget)) * M_PI / 180;
+ go_matrix3x3_from_euler (&box->mat, box->psi, box->theta, box->phi);
+
+ gog_object_emit_changed (gog_object_get_parent (GOG_OBJECT (gobj)),
+ TRUE);
+ return FALSE;
+}
+
+static gboolean
+cb_box_phi_changed (GtkHScale *scale_widget, GdkEventButton *event,
+ GObject *gobj)
+{
+ Gog3DBox *box = GOG_3D_BOX (gobj);
+
+ box->phi = gtk_range_get_value (GTK_RANGE (scale_widget)) * M_PI / 180;
+ go_matrix3x3_from_euler (&box->mat, box->psi, box->theta, box->phi);
+
+ gog_object_emit_changed (gog_object_get_parent (GOG_OBJECT (gobj)),
+ TRUE);
+ return FALSE;
+}
+
+static void
+cb_g3d_change_psi (GO3DRotationSel *g3d, int angle, GObject *gobj)
+{
+ g_signal_handlers_block_matched (GTK_RANGE (gobj), G_SIGNAL_MATCH_FUNC,
+ 0, 0, 0, G_CALLBACK (cb_box_psi_changed), 0);
+ gtk_range_set_value (GTK_RANGE (gobj), angle);
+ g_signal_handlers_unblock_matched (GTK_RANGE (gobj), G_SIGNAL_MATCH_FUNC,
+ 0, 0, 0, G_CALLBACK (cb_box_psi_changed), 0);
+}
+
+static void
+cb_g3d_change_theta (GO3DRotationSel *g3d, int angle, GObject *gobj)
+{
+ g_signal_handlers_block_matched (GTK_RANGE (gobj), G_SIGNAL_MATCH_FUNC,
+ 0, 0, 0, G_CALLBACK (cb_box_theta_changed), 0);
+ gtk_range_set_value (GTK_RANGE (gobj), angle);
+ g_signal_handlers_unblock_matched (GTK_RANGE (gobj), G_SIGNAL_MATCH_FUNC,
+ 0, 0, 0, G_CALLBACK (cb_box_theta_changed), 0);
+}
+
+static void
+cb_g3d_change_phi (GO3DRotationSel *g3d, int angle, GObject *gobj)
+{
+ g_signal_handlers_block_matched (GTK_RANGE (gobj), G_SIGNAL_MATCH_FUNC,
+ 0, 0, 0, G_CALLBACK (cb_box_phi_changed), 0);
+ gtk_range_set_value (GTK_RANGE (gobj), angle);
+ g_signal_handlers_unblock_matched (GTK_RANGE (gobj), G_SIGNAL_MATCH_FUNC,
+ 0, 0, 0, G_CALLBACK (cb_box_phi_changed), 0);
+}
+
+static void
+gog_3d_box_populate_editor (GogObject *gobj,
+ GogEditor *editor,
+ GogDataAllocator *dalloc,
+ GOCmdContext *cc)
+{
+ GtkWidget *w;
+ GtkWidget *g3d;
+ GladeXML *gui;
+ Gog3DBox *box = GOG_3D_BOX(gobj);
+
+ g3d = go_3d_rotation_sel_new ();
+ go_3d_rotation_sel_set_matrix (GO_3D_ROTATION_SEL (g3d), &box->mat);
+ go_3d_rotation_sel_set_fov (GO_3D_ROTATION_SEL (g3d), box->fov);
+ gog_editor_add_page (editor, g3d, _("Rotation"));
+
+ gui = go_libglade_new ("gog-3d-box-prefs.glade", "gog_3d_box_prefs", GETTEXT_PACKAGE, cc);
+ if (gui == NULL)
+ return;
+
+ g_signal_connect (G_OBJECT (g3d),
+ "expose-event",
+ G_CALLBACK (cb_g3d_update),
+ GOG_3D_BOX (gobj));
+ g_signal_connect (G_OBJECT (g3d),
+ "matrix-changed",
+ G_CALLBACK (cb_matrix_changed),
+ GOG_3D_BOX (gobj));
+ g_signal_connect (G_OBJECT (g3d),
+ "fov-changed",
+ G_CALLBACK (cb_fov_changed),
+ GOG_3D_BOX (gobj));
+
+ w = glade_xml_get_widget (gui, "psi_scale");
+ gtk_range_set_value (GTK_RANGE (w), box->psi * 180 / M_PI);
+ g_signal_connect (G_OBJECT (w),
+ "button-release-event",
+ G_CALLBACK (cb_box_psi_changed),
+ GOG_3D_BOX (gobj));
+ g_signal_connect (G_OBJECT (g3d),
+ "psi-changed",
+ G_CALLBACK (cb_g3d_change_psi),
+ GTK_RANGE (w));
+
+ w = glade_xml_get_widget (gui, "theta_scale");
+ gtk_range_set_value (GTK_RANGE (w), box->theta * 180 / M_PI);
+ g_signal_connect (G_OBJECT (w),
+ "button-release-event",
+ G_CALLBACK (cb_box_theta_changed),
+ GOG_3D_BOX (gobj));
+ g_signal_connect (G_OBJECT (g3d),
+ "theta-changed",
+ G_CALLBACK (cb_g3d_change_theta),
+ GTK_RANGE (w));
+
+ w = glade_xml_get_widget (gui, "phi_scale");
+ gtk_range_set_value (GTK_RANGE (w), box->phi * 180 / M_PI);
+ g_signal_connect (G_OBJECT (w),
+ "button-release-event",
+ G_CALLBACK (cb_box_phi_changed),
+ GOG_3D_BOX (gobj));
+ g_signal_connect (G_OBJECT (g3d),
+ "phi-changed",
+ G_CALLBACK (cb_g3d_change_phi),
+ GTK_RANGE (w));
+
+ w = glade_xml_get_widget (gui, "gog_3d_box_prefs");
+ g_object_set_data_full (G_OBJECT (w),
+ "state", gui, (GDestroyNotify)g_object_unref);
+
+ gog_editor_add_page (editor, w, _("Advanced"));
+}
+
+#endif
+
+static void
+gog_3d_box_set_property (GObject *obj, guint param_id,
+ GValue const *value, GParamSpec *pspec)
+{
+ Gog3DBox *box = GOG_3D_BOX (obj);
+
+ switch (param_id) {
+ case BOX3D_PROP_PSI:
+ box->psi = g_value_get_double (value);
+ break;
+ case BOX3D_PROP_THETA:
+ box->theta = g_value_get_double (value);
+ break;
+ case BOX3D_PROP_PHI:
+ box->phi = g_value_get_double (value);
+ break;
+ case BOX3D_PROP_FOV:
+ box->fov = g_value_get_double (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+ return;
+ }
+ go_matrix3x3_from_euler (&box->mat, box->psi, box->theta, box->phi);
+}
+
+static void
+gog_3d_box_get_property (GObject *obj, guint param_id,
+ GValue *value, GParamSpec *pspec)
+{
+ Gog3DBox *box = GOG_3D_BOX (obj);
+
+ switch (param_id) {
+ case BOX3D_PROP_PSI:
+ g_value_set_double (value, box->psi);
+ break;
+ case BOX3D_PROP_THETA:
+ g_value_set_double (value, box->theta);
+ break;
+ case BOX3D_PROP_PHI:
+ g_value_set_double (value, box->phi);
+ break;
+ case BOX3D_PROP_FOV:
+ g_value_set_double (value, box->fov);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+ break;
+ }
+}
+
static void
gog_3d_box_class_init (Gog3DBoxClass *klass)
{
+ GObjectClass *gobject_klass = (GObjectClass *) klass;
+ GogObjectClass *gog_klass = (GogObjectClass *) klass;
+
+ gobject_klass->set_property = gog_3d_box_set_property;
+ gobject_klass->get_property = gog_3d_box_get_property;
+
+ g_object_class_install_property (gobject_klass, BOX3D_PROP_PSI,
+ g_param_spec_double ("psi",
+ "Psi",
+ _("Euler angle psi"),
+ 0.0, 2 * M_PI, 70. / 180. * M_PI,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE
+ | GOG_PARAM_PERSISTENT));
+ g_object_class_install_property (gobject_klass, BOX3D_PROP_THETA,
+ g_param_spec_double ("theta",
+ "Theta",
+ _("Euler angle theta"),
+ 0.0, 2 * M_PI, 10. / 180. * M_PI,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE
+ | GOG_PARAM_PERSISTENT));
+ g_object_class_install_property (gobject_klass, BOX3D_PROP_PHI,
+ g_param_spec_double ("phi",
+ "Phi",
+ _("Euler angle phi"),
+ 0.0, 2 * M_PI, 270. / 180. * M_PI,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE
+ | GOG_PARAM_PERSISTENT));
+ g_object_class_install_property (gobject_klass, BOX3D_PROP_FOV,
+ g_param_spec_double ("fov",
+ "FoV",
+ _("Field of view"),
+ 0.0, M_PI, 10. / 180. * M_PI,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE
+ | GOG_PARAM_PERSISTENT));
+
+#ifdef GOFFICE_WITH_GTK
+ gog_klass->populate_editor = gog_3d_box_populate_editor;
+#endif
}
static void
@@ -37,7 +323,7 @@
box->fov = 10. / 180. * M_PI;
box->psi = 70. / 180. * M_PI;
box->theta = 10. / 180. * M_PI;
- box->phi = -90. / 180. * M_PI;
+ box->phi = 270. / 180. * M_PI;
go_matrix3x3_from_euler (&box->mat, box->psi, box->theta, box->phi);
}
Modified: trunk/goffice/gtk/Makefile.am
==============================================================================
--- trunk/goffice/gtk/Makefile.am (original)
+++ trunk/goffice/gtk/Makefile.am Mon Jul 7 06:41:37 2008
@@ -8,6 +8,7 @@
go-rotation-sel.c \
go-charmap-sel.c \
go-locale-sel.c \
+ go-3d-rotation-sel.c \
\
go-optionmenu.c \
go-combo-box.c \
@@ -44,6 +45,7 @@
go-rotation-sel.h \
go-charmap-sel.h \
go-locale-sel.h \
+ go-3d-rotation-sel.h \
\
go-optionmenu.h \
go-combo-box.h \
@@ -76,6 +78,7 @@
go-rotation-sel.glade \
go-font-sel.glade \
go-format-sel.glade \
+ go-3d-rotation-sel.glade \
go-image-save-dialog-extra.glade \
go-image-sel.glade
Added: trunk/goffice/gtk/go-3d-rotation-sel.c
==============================================================================
--- (empty file)
+++ trunk/goffice/gtk/go-3d-rotation-sel.c Mon Jul 7 06:41:37 2008
@@ -0,0 +1,499 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * go-3d-rotation-sel.c: A widget to select rotation angles of 3d plot
+ *
+ * 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 "go-3d-rotation-sel.h"
+
+#include <goffice/gtk/goffice-gtk.h>
+#include <goffice/math/go-math.h>
+#include <goffice/cut-n-paste/foocanvas/foo-canvas.h>
+#include <goffice/cut-n-paste/foocanvas/foo-canvas-util.h>
+#include <goffice/cut-n-paste/foocanvas/foo-canvas-line.h>
+#include <goffice/cut-n-paste/foocanvas/foo-canvas-widget.h>
+#include <goffice/cut-n-paste/foocanvas/foo-canvas-rect-ellipse.h>
+#include <goffice/cut-n-paste/foocanvas/foo-canvas-polygon.h>
+#include <gsf/gsf-impl-utils.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkrange.h>
+#include <gtk/gtkspinbutton.h>
+#include <gtk/gtklabel.h>
+#include <glib/gi18n-lib.h>
+#include <string.h>
+
+typedef struct {
+ double x, y, z;
+} g3d_point;
+
+struct _GO3DRotationSel {
+ GtkHBox box;
+ GladeXML *gui;
+ GtkRange *fovscale;
+ double psi;
+ double theta;
+ double phi;
+ double fov;
+ GOMatrix3x3 mat;
+
+ int radius;
+ int margin;
+ int bank_dial_x;
+ int bank_dial_y;
+ int bank_dial_r;
+ double old_x, old_y;
+ double bank;
+ g3d_point *cube_points;
+ int *cube_faces;
+ FooCanvas *rotate_canvas;
+ FooCanvasItem *dial;
+ FooCanvasItem *bank_dial;
+ FooCanvasItem *cube_polygons[6];
+ gulong motion_handle;
+};
+
+typedef struct {
+ GtkHBoxClass parent_class;
+ void (* psi_changed) (GO3DRotationSel *g3d, int angle);
+ void (* theta_changed) (GO3DRotationSel *g3d, int angle);
+ void (* phi_changed) (GO3DRotationSel *g3d, int angle);
+ void (* fov_changed) (GO3DRotationSel *g3d, int angle);
+} GO3DRotationSelClass;
+
+enum {
+ MATRIX_CHANGED,
+ PSI_CHANGED,
+ THETA_CHANGED,
+ PHI_CHANGED,
+ FOV_CHANGED,
+ LAST_SIGNAL
+};
+
+static guint g3d_signals[LAST_SIGNAL] = { 0, 0, 0, 0, 0 };
+static GObjectClass *g3d_parent_class;
+
+/* NOTE: This works only for angles [-2*pi,4*pi] */
+static double
+g3d_normalize (double angle)
+{
+ if (angle > 2 * M_PI)
+ return angle - 2 * M_PI;
+ if (angle < 0)
+ return angle + 2 * M_PI;
+ return angle;
+}
+
+static void
+cb_rotation_changed (GO3DRotationSel *g3d)
+{
+ double mgn = g3d->margin - 2;
+ double r = g3d->radius;
+ double d = 2 * r;
+ double dr = g3d->bank_dial_r;
+ double dx = g3d->bank_dial_x = mgn + r * (1 - sin (g3d->bank));
+ double dy = g3d->bank_dial_y = mgn + r * (1 - cos (g3d->bank));
+
+ /*double psi, theta, phi;*/
+ g3d_point cp[] = {
+ { 50, 50, 50},
+ { 50, -50, 50},
+ {-50, -50, 50},
+ {-50, 50, 50},
+ { 50, 50, -50},
+ { 50, -50, -50},
+ {-50, -50, -50},
+ {-50, 50, -50},
+ };
+ const int cf[] = {
+ 0, 1, 2, 3,
+ 4, 5, 6, 7,
+ 0, 1, 5, 4,
+ 1, 2, 6, 5,
+ 2, 3, 7, 6,
+ 3, 0, 4, 7
+ };
+ int i;
+
+ if (g3d->dial) {
+ foo_canvas_item_set (g3d->dial,
+ "x1", mgn, "y1", mgn,
+ "x2", mgn + d, "y2", mgn + d, NULL);
+ }
+
+ if (g3d->bank_dial) {
+ foo_canvas_item_set (g3d->bank_dial,
+ "x1", dx - dr, "y1", dy - dr,
+ "x2", dx + dr, "y2", dy + dr, NULL);
+ }
+
+ for (i = 0; i < 8; ++i) {
+ double x = cp[i].x;
+ double y = cp[i].y;
+ double z = cp[i].z;
+ go_matrix3x3_transform (&g3d->mat, x, y, z,
+ &cp[i].x, &cp[i].y, &cp[i].z);
+ }
+
+ for (i = 0; i < 6; ++i) {
+ FooCanvasPoints *points;
+ double cx = mgn + r;
+ double mean_y;
+ if (g3d->cube_polygons[i] == NULL)
+ continue;
+
+ points = foo_canvas_points_new (5);
+ points->coords[0] = cp[cf[4 * i + 0]].x + cx;
+ points->coords[1] = -cp[cf[4 * i + 0]].z + cx;
+ points->coords[2] = cp[cf[4 * i + 1]].x + cx;
+ points->coords[3] = -cp[cf[4 * i + 1]].z + cx;
+ points->coords[4] = cp[cf[4 * i + 2]].x + cx;
+ points->coords[5] = -cp[cf[4 * i + 2]].z + cx;
+ points->coords[6] = cp[cf[4 * i + 3]].x + cx;
+ points->coords[7] = -cp[cf[4 * i + 3]].z + cx;
+ points->coords[8] = cp[cf[4 * i + 0]].x + cx;
+ points->coords[9] = -cp[cf[4 * i + 0]].z + cx;
+
+ /* NOTE: This back face culling method works only with
+ * a cube in parallel projection*/
+ mean_y = cp[cf[4 * i + 0]].y;
+ mean_y += cp[cf[4 * i + 1]].y;
+ mean_y += cp[cf[4 * i + 2]].y;
+ mean_y += cp[cf[4 * i + 3]].y;
+ foo_canvas_item_set (g3d->cube_polygons[i], "points", points,
+ "width_units", (mean_y < 0) ? 4. : 0.5,
+ "fill-color", (i == 1)? "light blue" : "none",
+ NULL);
+ foo_canvas_points_free (points);
+ }
+ go_matrix3x3_to_euler (&g3d->mat, &g3d->psi, &g3d->theta, &g3d->phi);
+
+ g3d->psi = g3d_normalize (g3d->psi);
+ g3d->theta = g3d_normalize (g3d->theta);
+ g3d->phi = g3d_normalize (g3d->phi);
+
+ g_signal_emit (G_OBJECT (g3d),
+ g3d_signals[PSI_CHANGED], 0, (int) (g3d->psi * 180 / M_PI));
+ g_signal_emit (G_OBJECT (g3d),
+ g3d_signals[THETA_CHANGED], 0, (int) (g3d->theta * 180 / M_PI));
+ g_signal_emit (G_OBJECT (g3d),
+ g3d_signals[PHI_CHANGED], 0, (int) (g3d->phi * 180 / M_PI));
+}
+
+static gboolean
+cb_fov_changed (GtkRange *range, GdkEventButton *event, GO3DRotationSel *g3d)
+{
+ int angle = gtk_range_get_value (GTK_RANGE (range));
+ g3d->fov = angle * M_PI / 180;
+ g_signal_emit (G_OBJECT (g3d), g3d_signals[FOV_CHANGED], 0, angle);
+ return FALSE;
+}
+
+static void
+cb_rotate_canvas_realize (FooCanvas *canvas, GO3DRotationSel *g3d)
+{
+ FooCanvasGroup *group = FOO_CANVAS_GROUP (foo_canvas_root (canvas));
+ GtkStyle *style = gtk_style_copy (GTK_WIDGET (canvas)->style);
+ int i;
+ style->bg[GTK_STATE_NORMAL] = style->white;
+ gtk_widget_set_style (GTK_WIDGET (canvas), style);
+ g_object_unref (style);
+
+ foo_canvas_set_scroll_region (canvas, 0, 0, 220, 220);
+ foo_canvas_scroll_to (canvas, 0, 0);
+
+ for (i = 0; i < 6; ++i) {
+ g3d->cube_polygons[i] = foo_canvas_item_new (group,
+ FOO_TYPE_CANVAS_POLYGON, "outline-color", "black",
+ NULL);
+ }
+
+ g3d->dial = foo_canvas_item_new (group,
+ FOO_TYPE_CANVAS_ELLIPSE, "outline_color", "black",
+ "width_units", 2., NULL);
+
+ g3d->bank_dial = foo_canvas_item_new (group,
+ FOO_TYPE_CANVAS_ELLIPSE, "outline_color", "black",
+ "fill_color", "white", "width_units", 3., NULL);
+
+ cb_rotation_changed(g3d);
+}
+
+
+static gboolean
+cb_bank_dial_motion_notify_event (FooCanvas *canvas, GdkEventMotion *event,
+ GO3DRotationSel *g3d)
+{
+ GOMatrix3x3 m1, m2;
+ double x = event->x;
+ double y = event->y;
+ double theta, bank;
+
+ x -= g3d->margin + g3d->radius;
+ y -= g3d->margin + g3d->radius;
+
+ bank = g3d_normalize (-atan2 (x, -y));
+ theta = g3d->bank - bank;
+ g3d->bank = bank;
+ g3d->old_x = event->x;
+ g3d->old_y = event->y;
+ go_matrix3x3_from_euler (&m1, 0, theta, -M_PI * 0.5);
+ go_matrix3x3_from_euler (&m2, 0, 0, M_PI * 0.5);
+ go_matrix3x3_multiply (&m1, &m2, &m1);
+ go_matrix3x3_multiply (&g3d->mat, &m1, &g3d->mat);
+ cb_rotation_changed (g3d);
+ return TRUE;
+}
+
+static gboolean
+cb_rotate_motion_notify_event (FooCanvas *canvas, GdkEventMotion *event,
+ GO3DRotationSel *g3d)
+{
+ GOMatrix3x3 m1, m2, m3;
+ double theta, phi, dx, dy;
+
+ dx = event->x - g3d->old_x;
+ dy = event->y - g3d->old_y;
+ theta = atan2 (dy, dx);
+ phi = sqrt (dx * dx + dy * dy) * M_PI / 180;
+ g3d->old_x = event->x;
+ g3d->old_y = event->y;
+
+ go_matrix3x3_from_euler (&m1, 0, theta, phi);
+ go_matrix3x3_from_euler_transposed (&m2, 0, theta, 0);
+ go_matrix3x3_from_euler (&m3, 0, 0, M_PI * 0.5);
+ go_matrix3x3_multiply (&m1, &m3, &m1);
+ go_matrix3x3_multiply (&m1, &m1, &m2);
+ go_matrix3x3_from_euler (&m3, 0, 0, -M_PI * 0.5);
+ go_matrix3x3_multiply (&m1, &m1, &m3);
+ go_matrix3x3_multiply (&g3d->mat, &m1, &g3d->mat);
+ cb_rotation_changed (g3d);
+ return TRUE;
+}
+
+static gboolean
+cb_rotate_canvas_button (FooCanvas *canvas, GdkEventButton *event,
+ GO3DRotationSel *g3d)
+{
+ double x, y, r;
+ if (event->type == GDK_BUTTON_PRESS) {
+ if (g3d->motion_handle != 0)
+ return TRUE;
+ x = g3d->old_x = event->x;
+ y = g3d->old_y = event->y;
+ x -= g3d->bank_dial_x;
+ y -= g3d->bank_dial_y;
+ r = g3d->bank_dial_r;
+ gdk_pointer_grab (canvas->layout.bin_window, FALSE,
+ GDK_POINTER_MOTION_MASK
+ | GDK_BUTTON_RELEASE_MASK, NULL, NULL,
+ event->time);
+
+ if (x * x + y * y <= r * r) {
+ g3d->motion_handle = g_signal_connect (G_OBJECT (canvas),
+ "motion_notify_event",
+ G_CALLBACK (cb_bank_dial_motion_notify_event),
+ g3d);
+ } else {
+ g3d->motion_handle = g_signal_connect (G_OBJECT (canvas),
+ "motion_notify_event",
+ G_CALLBACK (cb_rotate_motion_notify_event), g3d);
+ }
+ } else if (event->type == GDK_BUTTON_RELEASE) {
+ if (g3d->motion_handle == 0)
+ return TRUE;
+ gdk_display_pointer_ungrab (gtk_widget_get_display (GTK_WIDGET (canvas)),
+ event->time);
+ g_signal_handler_disconnect (canvas, g3d->motion_handle);
+ g3d->motion_handle = 0;
+ g_signal_emit (G_OBJECT (g3d),
+ g3d_signals[MATRIX_CHANGED], 0, &g3d->mat);
+ }
+ return TRUE;
+}
+
+static void
+g3d_init (GO3DRotationSel *g3d)
+{
+ GtkWidget *w;
+
+ g3d->gui = go_libglade_new ("go-3d-rotation-sel.glade", "toplevel",
+ GETTEXT_PACKAGE, NULL);
+ if (g3d->gui == NULL)
+ return;
+
+ g3d->radius = 100;
+ g3d->margin = 10;
+ g3d->bank_dial_x = g3d->margin + g3d->radius;
+ g3d->bank_dial_y = g3d->margin;
+ g3d->bank_dial_r = 7;
+ g3d->dial = NULL;
+ g3d->bank_dial = NULL;
+ memset (g3d->cube_polygons, 0, sizeof (g3d->cube_polygons));
+ g3d->rotate_canvas = FOO_CANVAS (foo_canvas_new ());
+ gtk_container_add (GTK_CONTAINER (glade_xml_get_widget (g3d->gui,
+ "rotate_canvas")),
+ GTK_WIDGET (g3d->rotate_canvas));
+ gtk_widget_show (GTK_WIDGET (g3d->rotate_canvas));
+
+ g3d->motion_handle = 0;
+ g_object_connect (G_OBJECT (g3d->rotate_canvas),
+ "signal::realize",
+ G_CALLBACK (cb_rotate_canvas_realize), g3d,
+ "signal::button-press-event",
+ G_CALLBACK (cb_rotate_canvas_button), g3d,
+ "signal::button-release-event",
+ G_CALLBACK (cb_rotate_canvas_button), g3d,
+ NULL);
+
+ g3d->fovscale = GTK_RANGE (glade_xml_get_widget (g3d->gui, "fovscale"));
+ g_signal_connect (G_OBJECT (g3d->fovscale), "button-release-event",
+ G_CALLBACK (cb_fov_changed), g3d);
+ w = glade_xml_get_widget (g3d->gui, "toplevel");
+ gtk_box_pack_start (GTK_BOX (g3d), w, TRUE, TRUE, 0);
+ gtk_widget_show_all (GTK_WIDGET (g3d));
+}
+
+static void
+g3d_finalize (GObject *obj)
+{
+ GO3DRotationSel *g3d = GO_3D_ROTATION_SEL (obj);
+
+ if (g3d->gui) {
+ g_object_unref (G_OBJECT (g3d->gui));
+ g3d->gui = NULL;
+ }
+
+ g3d_parent_class->finalize (obj);
+}
+
+static void
+g3d_class_init (GObjectClass *klass)
+{
+ GObjectClass *gobj_class = (GObjectClass *) klass;
+ gobj_class->finalize = g3d_finalize;
+
+ g3d_parent_class = g_type_class_peek (gtk_hbox_get_type ());
+ g3d_signals [MATRIX_CHANGED] = g_signal_new ("matrix-changed",
+ G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GO3DRotationSelClass, psi_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ g3d_signals [PSI_CHANGED] = g_signal_new ("psi-changed",
+ G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GO3DRotationSelClass, psi_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE, 1, G_TYPE_INT);
+ g3d_signals [THETA_CHANGED] = g_signal_new ("theta-changed",
+ G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GO3DRotationSelClass, theta_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE, 1, G_TYPE_INT);
+ g3d_signals [PHI_CHANGED] = g_signal_new ("phi-changed",
+ G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GO3DRotationSelClass, phi_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE, 1, G_TYPE_INT);
+ g3d_signals [FOV_CHANGED] = g_signal_new ("fov-changed",
+ G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GO3DRotationSelClass, fov_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE, 1, G_TYPE_INT);
+}
+
+GSF_CLASS (GO3DRotationSel, go_3d_rotation_sel,
+ g3d_class_init, g3d_init, GTK_TYPE_HBOX)
+
+GtkWidget *
+go_3d_rotation_sel_new (void)
+{
+ return g_object_new (GO_3D_ROTATION_SEL_TYPE, NULL);
+}
+
+void
+go_3d_rotation_sel_get_matrix (GO3DRotationSel const *g3d, GOMatrix3x3 *mat)
+{
+ mat->a11 = g3d->mat.a11;
+ mat->a12 = g3d->mat.a12;
+ mat->a13 = g3d->mat.a13;
+ mat->a21 = g3d->mat.a21;
+ mat->a22 = g3d->mat.a22;
+ mat->a23 = g3d->mat.a23;
+ mat->a31 = g3d->mat.a31;
+ mat->a32 = g3d->mat.a32;
+ mat->a33 = g3d->mat.a33;
+}
+
+double
+go_3d_rotation_sel_get_psi (GO3DRotationSel const *g3d)
+{
+ g_return_val_if_fail (IS_GO_3D_ROTATION_SEL (g3d), 0);
+ return g3d->psi;
+}
+
+double
+go_3d_rotation_sel_get_theta (GO3DRotationSel const *g3d)
+{
+ g_return_val_if_fail (IS_GO_3D_ROTATION_SEL (g3d), 0);
+ return g3d->theta;
+}
+
+double
+go_3d_rotation_sel_get_phi (GO3DRotationSel const *g3d)
+{
+ g_return_val_if_fail (IS_GO_3D_ROTATION_SEL (g3d), 0);
+ return g3d->phi;
+}
+
+double
+go_3d_rotation_sel_get_fov (GO3DRotationSel const *g3d)
+{
+ g_return_val_if_fail (IS_GO_3D_ROTATION_SEL (g3d), 0);
+ return g3d->fov;
+}
+
+void
+go_3d_rotation_sel_set_matrix (GO3DRotationSel *g3d, GOMatrix3x3 *mat)
+{
+ g3d->mat.a11 = mat->a11;
+ g3d->mat.a12 = mat->a12;
+ g3d->mat.a13 = mat->a13;
+ g3d->mat.a21 = mat->a21;
+ g3d->mat.a22 = mat->a22;
+ g3d->mat.a23 = mat->a23;
+ g3d->mat.a31 = mat->a31;
+ g3d->mat.a32 = mat->a32;
+ g3d->mat.a33 = mat->a33;
+
+ cb_rotation_changed (g3d);
+}
+
+void
+go_3d_rotation_sel_set_fov (GO3DRotationSel *g3d, double fov)
+{
+ g3d->fov = fov;
+ g_signal_handlers_block_matched (GTK_RANGE (g3d->fovscale),
+ G_SIGNAL_MATCH_FUNC, 0, 0, 0, G_CALLBACK (cb_fov_changed), 0);
+ gtk_range_set_value (GTK_RANGE (g3d->fovscale),
+ (int) (fov * 180. / M_PI));
+ g_signal_handlers_unblock_matched (GTK_RANGE (g3d->fovscale),
+ G_SIGNAL_MATCH_FUNC, 0, 0, 0, G_CALLBACK (cb_fov_changed), 0);
+}
Added: trunk/goffice/gtk/go-3d-rotation-sel.glade
==============================================================================
--- (empty file)
+++ trunk/goffice/gtk/go-3d-rotation-sel.glade Mon Jul 7 06:41:37 2008
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
+<glade-interface>
+ <widget class="GtkWindow" id="window1">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">window2</property>
+ <child>
+ <widget class="GtkHBox" id="toplevel">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="spacing">24</property>
+ <child>
+ <widget class="GtkVBox" id="vbox7">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes"><b>Rotation</b></property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkScrolledWindow" id="rotate_canvas">
+ <property name="width_request">220</property>
+ <property name="height_request">220</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVScale" id="fovscale">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="adjustment">0 0 190 1 10 10</property>
+ <property name="digits">0</property>
+ <property name="draw_value">False</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
Added: trunk/goffice/gtk/go-3d-rotation-sel.h
==============================================================================
--- (empty file)
+++ trunk/goffice/gtk/go-3d-rotation-sel.h Mon Jul 7 06:41:37 2008
@@ -0,0 +1,48 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * go-3d-rotation-sel.h - Select a rotation angles
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License, version 2, as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA.
+ */
+#ifndef _GO_3D_ROTATION_SEL_H_
+#define _GO_3D_ROTATION_SEL_H_
+
+#include <gtk/gtkwindow.h>
+#include <goffice/utils/goffice-utils.h>
+#include <goffice/math/go-matrix3x3.h>
+
+G_BEGIN_DECLS
+
+#define GO_3D_ROTATION_SEL_TYPE (go_3d_rotation_sel_get_type ())
+#define GO_3D_ROTATION_SEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ GO_3D_ROTATION_SEL_TYPE, GO3DRotationSel))
+#define IS_GO_3D_ROTATION_SEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
+ GO_3D_ROTATION_SEL_TYPE))
+
+typedef struct _GO3DRotationSel GO3DRotationSel;
+
+GType go_3d_rotation_sel_get_type (void);
+GtkWidget *go_3d_rotation_sel_new (void);
+void go_3d_rotation_sel_set_matrix (GO3DRotationSel *rs, GOMatrix3x3 *mat);
+void go_3d_rotation_sel_set_fov (GO3DRotationSel *rs, double fov);
+void go_3d_rotation_sel_get_matrix (GO3DRotationSel const *rs, GOMatrix3x3 *mat);
+double go_3d_rotation_sel_get_psi (GO3DRotationSel const *rs);
+double go_3d_rotation_sel_get_theta (GO3DRotationSel const *rs);
+double go_3d_rotation_sel_get_phi (GO3DRotationSel const *rs);
+double go_3d_rotation_sel_get_fov (GO3DRotationSel const *rs);
+
+G_END_DECLS
+
+#endif /* _GO_3D_ROTATION_SEL_H_ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]