diff src/graphics.cc @ 7222:dd8b3bbeeaf9

[project @ 2007-11-30 06:23:25 by jwe]
author jwe
date Fri, 30 Nov 2007 06:23:26 +0000
parents 86d0b16f2bb2
children 3a695b7adf8e
line wrap: on
line diff
--- a/src/graphics.cc	Thu Nov 29 23:27:32 2007 +0000
+++ b/src/graphics.cc	Fri Nov 30 06:23:26 2007 +0000
@@ -25,6 +25,7 @@
 #endif
 
 #include <cctype>
+#include <cfloat>
 
 #include <algorithm>
 #include <list>
@@ -40,6 +41,7 @@
 #include "oct-map.h"
 #include "ov-fcn-handle.h"
 #include "parse.h"
+#include "unwind-prot.h"
 
 static void
 gripe_set_invalid (const std::string& pname)
@@ -1087,10 +1089,10 @@
     ylim (),
     zlim (),
     clim (),
-    xlimmode ("auto"),
-    ylimmode ("auto"),
-    zlimmode ("auto"),
-    climmode ("auto"),
+    xlimmode (radio_values ("{auto}|manual")),
+    ylimmode (radio_values ("{auto}|manual")),
+    zlimmode (radio_values ("{auto}|manual")),
+    climmode (radio_values ("{auto}|manual")),
     xlabel (octave_NaN),
     ylabel (octave_NaN),
     zlabel (octave_NaN),
@@ -1115,9 +1117,9 @@
     xcolor (),
     ycolor (),
     zcolor (),
-    xscale ("linear"),
-    yscale ("linear"),
-    zscale ("linear"),
+    xscale (radio_values ("{linear}|log")),
+    yscale (radio_values ("{linear}|log")),
+    zscale (radio_values ("{linear}|log")),
     xdir ("normal"),
     ydir ("normal"),
     zdir ("normal"),
@@ -1370,10 +1372,10 @@
   cl(1) = 1;
   clim = cl;
   
-  xlimmode = "auto";
-  ylimmode = "auto";
-  zlimmode = "auto";
-  climmode = "auto";
+  xlimmode = radio_property (radio_values ("{auto}|manual"));
+  ylimmode = radio_property (radio_values ("{auto}|manual"));
+  zlimmode = radio_property (radio_values ("{auto}|manual"));
+  climmode = radio_property (radio_values ("{auto}|manual"));
   xlabel = octave_NaN;
   ylabel = octave_NaN;
   zlabel = octave_NaN;
@@ -1398,9 +1400,9 @@
   xcolor = color_property ("black");
   ycolor = color_property ("black");
   zcolor = color_property ("black");
-  xscale = "linear";
-  yscale = "linear";
-  zscale = "linear";
+  xscale = radio_property (radio_values ("{linear}|log"));
+  yscale = radio_property (radio_values ("{linear}|log"));
+  zscale = radio_property (radio_values ("{linear}|log"));
   xdir = "normal";
   ydir = "normal";
   zdir = "normal";
@@ -1720,10 +1722,10 @@
   
   m["clim"] = cl;
 
-  m["xlimmode"] = "auto";
-  m["ylimmode"] = "auto";
-  m["zlimmode"] = "auto";
-  m["climmode"] = "auto";
+  m["xlimmode"] = radio_property (radio_values ("{auto}|manual"));
+  m["ylimmode"] = radio_property (radio_values ("{auto}|manual"));
+  m["zlimmode"] = radio_property (radio_values ("{auto}|manual"));
+  m["climmode"] = radio_property (radio_values ("{auto}|manual"));
   m["xlabel"] = octave_NaN;
   m["ylabel"] = octave_NaN;
   m["zlabel"] = octave_NaN;
@@ -1748,9 +1750,9 @@
   m["xcolor"] = color_property ("black");
   m["ycolor"] = color_property ("black");
   m["zcolor"] = color_property ("black");
-  m["xscale"] = "linear";
-  m["yscale"] = "linear";
-  m["zscale"] = "linear";
+  m["xscale"] = radio_property (radio_values ("{linear}|log"));
+  m["yscale"] = radio_property (radio_values ("{linear}|log"));
+  m["zscale"] = radio_property (radio_values ("{linear}|log"));
   m["xdir"] = "normal";
   m["ydir"] = "normal";
   m["zdir"] = "normal";
@@ -1791,9 +1793,281 @@
   return retval;
 }
 
+static void
+check_limit_val (double& min_val, double& max_val, double& min_pos, double val)
+{
+  if (! (xisinf (val) || xisnan (val)))
+    {
+      if (val < min_val)
+	min_val = val;
+
+      if (val > max_val)
+	max_val = val;
+
+      if (val > 0 && val < min_pos)
+	min_pos = val;
+    }
+}
+
+static void
+check_limit_vals (double& min_val, double& max_val, double& min_pos,
+		  const data_property& data)
+{
+  check_limit_val (min_val, max_val, min_pos, data.min_val ());
+  check_limit_val (max_val, max_val, min_pos, data.max_val ());
+  check_limit_val (min_pos, max_val, min_pos, data.min_pos ());
+}
+
+// Attempt to make "nice" limits from the actual max and min of the
+// data.  For log plots, we will also use the smallest strictly positive
+// value.
+
+static Matrix
+get_axis_limits (double xmin, double xmax, double min_pos, bool logscale)
+{
+  Matrix retval;
+
+  double min_val = xmin;
+  double max_val = xmax;
+
+  if (! (xisinf (min_val) || xisinf (max_val)))
+    {
+      if (logscale)
+	{
+	  if (xisinf (min_pos))
+	    {
+	      // warning ("axis: logscale with no positive values to plot");
+	      return retval;
+	    }
+
+	  if (min_val <= 0)
+	    {
+	      warning ("axis: omitting nonpositive data in log plot");
+	      min_val = min_pos;
+	    }
+	  // FIXME -- maybe this test should also be relative?
+	  if (std::abs (min_val - max_val) < sqrt (DBL_EPSILON))
+	    {
+	      min_val *= 0.9;
+	      max_val *= 1.1;
+	    }
+	  min_val = pow (10, floor (log10 (min_val)));
+	  max_val = pow (10, ceil (log10 (max_val)));
+	}
+      else
+	{
+	  if (min_val == 0 && max_val == 0)
+	    {
+	      min_val = -1;
+	      max_val = 1;
+	    }
+	  // FIXME -- maybe this test should also be relative?
+	  else if (std::abs (min_val - max_val) < sqrt (DBL_EPSILON))
+	    {
+	      min_val -= 0.1 * std::abs (min_val);
+	      max_val += 0.1 * std::abs (max_val);
+	    }
+	  // FIXME -- to do a better job, we should consider the tic spacing.
+	  double scale = pow (10, floor (log10 (max_val - min_val) - 1));
+	  min_val = scale * floor (min_val / scale);
+	  max_val = scale * ceil (max_val / scale);
+	}
+    }
+
+  retval.resize (1, 2);
+
+  retval(0) = min_val;
+  retval(1) = max_val;
+
+  return retval;
+}
+
+static bool updating_axis_limits = false;
+
 void
-axes::update_axis_limits (const std::string& /* axis_type */)
+axes::update_axis_limits (const std::string& axis_type)
 {
+  if (updating_axis_limits)
+    return;
+
+  Matrix kids = xproperties.get_children ();
+
+  octave_idx_type n = kids.numel ();
+
+  double min_val = octave_Inf;
+  double max_val = -octave_Inf;
+  double min_pos = octave_Inf;
+
+  radio_property tmp;
+
+  char update_type = 0;
+
+  Matrix limits;
+
+  if (axis_type == "xdata" || axis_type == "xscale"
+      || axis_type == "xldata" || axis_type == "xudata"
+      || axis_type == "xlimmode")
+    {
+      tmp = xproperties.get_xlimmode ();
+
+      if (tmp.current_value () == "auto")
+	{
+	  for (octave_idx_type i = 0; i < n; i++)
+	    {
+	      graphics_object obj = gh_manager::get_object (kids(i));
+
+	      if (obj.isa ("line") || obj.isa ("image")
+		  || obj.isa ("patch") || obj.isa ("surface"))
+		{
+		  data_property xdata = obj.get_xdata ();
+
+		  check_limit_vals (min_val, max_val, min_pos, xdata);
+
+		  if (obj.isa ("line"))
+		    {
+		      data_property xldata = obj.get_xldata ();
+		      data_property xudata = obj.get_xudata ();
+
+		      check_limit_vals (min_val, max_val, min_pos, xldata);
+		      check_limit_vals (min_val, max_val, min_pos, xudata);
+		    }
+		}
+	    }
+
+	  tmp = xproperties.get_xscale ();
+
+	  limits = get_axis_limits (min_val, max_val, min_pos,
+				    tmp.current_value () == "log");
+
+	  update_type = 'x';
+	}
+    }
+  else if (axis_type == "ydata" || axis_type == "yscale"
+	   || axis_type == "ldata" || axis_type == "udata"
+	   || axis_type == "ylimmode")
+    {
+      tmp = xproperties.get_ylimmode ();
+
+      if (tmp.current_value () == "auto")
+	{
+	    for (octave_idx_type i = 0; i < n; i++)
+	    {
+	      graphics_object obj = gh_manager::get_object (kids(i));
+
+	      if (obj.isa ("line") || obj.isa ("image")
+		|| obj.isa ("patch") || obj.isa ("surface"))
+		{
+		  data_property ydata = obj.get_ydata ();
+
+		  check_limit_vals (min_val, max_val, min_pos, ydata);
+
+		  if (obj.isa ("line"))
+		    {
+		      data_property ldata = obj.get_ldata ();
+		      data_property udata = obj.get_udata ();
+
+		      check_limit_vals (min_val, max_val, min_pos, ldata);
+		      check_limit_vals (min_val, max_val, min_pos, udata);
+		    }
+		}
+	    }
+
+	  tmp = xproperties.get_yscale ();
+
+	  limits = get_axis_limits (min_val, max_val, min_pos,
+				    tmp.current_value () == "log");
+
+	  update_type = 'y';
+	}
+    }
+  else if (axis_type == "zdata" || axis_type == "zscale"
+	   || axis_type == "zlimmode")
+    {
+      tmp = xproperties.get_zlimmode ();
+
+      if (tmp.current_value () == "auto")
+	{
+	  for (octave_idx_type i = 0; i < n; i++)
+	    {
+	      graphics_object obj = gh_manager::get_object (kids(i));
+
+	      if (obj.isa ("line") || obj.isa ("patch") || obj.isa ("surface"))
+		{
+		  data_property zdata = obj.get_zdata ();
+
+		  check_limit_vals (min_val, max_val, min_pos, zdata);
+		}
+	    }
+
+	  tmp = xproperties.get_zscale ();
+
+	  limits = get_axis_limits (min_val, max_val, min_pos,
+				    tmp.current_value () == "log");
+
+	  update_type = 'z';
+	}
+    }
+  else if (axis_type == "cdata" || axis_type == "climmode")
+    {
+      tmp = xproperties.get_climmode ();
+
+      if (tmp.current_value () == "auto")
+	{
+	  for (octave_idx_type i = 0; i < n; i++)
+	    {
+	      graphics_object obj = gh_manager::get_object (kids(i));
+
+	      if (obj.isa ("image") || obj.isa ("patch") || obj.isa ("surface"))
+		{
+		  data_property cdata = obj.get_cdata ();
+
+		  check_limit_vals (min_val, max_val, min_pos, cdata);
+		}
+	    }
+
+	  if (min_val == max_val)
+	    max_val = min_val + 1;
+
+	  limits.resize (1, 2);
+
+	  limits(0) = min_val;
+	  limits(1) = max_val;
+
+	  update_type = 'c';
+	}
+
+    }
+
+  unwind_protect_bool (updating_axis_limits);
+  updating_axis_limits = true;
+
+  switch (update_type)
+    {
+    case 'x':
+      xproperties.set_xlim (limits);
+      xproperties.set_xlimmode ("auto");
+      break;
+
+    case 'y':
+      xproperties.set_ylim (limits);
+      xproperties.set_ylimmode ("auto");
+      break;
+
+    case 'z':
+      xproperties.set_zlim (limits);
+      xproperties.set_zlimmode ("auto");
+      break;
+
+    case 'c':
+      xproperties.set_clim (limits);
+      xproperties.set_climmode ("auto");
+      break;
+
+    default:
+      break;
+    }
+
+  unwind_protect::run ();
 }
 
 std::string axes::properties::go_name ("axes");