[genius] Wed Jun 12 14:22:13 2013 Jiri (George) Lebl <jirka 5z com>



commit 727e852ae81bfa065c06ef5efe2cef940d8fefae
Author: Jiri (George) Lebl <jirka 5z com>
Date:   Wed Jun 12 14:23:45 2013 -0500

    Wed Jun 12 14:22:13 2013  Jiri (George) Lebl <jirka 5z com>
    
        * src/graphing.c, gtkextra/gtkplotdata.c: Allow immediate fitting of
          the dependent axis on function and parametric plots just as for
          surface plots.  Fix fitting a parametric plot after zoom was
          changed.
    
        * help/C/genius/xml: update documentation

 ChangeLog              |    9 +
 NEWS                   |    2 +
 gtkextra/gtkplotdata.c |    8 +
 help/C/genius.xml      |   41 ++++-
 help/genius.txt        |   64 ++++++--
 src/graphing.c         |  411 +++++++++++++++++++++++++++++++++++++++++++----
 6 files changed, 478 insertions(+), 57 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 2bd2eb2..9b0f7d9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+Wed Jun 12 14:22:13 2013  Jiri (George) Lebl <jirka 5z com>
+
+       * src/graphing.c, gtkextra/gtkplotdata.c: Allow immediate fitting of
+         the dependent axis on function and parametric plots just as for
+         surface plots.  Fix fitting a parametric plot after zoom was
+         changed.
+
+       * help/C/genius/xml: update documentation
+
 Tue Jun 11 17:36:01 2013  Jiri (George) Lebl <jirka 5z com>
 
        * src/geniustests.txt: some new tests
diff --git a/NEWS b/NEWS
index ef0a4dd..8552f9b 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,8 @@ Changes to 1.0.17
 
 * Better precision for graphs especially when zoomed it a lot, and make font
   smaller if needed
+* Line plots and parametric plots now allow "fit dependent axis" automatically when
+  z limits are unspecified.  And this is the default in the UI
 * Completion for "help on function" in the GUI
 * Fix FindRootBisection and FindRootMullersMethod
 * Factors is now a lot faster on very large numbers (as fast as Factorize)
diff --git a/gtkextra/gtkplotdata.c b/gtkextra/gtkplotdata.c
index 9ed6fd7..40e5031 100644
--- a/gtkextra/gtkplotdata.c
+++ b/gtkextra/gtkplotdata.c
@@ -3554,6 +3554,14 @@ line_on_screen (double x1, double y1, double x2, double y2,
                int left, int right,
                int top, int bottom)
 {
+       /* FIXME: hack, we use this to give bad data */
+       if ( ! isfinite(x1) ||
+            ! isfinite(x2) ||
+            ! isfinite(y1) ||
+            ! isfinite(y2)) {
+               return FALSE;
+       }
+
        if ( (x1 >= left && y1 >= top &&
              x1 <= right && y1 <= bottom) ||
             (x2 >= left && y2 >= top &&
diff --git a/help/C/genius.xml b/help/C/genius.xml
index d18d2f0..6d4f7cc 100644
--- a/help/C/genius.xml
+++ b/help/C/genius.xml
@@ -4,7 +4,7 @@
   <!ENTITY app "<application>Genius Mathematics Tool</application>">
   <!ENTITY appname "Genius">
   <!ENTITY appversion "1.0.17">
-  <!ENTITY date "April 2013">
+  <!ENTITY date "June 2013">
 
   <!ENTITY legal SYSTEM "legal.xml">
 
@@ -475,14 +475,17 @@ See <xref linkend="lineplot-fig"/>.
       </figure>
 
       <para>
-       Into the text boxes just type in expressions where <userinput>x</userinput> is
-       the independent variable.  You can also just give names of functions such as
+       Type expressions with <userinput>x</userinput> as
+       the independent variable into the textboxes.  Alternatively you can give names of functions such as
        <userinput>cos</userinput> rather then having to type <userinput>cos(x)</userinput>.
        You can graph up to ten functions.  If you make a mistake and &appname; cannot
        parse the input it will signify this with a warning icon on the right of the text
        input box where the error occurred, as well as giving you an error dialog.
        You can change the ranges of the dependent and independent variables in the bottom
        part of the dialog.
+       The <varname>y</varname> (dependent) range can be set automatically by turning on the <guilabel>Fit 
dependent axis</guilabel>
+       checkbox.
+       The names of the variables can also be changed.
        Pressing the <guilabel>Plot</guilabel> button produces the graph shown in <xref 
linkend="lineplot2-fig"/>.
       </para>
 
@@ -519,7 +522,13 @@ See <xref linkend="lineplot-fig"/>.
        In the create plot window, you can also choose the <guilabel>Parametric</guilabel> notebook
         tab to create two dimensional parametric plots.  This way you can
        plot a single parametric function.  You can either specify the
-       points as x and y, or giving a single complex number.
+       points as <varname>x</varname> and <varname>y</varname>, or giving a single complex number
+       as a function of the variable <varname>t</varname>.
+       The range of the variable <varname>t</varname> is given explicitly, and the function is sampled
+       according to the given increment.
+       The <varname>x</varname> and <varname>y</varname> range can be set
+       automatically by turning on the <guilabel>Fit dependent axis</guilabel>
+       checkbox, or it can be specified explicitly.
        See <xref linkend="paramplot-fig"/>.
       </para>
 
@@ -648,6 +657,10 @@ See <xref linkend="lineplot-fig"/>.
        For plotting using the command line see the documentation of the
         <link linkend="gel-function-SurfacePlot"><function>SurfacePlot</function></link> function.
       </para>
+      <para>
+             The <varname>z</varname> range can be set automatically by turning on the <guilabel>Fit 
dependent axis</guilabel>
+             checkbox.
+      </para>
 
       <figure id="surfaceplot-fig"> 
         <title>Surface Plot</title> 
@@ -8190,15 +8203,20 @@ and has period <userinput>b-a</userinput>.</para>
          <term><anchor id="gel-function-LinePlot"/>LinePlot</term>
          <listitem>
           <synopsis>LinePlot (func1,func2,func3,...)</synopsis>
+          <synopsis>LinePlot (func1,func2,func3,x1,x2)</synopsis>
           <synopsis>LinePlot (func1,func2,func3,x1,x2,y1,y2)</synopsis>
+          <synopsis>LinePlot (func1,func2,func3,[x1,x2])</synopsis>
+          <synopsis>LinePlot (func1,func2,func3,[x1,x2,y1,y2])</synopsis>
           <para>
            Plot a function (or several functions) with a line.
-           First up to 10 arguments are functions, then optionally
+           First (up to 10) arguments are functions, then optionally
             you can specify the limits of the plotting window as
            <varname>x1</varname>, <varname>x2</varname>,
            <varname>y1</varname>, <varname>y2</varname>.  If limits are not
            specified, then the currently set limits apply
            (See <link linkend="gel-function-LinePlotWindow"><function>LinePlotWindow</function></link>)
+           If the y limits are not sepcified, then the functions are computed and then the maxima and minima
+           are used.
           </para>
           <para>
            The parameter
@@ -8274,15 +8292,19 @@ and has period <userinput>b-a</userinput>.</para>
           <synopsis>LinePlotParametric (xfunc,yfunc,...)</synopsis>
           <synopsis>LinePlotParametric (xfunc,yfunc,t1,t2,tinc)</synopsis>
           <synopsis>LinePlotParametric (xfunc,yfunc,t1,t2,tinc,x1,x2,y1,y2)</synopsis>
+          <synopsis>LinePlotParametric (xfunc,yfunc,t1,t2,tinc,[x1,x2,y1,y2])</synopsis>
+          <synopsis>LinePlotParametric (xfunc,yfunc,t1,t2,tinc,"fit")</synopsis>
           <para>
            Plot a parametric function with a line.  First come the functions
 for <varname>x</varname> and <varname>y</varname> then optionally the <varname>t</varname> limits as 
<userinput>t1,t2,tinc</userinput>, then optionally the
 limits as <userinput>x1,x2,y1,y2</userinput>.
           </para>
          <para>
-           If limits are not
+           If x and y limits are not
            specified, then the currently set limits apply
            (See <link linkend="gel-function-LinePlotWindow"><function>LinePlotWindow</function></link>).
+           If instead the string "fit" is given for the x and y limits, then the limits are the maximum 
extent of
+           the graph
           </para>
           <para>
            The parameter
@@ -8308,6 +8330,8 @@ optionally the limits as <userinput>x1,x2,y1,y2</userinput>.
            If limits are not
            specified, then the currently set limits apply
            (See <link linkend="gel-function-LinePlotWindow"><function>LinePlotWindow</function></link>).
+           If instead the string "fit" is given for the x and y limits, then the limits are the maximum 
extent of
+           the graph
           </para>
           <para>
            The parameter
@@ -8380,7 +8404,9 @@ optionally the limits as <userinput>x1,x2,y1,y2</userinput>.
          <listitem>
           <synopsis>SurfacePlot (func)</synopsis>
           <synopsis>SurfacePlot (func,x1,x2,y1,y2,z1,z2)</synopsis>
+          <synopsis>SurfacePlot (func,x1,x2,y1,y2)</synopsis>
           <synopsis>SurfacePlot (func,[x1,x2,y1,y2,z1,z2])</synopsis>
+          <synopsis>SurfacePlot (func,[x1,x2,y1,y2])</synopsis>
           <para>
            Plot a surface function which takes either two arguments or a complex number.  First comes the 
function then optionally limits as <varname>x1</varname>, <varname>x2</varname>,
            <varname>y1</varname>, <varname>y2</varname>,
@@ -8390,6 +8416,9 @@ optionally the limits as <userinput>x1,x2,y1,y2</userinput>.
            Genius can only plot a single surface function at this time.
           </para>
           <para>
+           If the z limits are not specified then the maxima and minima of the function are used.
+         </para>
+          <para>
            Examples:
           <screen><prompt>genius></prompt> <userinput>SurfacePlot(|sin|,-1,1,-1,1,0,1.5)</userinput>
 <prompt>genius></prompt> <userinput>SurfacePlot(`(x,y)=x^2+y,-1,1,-1,1,-2,2)</userinput>
diff --git a/help/genius.txt b/help/genius.txt
index 1fc562e..4ec940c 100644
--- a/help/genius.txt
+++ b/help/genius.txt
@@ -12,7 +12,7 @@ Kai Willadsen
 
     <kaiw itee uq edu au>
 
-   Copyright © 1997-2012 Jiří (George) Lebl
+   Copyright © 1997-2013 Jiří (George) Lebl
 
    Copyright © 2004 Kai Willadsen
 
@@ -75,7 +75,7 @@ Kai Willadsen
    To report a bug or make a suggestion regarding the Genius
    Mathematics Tool application or this manual, follow the
    directions in the GNOME Feedback Page.
-   This manual describes version 1.0.16 of Genius.
+   This manual describes version 1.0.17 of Genius.
      __________________________________________________________
 
    Table of Contents
@@ -415,16 +415,18 @@ Line Plots
 
    Figure 1. Create Plot Window
 
-   Into the text boxes just type in expressions where x is the
-   independent variable. You can also just give names of functions
-   such as cos rather then having to type cos(x). You can graph up
-   to ten functions. If you make a mistake and Genius cannot parse
+   Type expressions with x as the independent variable into the
+   textboxes. Alternatively you can give names of functions such
+   as cos rather then having to type cos(x). You can graph up to
+   ten functions. If you make a mistake and Genius cannot parse
    the input it will signify this with a warning icon on the right
    of the text input box where the error occurred, as well as
    giving you an error dialog. You can change the ranges of the
    dependent and independent variables in the bottom part of the
-   dialog. Pressing the Plot button produces the graph shown in
-   Figure 2.
+   dialog. The y (dependent) range can be set automatically by
+   turning on the Fit dependent axis checkbox. The names of the
+   variables can also be changed. Pressing the Plot button
+   produces the graph shown in Figure 2.
 
    [line_plot_graph.png]
 
@@ -445,7 +447,11 @@ Parametric Plots
    notebook tab to create two dimensional parametric plots. This
    way you can plot a single parametric function. You can either
    specify the points as x and y, or giving a single complex
-   number. See Figure 3.
+   number as a function of the variable t. The range of the
+   variable t is given explicitly, and the function is sampled
+   according to the given increment. The x and y range can be set
+   automatically by turning on the Fit dependent axis checkbox, or
+   it can be specified explicitly. See Figure 3.
 
    [parametric.png]
 
@@ -529,6 +535,9 @@ Surface Plots
    to |cos(x+1i*y)|. See Figure 5. For plotting using the command
    line see the documentation of the SurfacePlot function.
 
+   The z range can be set automatically by turning on the Fit
+   dependent axis checkbox.
+
    [surface_graph.png]
 
    Figure 5. Surface Plot
@@ -6221,13 +6230,21 @@ genius> ExportPlot("/directory/file","eps")
 
 LinePlot (func1,func2,func3,...)
 
+LinePlot (func1,func2,func3,x1,x2)
+
 LinePlot (func1,func2,func3,x1,x2,y1,y2)
 
+LinePlot (func1,func2,func3,[x1,x2])
+
+LinePlot (func1,func2,func3,[x1,x2,y1,y2])
+
           Plot a function (or several functions) with a line.
-          First up to 10 arguments are functions, then optionally
-          you can specify the limits of the plotting window as x1,
-          x2, y1, y2. If limits are not specified, then the
-          currently set limits apply (See LinePlotWindow)
+          First (up to 10) arguments are functions, then
+          optionally you can specify the limits of the plotting
+          window as x1, x2, y1, y2. If limits are not specified,
+          then the currently set limits apply (See LinePlotWindow)
+          If the y limits are not sepcified, then the functions
+          are computed and then the maxima and minima are used.
 
           The parameter LinePlotDrawLegends controls the drawing
           of the legend.
@@ -6281,12 +6298,18 @@ LinePlotParametric (xfunc,yfunc,t1,t2,tinc)
 
 LinePlotParametric (xfunc,yfunc,t1,t2,tinc,x1,x2,y1,y2)
 
+LinePlotParametric (xfunc,yfunc,t1,t2,tinc,[x1,x2,y1,y2])
+
+LinePlotParametric (xfunc,yfunc,t1,t2,tinc,"fit")
+
           Plot a parametric function with a line. First come the
           functions for x and y then optionally the t limits as
           t1,t2,tinc, then optionally the limits as x1,x2,y1,y2.
 
-          If limits are not specified, then the currently set
-          limits apply (See LinePlotWindow).
+          If x and y limits are not specified, then the currently
+          set limits apply (See LinePlotWindow). If instead the
+          string "fit" is given for the x and y limits, then the
+          limits are the maximum extent of the graph
 
           The parameter LinePlotDrawLegends controls the drawing
           of the legend.
@@ -6305,7 +6328,9 @@ LinePlotCParametric (func,t1,t2,tinc,x1,x2,y1,y2)
           the limits as x1,x2,y1,y2.
 
           If limits are not specified, then the currently set
-          limits apply (See LinePlotWindow).
+          limits apply (See LinePlotWindow). If instead the string
+          "fit" is given for the x and y limits, then the limits
+          are the maximum extent of the graph
 
           The parameter LinePlotDrawLegends controls the drawing
           of the legend.
@@ -6355,8 +6380,12 @@ SurfacePlot (func)
 
 SurfacePlot (func,x1,x2,y1,y2,z1,z2)
 
+SurfacePlot (func,x1,x2,y1,y2)
+
 SurfacePlot (func,[x1,x2,y1,y2,z1,z2])
 
+SurfacePlot (func,[x1,x2,y1,y2])
+
           Plot a surface function which takes either two arguments
           or a complex number. First comes the function then
           optionally limits as x1, x2, y1, y2, z1, z2. If limits
@@ -6364,6 +6393,9 @@ SurfacePlot (func,[x1,x2,y1,y2,z1,z2])
           (See SurfacePlotWindow). Genius can only plot a single
           surface function at this time.
 
+          If the z limits are not specified then the maxima and
+          minima of the function are used.
+
           Examples:
 
 genius> SurfacePlot(|sin|,-1,1,-1,1,0,1.5)
diff --git a/src/graphing.c b/src/graphing.c
index 845906a..2b1482a 100644
--- a/src/graphing.c
+++ b/src/graphing.c
@@ -180,7 +180,7 @@ static gboolean lineplot_draw_legends = TRUE;
 static gboolean lineplot_draw_legends_cb = TRUE;
 static gboolean lineplot_draw_labels = TRUE;
 static gboolean lineplot_draw_labels_cb = TRUE;
-/* static gboolean lineplot_fit_dependent_axis_cb = TRUE; */
+static gboolean lineplot_fit_dependent_axis_cb = TRUE;
 static gboolean vectorfield_normalize_arrow_length = FALSE;
 static gboolean vectorfield_normalize_arrow_length_cb = FALSE;
 static gboolean vectorfield_normalize_arrow_length_parameter = FALSE;
@@ -189,7 +189,9 @@ static gboolean surfaceplot_draw_legends_cb = TRUE;
 static gboolean surfaceplot_fit_dependent_axis_cb = TRUE;
 
 static GtkWidget* surfaceplot_dep_axis_buttons = NULL;
-/* static GtkWidget* lineplot_dep_axis_buttons = NULL; */
+static GtkWidget* lineplot_dep_axis_buttons = NULL;
+static GtkWidget* lineplot_depx_axis_buttons = NULL;
+static GtkWidget* lineplot_fit_dep_axis_checkbox = NULL;
 
 /* Replotting info */
 static GelEFunc *plot_func[MAXFUNC] = { NULL };
@@ -308,7 +310,9 @@ static void plot_axis (void);
 
 /* lineplots */
 static void plot_functions (gboolean do_window_present,
-                           gboolean from_gui);
+                           gboolean from_gui,
+                           gboolean fit);
+static void recompute_functions (void);
 
 /* surfaces */
 static void plot_surface_functions (gboolean do_window_present, gboolean fit_function);
@@ -2313,8 +2317,7 @@ plot_setup_axis (void)
 
        /* FIXME: implement logarithmic scale
        gtk_plot_set_xscale (GTK_PLOT (line_plot), GTK_PLOT_SCALE_LOG10);
-       gtk_plot_set_yscale (GTK_PLOT (line_plot), GTK_PLOT_SCALE_LOG10);
-       */
+       gtk_plot_set_yscale (GTK_PLOT (line_plot), GTK_PLOT_SCALE_LOG10);*/
 
        gtk_plot_thaw (GTK_PLOT (line_plot));
 }
@@ -2416,19 +2419,24 @@ plot_axis (void)
        plot_in_progress ++;
        plot_window_setup ();
 
-       plot_maxy = - G_MAXDOUBLE/2;
-       plot_miny = G_MAXDOUBLE/2;
-       plot_maxz = - G_MAXDOUBLE/2;
-       plot_minz = G_MAXDOUBLE/2;
-       plot_maxx = - G_MAXDOUBLE/2;
-       plot_minx = G_MAXDOUBLE/2;
-
-       if (plot_mode == MODE_LINEPLOT ||
-           plot_mode == MODE_LINEPLOT_PARAMETRIC ||
-           plot_mode == MODE_LINEPLOT_SLOPEFIELD ||
-           plot_mode == MODE_LINEPLOT_VECTORFIELD) {
+       if (plot_mode == MODE_LINEPLOT) {
+               plot_maxy = - G_MAXDOUBLE/2;
+               plot_miny = G_MAXDOUBLE/2;
+               plot_maxx = - G_MAXDOUBLE/2;
+               plot_minx = G_MAXDOUBLE/2;
+               recompute_functions ();
+               plot_setup_axis ();
+       } else if (plot_mode == MODE_LINEPLOT_PARAMETRIC ||
+                  plot_mode == MODE_LINEPLOT_SLOPEFIELD ||
+                  plot_mode == MODE_LINEPLOT_VECTORFIELD) {
                plot_setup_axis ();
        } else if (plot_mode == MODE_SURFACE) {
+               plot_maxx = - G_MAXDOUBLE/2;
+               plot_minx = G_MAXDOUBLE/2;
+               plot_maxy = - G_MAXDOUBLE/2;
+               plot_miny = G_MAXDOUBLE/2;
+               plot_maxz = - G_MAXDOUBLE/2;
+               plot_minz = G_MAXDOUBLE/2;
                surface_setup_axis ();
                surface_setup_steps ();
                gtk_plot_surface_build_mesh (GTK_PLOT_SURFACE (surface_data));
@@ -2721,6 +2729,7 @@ call_func_z (GelCtx *ctx,
        gel_freetree (ret);
 }
 
+#if 0
 static double
 plot_func_data (GtkPlot *plot, GtkPlotData *data, double x, gboolean *error)
 {
@@ -2784,6 +2793,7 @@ plot_func_data (GtkPlot *plot, GtkPlotData *data, double x, gboolean *error)
 
        return y;
 }
+#endif
 
 static double
 call_xy_or_z_function (GelEFunc *f, double x, double y, gboolean *ex)
@@ -3179,6 +3189,52 @@ get_limits_from_matrix (GelETree *m, double *x1, double *x2, double *y1, double
        return TRUE;
 }
 
+static gboolean
+get_limits_from_matrix_xonly (GelETree *m, double *x1, double *x2)
+{
+       GelETree *t;
+
+       if (m->type != GEL_MATRIX_NODE ||
+           gel_matrixw_elements (m->mat.matrix) != 2) {
+               gel_errorout (_("Graph limits not given as a 2-vector"));
+               return FALSE;
+       }
+
+       t = gel_matrixw_vindex (m->mat.matrix, 0);
+       if (t->type != GEL_VALUE_NODE) {
+               gel_errorout (_("Graph limits not given as numbers"));
+               return FALSE;
+       }
+       *x1 = mpw_get_double (t->val.value);
+       if G_UNLIKELY (gel_error_num != 0) {
+               gel_error_num = 0;
+               return FALSE;
+       }
+
+       t = gel_matrixw_vindex (m->mat.matrix, 1);
+       if (t->type != GEL_VALUE_NODE) {
+               gel_errorout (_("Graph limits not given as numbers"));
+               return FALSE;
+       }
+       *x2 = mpw_get_double (t->val.value);
+       if G_UNLIKELY (gel_error_num != 0) {
+               gel_error_num = 0;
+               return FALSE;
+       }
+
+       if (*x1 > *x2) {
+               double s = *x1;
+               *x1 = *x2;
+               *x2 = s;
+       }
+
+       /* sanity */
+       if (*x2 - *x1 < MINPLOT)
+               *x2 = *x1 + MINPLOT;
+
+       return TRUE;
+}
+
 static GelETree *
 make_matrix_from_limits (void)
 {
@@ -3964,8 +4020,101 @@ init_plot_ctx (void)
 }
 
 static void
+recompute_function (int funci, double **x, double **y, int *len)
+{
+       int i, iter, lentried;
+       double maxfuzz;
+       double fuzz[16];
+
+       lentried = 1000;/* FIXME: perhaps settable */
+
+       *x = g_new0 (double, lentried);
+       *y = g_new0 (double, lentried);
+
+       /* up to 1% of the interval is fuzzed */
+       maxfuzz = 0.01*(plotx2-plotx1)/lentried;
+       for (i = 0; i < 16; i++) {
+               fuzz[i] = g_random_double_range (-maxfuzz, maxfuzz);
+       }
+
+       iter = 0;
+       for (i = 0; i < lentried; i++) {
+               static int hookrun = 0;
+               gboolean ex = FALSE;
+               double rety;
+               double thex;
+
+               if G_UNLIKELY (gel_interrupted) {
+                       *len = iter;
+                       return;
+               }
+
+               thex = plotx1 + ((plotx2-plotx1)*(double)i)/lentried +
+                       fuzz[i&0xf];
+
+               mpw_set_d (plot_arg->val.value, thex);
+               rety = call_func (plot_ctx, plot_func[funci], plot_arg, &ex, NULL);
+
+               if G_UNLIKELY (ex) {
+                       (*x)[iter] = thex;
+#ifdef NAN
+                       (*y)[iter] = NAN;
+#else
+#ifdef INFINITY
+                       (*y)[iter] = INFINITY;
+#else
+                       (*y)[iter] = 1.0/0.0;
+#endif
+#endif
+                       iter++;
+               } else {
+                       (*x)[iter] = thex;
+                       (*y)[iter] = rety;
+                       iter++;
+
+                       if G_UNLIKELY (rety > plot_maxy)
+                               plot_maxy = rety;
+                       if G_UNLIKELY (rety < plot_miny)
+                               plot_miny = rety;
+               }
+
+               if G_UNLIKELY (hookrun++ >= 10) {
+                       if (gel_evalnode_hook != NULL) {
+                               hookrun = 0;
+                               (*gel_evalnode_hook)();
+                               if G_UNLIKELY (gel_interrupted) {
+                                       *len = iter;
+                                       return;
+                               }
+                       }
+               }
+       }
+       *len = iter;
+}
+
+
+
+static void
+recompute_functions (void)
+{
+       int i;
+       for (i = 0; i < MAXFUNC && plot_func[i] != NULL; i++) {
+               double *x, *y;
+               int len;
+               recompute_function (i,&x, &y, &len);
+
+               gtk_plot_data_set_points (line_data[i], x, y, NULL, NULL, len);
+               g_object_set_data_full (G_OBJECT (line_data[i]),
+                                       "x", x, (GDestroyNotify)g_free);
+               g_object_set_data_full (G_OBJECT (line_data[i]),
+                                       "y", y, (GDestroyNotify)g_free);
+       }
+}
+
+static void
 plot_functions (gboolean do_window_present,
-               gboolean from_gui)
+               gboolean from_gui,
+               gboolean fit)
 {
        char *colors[] = {
                "darkblue",
@@ -4000,6 +4149,7 @@ plot_functions (gboolean do_window_present,
 
        plot_in_progress ++;
        plot_window_setup ();
+       gtk_plot_freeze (GTK_PLOT (line_plot));
 
        /* sanity */
        if (plotx2 < plotx1) {
@@ -4023,8 +4173,6 @@ plot_functions (gboolean do_window_present,
        plot_maxy = - G_MAXDOUBLE/2;
        plot_miny = G_MAXDOUBLE/2;
 
-       plot_setup_axis ();
-
        init_plot_ctx ();
 
        if (gel_evalnode_hook != NULL)
@@ -4036,8 +4184,7 @@ plot_functions (gboolean do_window_present,
                GdkColor color;
                char *label;
 
-               line_data[i] = GTK_PLOT_DATA
-                       (gtk_plot_data_new_function (plot_func_data));
+               line_data[i] = GTK_PLOT_DATA (gtk_plot_data_new ());
                gtk_plot_add_data (GTK_PLOT (line_plot),
                                   line_data[i]);
 
@@ -4058,6 +4205,27 @@ plot_functions (gboolean do_window_present,
                g_free (label);
        }
 
+       recompute_functions ();
+
+       if (plot_func[0] != NULL && fit) {
+               double size = plot_maxy - plot_miny;
+               if (size <= 0)
+                       size = 1.0;
+               ploty1 = plot_miny - size * 0.05;
+               ploty2 = plot_maxy + size * 0.05;
+
+               /* sanity */
+               if (ploty2 <= ploty1)
+                       ploty2 = ploty1 + 0.1;
+
+               /* sanity */
+               if (ploty1 < -(G_MAXDOUBLE/2))
+                       ploty1 = -(G_MAXDOUBLE/2);
+               if (ploty2 > (G_MAXDOUBLE/2))
+                       ploty2 = (G_MAXDOUBLE/2);
+       }
+
+
        if ((parametric_func_x != NULL && parametric_func_y != NULL) ||
            (parametric_func_z != NULL)) {
                GdkColor color;
@@ -4123,8 +4291,39 @@ plot_functions (gboolean do_window_present,
                }
                gtk_plot_data_set_legend (parametric_data, label);
                g_free (label);
+
+               if (fit) {
+                       double sizex = plot_maxx - plot_minx;
+                       double sizey = plot_maxy - plot_miny;
+                       if (sizex <= 0)
+                               sizex = 1.0;
+                       if (sizey <= 0)
+                               sizey = 1.0;
+                       plotx1 = plot_minx - sizex * 0.05;
+                       plotx2 = plot_maxx + sizex * 0.05;
+                       ploty1 = plot_miny - sizey * 0.05;
+                       ploty2 = plot_maxy + sizey * 0.05;
+
+                       /* sanity */
+                       if (plotx2 <= plotx1)
+                               plotx2 = plotx1 + 0.1;
+                       if (ploty2 <= ploty1)
+                               ploty2 = ploty1 + 0.1;
+
+                       /* sanity */
+                       if (plotx1 < -(G_MAXDOUBLE/2))
+                               plotx1 = -(G_MAXDOUBLE/2);
+                       if (plotx2 > (G_MAXDOUBLE/2))
+                               plotx2 = (G_MAXDOUBLE/2);
+                       if (ploty1 < -(G_MAXDOUBLE/2))
+                               ploty1 = -(G_MAXDOUBLE/2);
+                       if (ploty2 > (G_MAXDOUBLE/2))
+                               ploty2 = (G_MAXDOUBLE/2);
+               }
        } 
 
+       plot_setup_axis ();
+
        replot_fields ();
 
        if (lineplot_draw_legends)
@@ -4144,6 +4343,7 @@ plot_functions (gboolean do_window_present,
                        (*gel_evalnode_hook)();
        }
 
+       gtk_plot_thaw (GTK_PLOT (line_plot));
        plot_in_progress --;
        plot_window_setup ();
 }
@@ -5003,6 +5203,61 @@ run_dialog_again:
        set_surface_labels ();
 }
 
+static void
+setup_page (int page)
+{
+       if (page == 0 /* functions */) {
+               gtk_widget_set_sensitive (lineplot_fit_dep_axis_checkbox, TRUE);
+
+               if (lineplot_fit_dependent_axis_cb) {
+                       gtk_widget_set_sensitive (lineplot_dep_axis_buttons, FALSE);
+               } else {
+                       gtk_widget_set_sensitive (lineplot_dep_axis_buttons, TRUE);
+               }
+               gtk_widget_set_sensitive (lineplot_depx_axis_buttons, TRUE);
+       } else if (page == 1 /* parametric */) {
+               gtk_widget_set_sensitive (lineplot_fit_dep_axis_checkbox, TRUE);
+
+               if (lineplot_fit_dependent_axis_cb) {
+                       gtk_widget_set_sensitive (lineplot_dep_axis_buttons, FALSE);
+                       gtk_widget_set_sensitive (lineplot_depx_axis_buttons, FALSE);
+               } else {
+                       gtk_widget_set_sensitive (lineplot_dep_axis_buttons, TRUE);
+                       gtk_widget_set_sensitive (lineplot_depx_axis_buttons, TRUE);
+               }
+       } else {
+               gtk_widget_set_sensitive (lineplot_fit_dep_axis_checkbox, FALSE);
+
+               gtk_widget_set_sensitive (lineplot_dep_axis_buttons, TRUE);
+               gtk_widget_set_sensitive (lineplot_depx_axis_buttons, TRUE);
+       }
+}
+
+static void
+lineplot_switch_page_cb (GtkNotebook *notebook, GtkWidget *page, guint page_num,
+                        gpointer data)
+{
+       setup_page (page_num);
+}
+
+
+/*option callback*/
+static void
+lineplot_fit_cb_cb (GtkWidget * widget)
+{
+       int function_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (function_notebook));
+
+       if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
+               lineplot_fit_dependent_axis_cb = TRUE;
+       } else {
+               lineplot_fit_dependent_axis_cb = FALSE;
+       }
+
+       setup_page (function_page);
+
+}
+
+
 static GtkWidget *
 create_lineplot_box (void)
 {
@@ -5266,6 +5521,7 @@ create_lineplot_box (void)
                                    NULL, NULL, NULL, 0, 0, 0,
                                    entry_activate);
        gtk_box_pack_start (GTK_BOX(box), b, FALSE, FALSE, 0);
+       lineplot_depx_axis_buttons = b;
 
        /*
         * Y range
@@ -5278,10 +5534,26 @@ create_lineplot_box (void)
                                    NULL, NULL, NULL, 0, 0, 0,
                                    entry_activate);
        gtk_box_pack_start (GTK_BOX(box), b, FALSE, FALSE, 0);
+       lineplot_dep_axis_buttons = b;
+
+       /* fit dependent axis? */
+       w = gtk_check_button_new_with_label (_("Fit dependent axis"));
+       lineplot_fit_dep_axis_checkbox = w;
+       gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 0);
+       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), 
+                                     lineplot_fit_dependent_axis_cb);
+       g_signal_connect (G_OBJECT (w), "toggled",
+                         G_CALLBACK (lineplot_fit_cb_cb), NULL);
+       lineplot_fit_cb_cb (w);
+
+
 
        /* set labels correclty */
        set_lineplot_labels ();
 
+       g_signal_connect (G_OBJECT (function_notebook), "switch_page",
+                         G_CALLBACK (lineplot_switch_page_cb), NULL);
+
        return mainbox;
 }
 
@@ -5881,7 +6153,13 @@ plot_from_dialog_lineplot (void)
        }
 
        plot_functions (TRUE /* do_window_present */,
-                       TRUE /* from_gui */);
+                       TRUE /* from_gui */,
+                       lineplot_fit_dependent_axis_cb /*fit*/);
+
+       if (lineplot_fit_dependent_axis_cb) {
+               reset_ploty1 = ploty1;
+               reset_ploty2 = ploty2;
+       }
 
        if (gel_interrupted)
                gel_interrupted = FALSE;
@@ -6013,7 +6291,15 @@ plot_from_dialog_parametric (void)
        }
 
        plot_functions (TRUE /* do_window_present */,
-                       TRUE /* from_gui */);
+                       TRUE /* from_gui */,
+                       lineplot_fit_dependent_axis_cb /*fit*/);
+
+       if (lineplot_fit_dependent_axis_cb) {
+               reset_plotx1 = plotx1;
+               reset_plotx2 = plotx2;
+               reset_ploty1 = ploty1;
+               reset_ploty2 = ploty2;
+       }
 
        if (gel_interrupted)
                gel_interrupted = FALSE;
@@ -6117,7 +6403,8 @@ plot_from_dialog_slopefield (void)
        slopefield_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (slopefield_entry)));
 
        plot_functions (TRUE /* do_window_present */,
-                       TRUE /* from_gui */);
+                       TRUE /* from_gui */,
+                       FALSE /*fit*/);
 
        if (gel_interrupted)
                gel_interrupted = FALSE;
@@ -6223,7 +6510,8 @@ plot_from_dialog_vectorfield (void)
        vectorfield_name_y = g_strdup (gtk_entry_get_text (GTK_ENTRY (vectorfield_entry_y)));
 
        plot_functions (TRUE /* do_window_present */,
-                       TRUE /* from_gui */);
+                       TRUE /* from_gui */,
+                       FALSE /*fit*/);
 
        if (gel_interrupted)
                gel_interrupted = FALSE;
@@ -6372,10 +6660,13 @@ SurfacePlot_op (GelCtx *ctx, GelETree * * a, int *exception)
                                if ( ! get_limits_from_matrix_surf (a[i], &x1, &x2, &y1, &y2, &z1, &z2))
                                        goto whack_copied_funcs;
                                fitz = FALSE;
-                       } else {
+                       } else if (gel_matrixw_elements (a[i]->mat.matrix) == 4) {
                                if ( ! get_limits_from_matrix (a[i], &x1, &x2, &y1, &y2))
                                        goto whack_copied_funcs;
                                fitz = TRUE;
+                       } else {
+                               gel_errorout (_("Graph limits not given as a 4-vector or a 6-vector"));
+                               goto whack_copied_funcs;
                        }
                        i++;
                } else {
@@ -6707,7 +6998,8 @@ SlopefieldPlot_op (GelCtx *ctx, GelETree * * a, int *exception)
 
        plot_mode = MODE_LINEPLOT_SLOPEFIELD;
        plot_functions (FALSE /* do_window_present */,
-                       FALSE /* from gui */);
+                       FALSE /* from gui */,
+                       FALSE /*fit*/);
 
        if (gel_interrupted)
                return NULL;
@@ -6827,7 +7119,8 @@ VectorfieldPlot_op (GelCtx *ctx, GelETree * * a, int *exception)
 
        plot_mode = MODE_LINEPLOT_VECTORFIELD;
        plot_functions (FALSE /* do_window_present */,
-                       FALSE /* from_gui */);
+                       FALSE /* from_gui */,
+                       FALSE /* fit */);
 
        if (gel_interrupted)
                return NULL;
@@ -6848,6 +7141,7 @@ LinePlot_op (GelCtx *ctx, GelETree * * a, int *exception)
 {
        double x1, x2, y1, y2;
        int funcs = 0;
+       gboolean fity = FALSE;
        GelEFunc *func[MAXFUNC] = { NULL };
        int i;
 
@@ -6883,8 +7177,18 @@ LinePlot_op (GelCtx *ctx, GelETree * * a, int *exception)
 
        if (a[i] != NULL) {
                if (a[i]->type == GEL_MATRIX_NODE) {
-                       if ( ! get_limits_from_matrix (a[i], &x1, &x2, &y1, &y2))
+                       if (gel_matrixw_elements (a[i]->mat.matrix) == 4) {
+                               if ( ! get_limits_from_matrix (a[i], &x1, &x2, &y1, &y2))
+                                       goto whack_copied_funcs;
+                               fity = FALSE;
+                       } else if (gel_matrixw_elements (a[i]->mat.matrix) == 2) {
+                               if ( ! get_limits_from_matrix_xonly (a[i], &x1, &x2))
+                                       goto whack_copied_funcs;
+                               fity = TRUE;
+                       } else {
+                               gel_errorout (_("Graph limits not given as a 2-vector or a 4-vector"));
                                goto whack_copied_funcs;
+                       }
                        i++;
                } else {
                        GET_DOUBLE(x1, i, "LinePlot");
@@ -6892,9 +7196,11 @@ LinePlot_op (GelCtx *ctx, GelETree * * a, int *exception)
                        if (a[i] != NULL) {
                                GET_DOUBLE(x2, i, "LinePlot");
                                i++;
+                               fity = TRUE;
                                if (a[i] != NULL) {
                                        GET_DOUBLE(y1, i, "LinePlot");
                                        i++;
+                                       fity = FALSE;
                                        if (a[i] != NULL) {
                                                GET_DOUBLE(y2, i, "LinePlot");
                                                i++;
@@ -6945,7 +7251,13 @@ LinePlot_op (GelCtx *ctx, GelETree * * a, int *exception)
 
        plot_mode = MODE_LINEPLOT;
        plot_functions (FALSE /* do_window_present */,
-                       FALSE /* from_gui */);
+                       FALSE /* from_gui */,
+                       fity /* fit */);
+
+       if (fity) {
+               reset_ploty1 = ploty1;
+               reset_ploty2 = ploty2;
+       }
 
        if G_UNLIKELY (gel_interrupted)
                return NULL;
@@ -6965,6 +7277,7 @@ static GelETree *
 LinePlotParametric_op (GelCtx *ctx, GelETree * * a, int *exception)
 {
        double x1, x2, y1, y2, t1, t2, tinc;
+       gboolean fit = FALSE;
        GelEFunc *funcx = NULL;
        GelEFunc *funcy = NULL;
        int i;
@@ -7019,7 +7332,12 @@ LinePlotParametric_op (GelCtx *ctx, GelETree * * a, int *exception)
 
        /* Get window limits */
        if (a[i] != NULL) {
-               if (a[i]->type == GEL_MATRIX_NODE) {
+               if ( (a[i]->type == GEL_STRING_NODE &&
+                     strcasecmp (a[i]->str.str, "fit") == 0) ||
+                    (a[i]->type == GEL_IDENTIFIER_NODE &&
+                     strcasecmp (a[i]->id.id->token, "fit") == 0)) {
+                       fit = TRUE;
+               } else if (a[i]->type == GEL_MATRIX_NODE) {
                        if ( ! get_limits_from_matrix (a[i], &x1, &x2, &y1, &y2))
                                goto whack_copied_funcs;
                        i++;
@@ -7089,7 +7407,15 @@ LinePlotParametric_op (GelCtx *ctx, GelETree * * a, int *exception)
 
        plot_mode = MODE_LINEPLOT_PARAMETRIC;
        plot_functions (FALSE /* do_window_present */,
-                       FALSE /* from_gui */ );
+                       FALSE /* from_gui */,
+                       fit /* fit */);
+
+       if (fit) {
+               reset_plotx1 = plotx1;
+               reset_plotx2 = plotx2;
+               reset_ploty1 = ploty1;
+               reset_ploty2 = ploty2;
+       }
 
        if G_UNLIKELY (gel_interrupted)
                return NULL;
@@ -7109,6 +7435,7 @@ static GelETree *
 LinePlotCParametric_op (GelCtx *ctx, GelETree * * a, int *exception)
 {
        double x1, x2, y1, y2, t1, t2, tinc;
+       gboolean fit = FALSE;
        GelEFunc *func = NULL;
        int i;
 
@@ -7160,7 +7487,12 @@ LinePlotCParametric_op (GelCtx *ctx, GelETree * * a, int *exception)
 
        /* Get window limits */
        if (a[i] != NULL) {
-               if (a[i]->type == GEL_MATRIX_NODE) {
+               if ( (a[i]->type == GEL_STRING_NODE &&
+                     strcasecmp (a[i]->str.str, "fit") == 0) ||
+                    (a[i]->type == GEL_IDENTIFIER_NODE &&
+                     strcasecmp (a[i]->id.id->token, "fit") == 0)) {
+                       fit = TRUE;
+               } else if (a[i]->type == GEL_MATRIX_NODE) {
                        if ( ! get_limits_from_matrix (a[i], &x1, &x2, &y1, &y2))
                                goto whack_copied_funcs;
                        i++;
@@ -7229,7 +7561,15 @@ LinePlotCParametric_op (GelCtx *ctx, GelETree * * a, int *exception)
 
        plot_mode = MODE_LINEPLOT_PARAMETRIC;
        plot_functions (FALSE /* do_window_present */,
-                       FALSE /* from_gui */);
+                       FALSE /* from_gui */,
+                       fit /* fit */);
+
+       if (fit) {
+               reset_plotx1 = plotx1;
+               reset_plotx2 = plotx2;
+               reset_ploty1 = ploty1;
+               reset_ploty2 = ploty2;
+       }
 
        if G_UNLIKELY (gel_interrupted)
                return NULL;
@@ -7257,7 +7597,8 @@ LinePlotClear_op (GelCtx *ctx, GelETree * * a, int *exception)
        /* This will just clear the window */
        plot_mode = MODE_LINEPLOT;
        plot_functions (FALSE /* do_window_present */,
-                       FALSE /* from_gui */);
+                       FALSE /* from_gui */,
+                       FALSE /* fit */);
 
        if G_UNLIKELY (gel_interrupted)
                return NULL;


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