changeset 11162:a981e2f56ec1

Don't plot patch outlines with the gnuplot backend if the marker property is set to none. Fixes contourf(peaks(),'edgecolor','none')
author David Bateman <dbateman@free.fr>
date Fri, 29 Oct 2010 00:25:04 +0200
parents 2e32236eaa90
children 31e7e9f94850
files scripts/ChangeLog scripts/plot/__go_draw_axes__.m scripts/plot/private/__contour__.m src/gl-render.cc src/graphics.cc src/graphics.h.in
diffstat 6 files changed, 747 insertions(+), 207 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/ChangeLog	Thu Oct 28 13:22:49 2010 +0800
+++ b/scripts/ChangeLog	Fri Oct 29 00:25:04 2010 +0200
@@ -1,3 +1,8 @@
+2010-10-27  David Bateman  <dbateman@free.fr>
+
+	* plot/__go_draw_axes__.m: Don't attempt to plot patch outlines if
+	the marker property is set to none.
+
 2010-10-28  Ben Abbott <bpabbott@mac.com>
 
 	* plot/daspect.m, plot/pbaspect.m: Add demos setting both data and
--- a/scripts/plot/__go_draw_axes__.m	Thu Oct 28 13:22:49 2010 +0800
+++ b/scripts/plot/__go_draw_axes__.m	Fri Oct 29 00:25:04 2010 +0200
@@ -719,8 +719,9 @@
 
            ## patch outline
            if (!(strncmp (obj.edgecolor, "none", 4)
-                  && strncmp (obj.markeredgecolor, "none", 4)
-                  && strncmp (obj.markerfacecolor, "none", 4)))
+                  && (strncmp (obj.marker, "none", 4) 
+                      || (strncmp (obj.markeredgecolor, "none", 4)
+                          && strncmp (obj.markerfacecolor, "none", 4)))))
 
              data_idx++;
              is_image_data(data_idx) = false;
--- a/scripts/plot/private/__contour__.m	Thu Oct 28 13:22:49 2010 +0800
+++ b/scripts/plot/private/__contour__.m	Fri Oct 29 00:25:04 2010 +0200
@@ -143,10 +143,10 @@
   ## allow the use of contourgroups with the contour3, meshc and surfc 
   ## functions. 
   if (isnumeric (zlevel))
-    addproperty ("zlevelmode", hg, "radio", "{none}|auto|manual", "manual")
+    addproperty ("zlevelmode", hg, "radio", "{none}|auto|manual", "manual");
     addproperty ("zlevel", hg, "data", zlevel);
   else
-    addproperty ("zlevelmode", hg, "radio", "{none}|auto|manual", zlevel)
+    addproperty ("zlevelmode", hg, "radio", "{none}|auto|manual", zlevel);
     if (ischar (zlevel) && strcmpi (zlevel, "manual"))
       z = varargin{3};
       z = 2 * (min (z(:)) - max (z(:)));
@@ -211,6 +211,8 @@
 
   add_patch_children (hg);
 
+  axis("tight");
+
   if (!isempty (opts))
     set (hg, opts{:});
   endif
@@ -220,12 +222,13 @@
   c = get (hg, "contourmatrix");
   lev = get (hg, "levellist");
   fill = get (hg, "fill");
-  z = get (hg, "zlevel");
+  zlev = get (hg, "zlevel");
   zmode = get (hg, "zlevelmode");
   lc = get (hg, "linecolor");
   lw = get (hg, "linewidth");
   ls = get (hg, "linestyle");
   filled = get (hg, "fill");
+  ca = gca ();
 
   if (strcmpi (lc, "auto"))
     lc = "flat";
@@ -243,11 +246,7 @@
       cont_lev(ncont) = c(1, i1);
       cont_len(ncont) = c(2, i1);
       cont_idx(ncont) = i1+1;
-
       ii = i1+1:i1+cont_len(ncont);
-      cur_cont = c(:, ii);
-      startidx = ii(1);
-      stopidx = ii(end);
       cont_area(ncont) = polyarea (c(1, ii), c(2, ii));
       i1 += c(2, i1) + 1;
     endwhile
@@ -320,17 +319,19 @@
       else
         ## Special case unclosed contours
       endif
-      h = [h; patch(ctmp(1, :), ctmp(2, :), cont_lev(idx), "edgecolor", lc, 
-                    "linestyle", ls, "linewidth", lw, "parent", hg)];
+      h = [h; __go_patch__(ca, "xdata", ctmp(1, :)(:), "ydata", ctmp(2, :)(:), 
+                           "vertices", ctmp.', "faces", 1:(cont_len(idx)-1),
+                           "facevertexcdata", cont_lev(idx),
+                           "facecolor", "flat", "cdata", cont_lev(idx),
+                           "edgecolor", lc, "linestyle", ls, 
+                           "linewidth", lw, "parent", hg)];
     endfor
 
     if (min (lev) == max (lev))
-      set (gca (), "clim", [min(lev)-1, max(lev)+1]);
+      set (ca, "clim", [min(lev)-1, max(lev)+1], "layer", "top");
     else
-      set (gca(), "clim", [min(lev), max(lev)]);
+      set (ca, "clim", [min(lev), max(lev)], "layer", "top");
     endif
-
-    set (gca (), "layer", "top");
   else
     ## Decode contourc output format.
     i1 = 1;
@@ -340,28 +341,40 @@
       clen = c(2,i1);
 
       if (all (c(:,i1+1) == c(:,i1+clen)))
-        p = c(:, i1+1:i1+clen-1);
+        p = c(:, i1+1:i1+clen-1).';
       else
-        p = [c(:, i1+1:i1+clen), NaN(2, 1)];
+        p = [c(:, i1+1:i1+clen), NaN(2, 1)].';
       endif
 
       switch (zmode)
         case "none"
-          h = [h; patch(p(1,:), p(2,:), "facecolor", "none", 
-                        "edgecolor", lc, "linestyle", ls, "linewidth", lw,
-                        "cdata", clev, "parent", hg)]; 
+          h = [h; __go_patch__(ca, "xdata", p(:,1), "ydata", p(:,2),
+                               "zdata", [], "facecolor", "none", 
+                               "vertices", p, "faces", 1:rows(p),
+                               "facevertexcdata", clev,
+                               "edgecolor", lc, "linestyle", ls,
+                               "linewidth", lw,
+                               "cdata", clev, "parent", hg)]; 
         case "auto"
-          h = [h; patch(p(1,:), p(2,:), clev * ones (1, columns (p)),
-                        "facecolor", "none", "edgecolor", lc, 
-                        "linestyle", ls, "linewidth", lw, "cdata", clev, 
-                        "parent", hg)];
+          h = [h; __go_patch__(ca, "xdata", p(:,1), "ydata", p(:,2),
+                               "zdata", clev * ones(rows(p),1),
+                               "vertices", [p, clev * ones(rows(p),1)], 
+                               "faces", 1:rows(p),
+                               "facevertexcdata", clev,
+                               "facecolor", "none", "edgecolor", lc, 
+                               "linestyle", ls, "linewidth", lw,
+                               "cdata", clev, "parent", hg)];
         otherwise
-          h = [h; patch(p(1,:), p(2,:), z * ones (1, columns (p)),
-                        "facecolor", "none", "edgecolor", lc,
-                        "linestyle", ls, "linewidth", lw, "cdata", clev,
-                        "parent", hg)];
+          h = [h; __go_patch__(ca, "xdata", p(:,1), "ydata", p(:,2),
+                               "zdata", zlev * ones (rows(p), 1),
+                               "vertices", [p, zlev * ones(rows(p),1)], 
+                               "faces", 1:rows(p),
+                               "facevertexcdata", clev,
+                               "facecolor", "none", "edgecolor", lc,
+                               "linestyle", ls, "linewidth", lw,
+                               "cdata", clev, "parent", hg)];
       endswitch
-      i1 += clen+1;
+      i1 += clen + 1;
     endwhile
   endif
 
--- a/src/gl-render.cc	Thu Oct 28 13:22:49 2010 +0800
+++ b/src/gl-render.cc	Fri Oct 29 00:25:04 2010 +0200
@@ -2578,6 +2578,7 @@
           set_linestyle (props.get_linestyle (), false);
           set_linewidth (props.get_linewidth ());
 
+
           // FIXME: use __index__ property from patch object; should we
           // offset patch contour as well?
           patch_tesselator tess (this, ec_mode, el_mode);
@@ -2585,20 +2586,47 @@
           for (int i = 0; i < nf; i++)
             {
               if (clip_f(i))
-                continue;
-
-              tess.begin_polygon (false);
-              tess.begin_contour ();
-
-              for (int j = 0; j < count_f(i); j++)
                 {
-                  vertex_data::vertex_data_rep *vv = vdata[i+j*fr].get_rep ();
-        
-                  tess.add_vertex (vv->coords.fortran_vec (), vv);
+                  // This is an unclosed contour. Draw it as a line
+                  bool flag = false;
+
+                  for (int j = 0; j < count_f(i); j++)
+                    {
+                      if (! clip(int (f(i,j) - 1)))
+                        {
+                          vertex_data::vertex_data_rep *vv = vdata[i+j*fr].get_rep ();
+                          const Matrix m = vv->coords;
+                          if (! flag)
+                            {
+                              flag = true;
+                              glBegin (GL_LINE_STRIP);
+                            }
+                          glVertex3d (m(0), m(1), m(2));
+                        }
+                      else if (flag)
+                        {
+                          flag = false;
+                          glEnd ();
+                        }
+                    }
+
+                  if (flag)
+                    glEnd ();
                 }
-
-              tess.end_contour ();
-              tess.end_polygon ();
+              else
+                {
+                  tess.begin_polygon (false);
+                  tess.begin_contour ();
+
+                  for (int j = 0; j < count_f(i); j++)
+                    {
+                      vertex_data::vertex_data_rep *vv = vdata[i+j*fr].get_rep ();
+                      tess.add_vertex (vv->coords.fortran_vec (), vv);
+                    }
+
+                  tess.end_contour ();
+                  tess.end_polygon ();
+                }
             }
 
           set_linestyle ("-");
--- a/src/graphics.cc	Thu Oct 28 13:22:49 2010 +0800
+++ b/src/graphics.cc	Fri Oct 29 00:25:04 2010 +0200
@@ -688,7 +688,8 @@
     {
       double e = double (data[i]);
 
-      if (! (xisinf (e) || xisnan (e)))
+      // Don't need to test for NaN here as NaN>x and NaN<x is always false 
+      if (! xisinf (e))
         {
           if (e < emin)
             emin = e;
@@ -1206,6 +1207,62 @@
   return false;
 }
 
+Matrix 
+children_property::do_get_children (bool return_hidden) const
+{
+  Matrix retval (children_list.size (), 1);
+  octave_idx_type k = 0;
+
+  graphics_object go = gh_manager::get_object (0);
+          
+  root_figure::properties& props =
+    dynamic_cast<root_figure::properties&> (go.get_properties ());
+
+  if (! props.is_showhiddenhandles ())
+    {
+      for (const_children_list_iterator p = children_list.begin ();
+           p != children_list.end (); p++)
+        {
+          graphics_handle kid = *p;
+
+          if (gh_manager::is_handle_visible (kid))
+            {
+              if (! return_hidden)
+                retval(k++) = *p;
+            }
+          else if (return_hidden)
+            retval(k++) = *p;
+        }
+
+      retval.resize (k, 1);
+    }
+  else
+    {
+      for (const_children_list_iterator p = children_list.begin ();
+           p != children_list.end (); p++)
+        retval(k++) = *p;
+    }
+      
+  return retval;
+}
+
+void 
+children_property::do_delete_children (bool clear)
+{
+  for (children_list_iterator p = children_list.begin ();
+       p != children_list.end (); p++)
+    {
+      graphics_object go = gh_manager::get_object (*p);
+
+      if (go.valid_object ())
+        gh_manager::free (*p);
+
+    }
+
+  if (clear)
+    children_list.clear ();
+}
+
 bool
 callback_property::validate (const octave_value& v) const
 {
@@ -1883,7 +1940,6 @@
     }
 }
 
-
 static octave_value
 xget (const graphics_handle& h, const caseless_str& name)
 {
@@ -1952,7 +2008,6 @@
 adopt (const graphics_handle& p, const graphics_handle& h)
 {
   graphics_object parent_obj = gh_manager::get_object (p);
-
   parent_obj.adopt (h);
 }
 
@@ -2147,34 +2202,6 @@
 }
 
 void
-base_properties::remove_child (const graphics_handle& h)
-{
-  octave_idx_type k = -1;
-  octave_idx_type n = children.numel ();
-  for (octave_idx_type i = 0; i < n; i++)
-    {
-      if (h.value () == children(i))
-        {
-          k = i;
-          break;
-        }
-    }
-
-  if (k >= 0)
-    {
-      Matrix new_kids (n-1, 1);
-      octave_idx_type j = 0;
-      for (octave_idx_type i = 0; i < n; i++)
-        {
-          if (i != k)
-            new_kids(j++) = children(i);
-        }
-      children = new_kids;
-      mark_modified ();
-    }
-}
-
-void
 base_properties::set_parent (const octave_value& val)
 {
   double tmp = val.double_value ();
@@ -2203,45 +2230,6 @@
 }
 
 void
-base_properties::set_children (const octave_value& val)
-{
-  const Matrix new_kids = val.matrix_value ();
-
-  octave_idx_type nel = new_kids.numel ();
-
-  const Matrix new_kids_column = new_kids.reshape (dim_vector (nel, 1));
-
-  bool ok = true;
-
-  if (! error_state)
-    {
-      const Matrix visible_kids = get_children ();
-
-      if (visible_kids.numel () == new_kids.numel ())
-        {
-          Matrix t1 = visible_kids.sort ();
-          Matrix t2 = new_kids_column.sort ();
-
-          if (t1 != t2)
-            ok = false;
-        }
-      else
-        ok = false;
-
-      if (! ok)
-        error ("set: new children must be a permutation of existing children");
-    }
-  else
-    {
-      ok = false;
-      error ("set: expecting children to be array of graphics handles");
-    }
-
-  if (ok)
-    children = new_kids_column.stack (get_hidden_children ());
-}
-
-void
 base_properties::mark_modified (void)
 {
   __modified__ = "on";
@@ -2269,19 +2257,13 @@
 }
 
 void
-base_properties::delete_children (void)
-{
-  octave_idx_type n = children.numel ();
-
-  // A callback function might have already deleted the child,
-  // so check before deleting
-  for (octave_idx_type i = 0; i < n; i++)
-    {
-      graphics_object go = gh_manager::get_object (children(i));
-
-      if (go.valid_object ())
-        gh_manager::free (children(i));
-    }
+base_properties::update_axis_limits (const std::string& axis_type,
+                                     const graphics_handle& h) const
+{
+  graphics_object obj = gh_manager::get_object (__myhandle__);
+
+  if (obj)
+    obj.update_axis_limits (axis_type, h);
 }
 
 graphics_backend
@@ -2470,6 +2452,21 @@
 }
 
 void
+base_graphics_object::update_axis_limits (const std::string& axis_type,
+                                          const graphics_handle& h)
+{
+  if (valid_object ())
+    {
+      graphics_object parent_obj = gh_manager::get_object (get_parent ());
+
+      if (parent_obj)
+        parent_obj.update_axis_limits (axis_type, h);
+    }
+  else
+    error ("base_graphics_object::update_axis_limits: invalid graphics object");
+}
+
+void
 base_graphics_object::remove_all_listeners (void)
 {
   octave_map m = get (true).map_value ();
@@ -2728,9 +2725,11 @@
     {
       graphics_handle new_currentaxes;
 
-      for (octave_idx_type i = 0; i < children.numel (); i++)
+      Matrix kids = get_children ();
+
+      for (octave_idx_type i = 0; i < kids.numel (); i++)
         {
-          graphics_handle kid = children(i);
+          graphics_handle kid = kids(i);
 
           graphics_object go = gh_manager::get_object (kid);
 
@@ -3418,9 +3417,7 @@
       activepositionproperty = "outerposition";
     }
 
-  delete_children ();
-
-  children = Matrix ();
+  delete_children (true);
 
   xlabel = gh_manager::make_graphics_handle ("text", __myhandle__, false);
   ylabel = gh_manager::make_graphics_handle ("text", __myhandle__, false);
@@ -3504,54 +3501,6 @@
     base_properties::remove_child (h);
 }
 
-Matrix
-base_properties::get_children_internal (bool return_hidden) const
-{
-  Matrix retval = children;
-  
-  graphics_object go = gh_manager::get_object (0);
-
-  root_figure::properties& props =
-      dynamic_cast<root_figure::properties&> (go.get_properties ());
-
-  if (! props.is_showhiddenhandles ())
-    {
-      octave_idx_type k = 0;
-
-      for (octave_idx_type i = 0; i < children.numel (); i++)
-        {
-          graphics_handle kid = children (i);
-
-          if (gh_manager::is_handle_visible (kid))
-            {
-              if (! return_hidden)
-                retval(k++) = children(i);
-            }
-          else
-            {
-              if (return_hidden)
-                retval(k++) = children(i);
-            }
-        }
-
-      retval.resize (k, 1);
-    }
-
-  return retval;
-}
-
-Matrix
-base_properties::get_children (void) const
-{
-  return get_children_internal (false);
-}
-
-Matrix
-base_properties::get_hidden_children (void) const
-{
-  return get_children_internal (true);
-}
-
 inline Matrix
 xform_matrix (void)
 {
@@ -4446,6 +4395,198 @@
 static bool updating_axis_limits = false;
 
 void
+axes::update_axis_limits (const std::string& axis_type,
+                          const graphics_handle& h)
+{
+  if (updating_axis_limits)
+    return;
+
+  Matrix kids = Matrix (1, 1, h.value ());
+ 
+  double min_val = octave_Inf;
+  double max_val = -octave_Inf;
+  double min_pos = octave_Inf;
+
+  char update_type = 0;
+
+  Matrix limits;
+  double val;
+
+#define FIX_LIMITS \
+  if (limits.numel() == 3) \
+    { \
+      val = limits(0); \
+      if (! (xisinf (val) || xisnan (val))) \
+        min_val = val; \
+      val = limits(1); \
+      if (! (xisinf (val) || xisnan (val))) \
+        max_val = val; \
+      val = limits(2); \
+      if (! (xisinf (val) || xisnan (val))) \
+        min_pos = val; \
+    } \
+  else \
+    { \
+      limits.resize(3, 1); \
+      limits(0) = min_val; \
+      limits(1) = max_val; \
+      limits(2) = min_pos; \
+    }
+
+  if (axis_type == "xdata" || axis_type == "xscale"
+      || axis_type == "xlimmode" || axis_type == "xliminclude"
+      || axis_type == "xlim")
+    {
+      if (xproperties.xlimmode_is ("auto"))
+        {
+          limits = xproperties.get_xlim ().matrix_value ();
+          FIX_LIMITS ;
+
+          get_children_limits (min_val, max_val, min_pos, kids, 'x');
+          
+          limits = xproperties.get_axis_limits (min_val, max_val, min_pos,
+                                                xproperties.xscale_is ("log"));
+
+          update_type = 'x';
+        }
+    }
+  else if (axis_type == "ydata" || axis_type == "yscale"
+           || axis_type == "ylimmode" || axis_type == "yliminclude"
+           || axis_type == "ylim")
+    {
+      if (xproperties.ylimmode_is ("auto"))
+        {
+          limits = xproperties.get_ylim ().matrix_value ();
+          FIX_LIMITS ;
+
+          get_children_limits (min_val, max_val, min_pos, kids, 'y');
+
+          limits = xproperties.get_axis_limits (min_val, max_val, min_pos,
+                                                xproperties.yscale_is ("log"));
+
+          update_type = 'y';
+        }
+    }
+  else if (axis_type == "zdata" || axis_type == "zscale"
+           || axis_type == "zlimmode" || axis_type == "zliminclude"
+           || axis_type == "zlim")
+    {
+      if (xproperties.zlimmode_is ("auto"))
+        {
+          limits = xproperties.get_zlim ().matrix_value ();
+          FIX_LIMITS ;
+
+          get_children_limits (min_val, max_val, min_pos, kids, 'z');
+
+          limits = xproperties.get_axis_limits (min_val, max_val, min_pos,
+                                                xproperties.zscale_is ("log"));
+
+          update_type = 'z';
+        }
+    }
+  else if (axis_type == "cdata" || axis_type == "climmode"
+           || axis_type == "cdatamapping" || axis_type == "climinclude"
+           || axis_type == "clim")
+    {
+      if (xproperties.climmode_is ("auto"))
+        {
+          limits = xproperties.get_clim ().matrix_value ();
+          FIX_LIMITS ;
+
+          get_children_limits (min_val, max_val, min_pos, kids, 'c');
+
+          if (min_val > max_val)
+            {
+              min_val = min_pos = 0;
+              max_val = 1;
+            }
+          else 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';
+        }
+
+    }
+  else if (axis_type == "alphadata" || axis_type == "alimmode"
+           || axis_type == "alphadatamapping" || axis_type == "aliminclude"
+           || axis_type == "alim")
+    {
+      if (xproperties.alimmode_is ("auto"))
+        {
+          limits = xproperties.get_alim ().matrix_value ();
+          FIX_LIMITS ;
+
+          get_children_limits (min_val, max_val, min_pos, kids, 'a');
+
+          if (min_val > max_val)
+            {
+              min_val = min_pos = 0;
+              max_val = 1;
+            }
+          else if (min_val == max_val)
+            max_val = min_val + 1;
+
+          limits.resize (1, 2);
+
+          limits(0) = min_val;
+          limits(1) = max_val;
+
+          update_type = 'a';
+        }
+
+    }
+
+#undef FIX_LIMITS
+
+  unwind_protect frame;
+  frame.protect_var (updating_axis_limits);
+
+  updating_axis_limits = true;
+
+  switch (update_type)
+    {
+    case 'x':
+      xproperties.set_xlim (limits);
+      xproperties.set_xlimmode ("auto");
+      xproperties.update_xlim ();
+      break;
+
+    case 'y':
+      xproperties.set_ylim (limits);
+      xproperties.set_ylimmode ("auto");
+      xproperties.update_ylim ();
+      break;
+
+    case 'z':
+      xproperties.set_zlim (limits);
+      xproperties.set_zlimmode ("auto");
+      xproperties.update_zlim ();
+      break;
+
+    case 'c':
+      xproperties.set_clim (limits);
+      xproperties.set_climmode ("auto");
+      break;
+
+    case 'a':
+      xproperties.set_alim (limits);
+      xproperties.set_alimmode ("auto");
+      break;
+
+    default:
+      break;
+    }
+
+  xproperties.update_transform ();
+
+}
+
+void
 axes::update_axis_limits (const std::string& axis_type)
 {
   if (updating_axis_limits)
@@ -4957,9 +5098,151 @@
 
 // ---------------------------------------------------------------------
 
+void 
+hggroup::properties::update_limits (void) const
+{
+  graphics_object obj = gh_manager::get_object (__myhandle__);
+
+  if (obj)
+    {
+      obj.update_axis_limits ("xlim");
+      obj.update_axis_limits ("ylim");
+      obj.update_axis_limits ("zlim");
+      obj.update_axis_limits ("clim");
+      obj.update_axis_limits ("alim");
+    }
+}
+
+void 
+hggroup::properties::update_limits (const graphics_handle& h) const
+{
+  graphics_object obj = gh_manager::get_object (__myhandle__);
+
+  if (obj)
+    {
+      obj.update_axis_limits ("xlim", h);
+      obj.update_axis_limits ("ylim", h);
+      obj.update_axis_limits ("zlim", h);
+      obj.update_axis_limits ("clim", h);
+      obj.update_axis_limits ("alim", h);
+    }
+}
+
+static bool updating_hggroup_limits = false;
+
+void
+hggroup::update_axis_limits (const std::string& axis_type,
+                             const graphics_handle& h)
+{
+  if (updating_hggroup_limits)
+    return;
+
+  Matrix kids = Matrix (1, 1, h.value ());
+ 
+  double min_val = octave_Inf;
+  double max_val = -octave_Inf;
+  double min_pos = octave_Inf;
+
+  Matrix limits;
+  double val;
+
+  char update_type = 0;
+
+  if (axis_type == "xlim" || axis_type == "xliminclude")
+    {
+      limits = xproperties.get_xlim ().matrix_value ();
+      update_type = 'x';
+    }
+  else if (axis_type == "ylim" || axis_type == "yliminclude")
+    {
+      limits = xproperties.get_ylim ().matrix_value ();
+      update_type = 'y';
+    }
+  else if (axis_type == "zlim" || axis_type == "zliminclude")
+    {
+      limits = xproperties.get_zlim ().matrix_value ();
+      update_type = 'z';
+    }
+  else if (axis_type == "clim" || axis_type == "climinclude")
+    {
+      limits = xproperties.get_clim ().matrix_value ();
+      update_type = 'c';
+    }
+  else if (axis_type == "alim" || axis_type == "aliminclude")
+    {
+      limits = xproperties.get_alim ().matrix_value ();
+      update_type = 'a';
+    }
+
+  if (limits.numel() == 3)
+    {
+      val = limits(0);
+      if (! (xisinf (val) || xisnan (val)))
+        min_val = val;
+      val = limits(1);
+      if (! (xisinf (val) || xisnan (val)))
+        max_val = val;
+      val = limits(2);
+      if (! (xisinf (val) || xisnan (val)))
+        min_pos = val;
+    }
+  else
+    {
+      limits.resize(3,1);
+      limits(0) = min_val;
+      limits(1) = max_val;
+      limits(2) = min_pos;
+    }
+
+  get_children_limits (min_val, max_val, min_pos, kids, update_type);
+
+  unwind_protect frame;
+  frame.protect_var (updating_hggroup_limits);
+
+  updating_hggroup_limits = true;
+
+  if (limits(0) != min_val || limits(1) != max_val || limits(2) != min_pos)
+    {
+      limits(0) = min_val;
+      limits(1) = max_val;
+      limits(2) = min_pos;
+
+      switch (update_type)
+        {
+        case 'x':
+          xproperties.set_xlim (limits);
+          break;
+
+        case 'y':
+          xproperties.set_ylim (limits);
+          break;
+
+        case 'z':
+          xproperties.set_zlim (limits);
+          break;
+
+        case 'c':
+          xproperties.set_clim (limits);
+          break;
+
+        case 'a':
+          xproperties.set_alim (limits);
+          break;
+
+        default:
+          break;
+        }
+
+      base_graphics_object::update_axis_limits (axis_type, h);
+    }
+}
+
 void
 hggroup::update_axis_limits (const std::string& axis_type)
 {
+  if (updating_hggroup_limits)
+    return;
+
   Matrix kids = xproperties.get_children ();
 
   double min_val = octave_Inf;
@@ -4971,7 +5254,7 @@
   if (axis_type == "xlim" || axis_type == "xliminclude")
     {
       get_children_limits (min_val, max_val, min_pos, kids, 'x');
-      
+          
       update_type = 'x';
     }
   else if (axis_type == "ylim" || axis_type == "yliminclude")
@@ -4991,7 +5274,6 @@
       get_children_limits (min_val, max_val, min_pos, kids, 'c');
 
       update_type = 'c';
-
     }
   else if (axis_type == "alim" || axis_type == "aliminclude")
     {
@@ -5000,6 +5282,11 @@
       update_type = 'a';
     }
 
+  unwind_protect frame;
+  frame.protect_var (updating_hggroup_limits);
+
+  updating_hggroup_limits = true;
+
   Matrix limits (1, 3, 0.0);
 
   limits(0) = min_val;
@@ -5774,6 +6061,10 @@
 make_graphics_object (const std::string& go_name,
                       const octave_value_list& args)
 {
+  //octave_time now;
+  //double t1, t2, t3;
+  //double t0 = now.double_value ();
+
   octave_value retval;
 
   double val = octave_NaN;
@@ -5816,9 +6107,15 @@
           if (! error_state)
             {
               adopt (parent, h);
+              //now.stamp();
+              //t1 = now.double_value ();
 
               xset (h, xargs);
+              //now.stamp();
+              //t2 = now.double_value ();
               xcreatefcn (h);
+              //now.stamp();
+              //t3 = now.double_value ();
 
               retval = h.value ();
 
@@ -5835,6 +6132,10 @@
   else
     error ("__go_%s__: invalid parent", go_name.c_str ());
 
+  
+  //now.stamp();
+  //octave_stdout << "Make object times : " << t1 - t0 << " " << t2 - t1 << " " << t3 - t2 << " " << now.double_value() - t3 << " seconds.\n";
+
   return retval;
 }
 
--- a/src/graphics.h.in	Thu Oct 28 13:22:49 2010 +0800
+++ b/src/graphics.h.in	Fri Oct 29 00:25:04 2010 +0200
@@ -1368,6 +1368,174 @@
 
 // ---------------------------------------------------------------------
 
+class children_property : public base_property
+{
+public: 
+  children_property (void)
+    : base_property ("", graphics_handle ())
+    {
+      do_init_children (Matrix ());
+    }
+  
+  children_property (const std::string& nm, const graphics_handle& h,
+                     const Matrix &val)
+    : base_property (nm, h)
+    {
+      do_init_children (val);
+    }
+
+  children_property (const children_property& p)
+    : base_property (p) 
+    {
+      do_init_children (p.children_list);
+    }
+
+  children_property& operator = (const octave_value& val)
+    {
+      set (val);
+      return *this;
+    }
+
+  base_property* clone (void) const { return new children_property (*this); }
+
+  bool remove_child (const double &val)
+    {
+      return do_remove_child (val);
+    }
+  
+  void adopt (const double &val)
+    {
+      do_adopt_child (val);
+    }
+  
+  Matrix get_children (void) const
+    {
+      return do_get_children (false);
+    }
+  
+  Matrix get_hidden (void) const
+    {
+      return do_get_children (true);
+    }
+
+  Matrix get_all (void) const
+   {
+     return do_get_all_children ();
+   }
+  
+  octave_value get (void) const
+    {
+      return octave_value (get_children ());
+    }
+  
+  void delete_children (bool clear = false)
+    {
+      do_delete_children (clear);
+    }
+  
+private:
+  typedef std::list<double>::iterator children_list_iterator;
+  typedef std::list<double>::const_iterator const_children_list_iterator;
+  std::list<double> children_list;
+
+protected:
+  bool do_set (const octave_value& val)
+    {
+      const Matrix new_kids = val.matrix_value ();
+
+      octave_idx_type nel = new_kids.numel ();
+
+      const Matrix new_kids_column = new_kids.reshape (dim_vector (nel, 1));
+
+      bool is_ok = true;
+
+      if (! error_state)
+        {
+          const Matrix visible_kids = do_get_children (false);
+
+          if (visible_kids.numel () == new_kids.numel ())
+            {
+              Matrix t1 = visible_kids.sort ();
+              Matrix t2 = new_kids_column.sort ();
+
+              if (t1 != t2)
+                is_ok = false;
+            }
+          else
+            is_ok = false;
+
+          if (! is_ok)
+            error ("set: new children must be a permutation of existing children");
+        }
+      else
+        {
+          is_ok = false;
+          error ("set: expecting children to be array of graphics handles");
+        }
+
+      if (is_ok)
+        {
+          children_list.clear ();
+          do_init_children (new_kids_column.stack (get_hidden ()));
+        }
+
+      return is_ok;
+    }
+
+private:
+  void do_init_children (const Matrix &val)
+    {
+      children_list.clear ();
+      for (octave_idx_type i = 0; i < val.numel (); i++)
+        children_list.push_front (val.xelem (i));
+    }
+
+  void do_init_children (const std::list<double> &val)
+    {
+      children_list.clear ();
+      for (const_children_list_iterator p = val.begin (); p != val.end (); p++)
+        children_list.push_front (*p);
+    }
+
+  Matrix do_get_children (bool return_hidden) const;
+
+  Matrix do_get_all_children (void) const
+    {
+      Matrix retval (children_list.size (), 1);
+      octave_idx_type i  = 0;
+      
+      for (const_children_list_iterator p = children_list.begin ();
+           p != children_list.end (); p++)
+        retval(i++) = *p;
+      return retval;
+    }
+
+  bool do_remove_child (double child)
+    {
+      for (children_list_iterator p = children_list.begin ();
+           p != children_list.end (); p++)
+        {
+          if (*p == child)
+            {
+              children_list.erase (p);
+              return true;
+            }
+        }
+      return false;
+    }
+
+  void do_adopt_child (const double &val)
+    {
+      children_list.push_front (val);
+    }
+  
+  void do_delete_children (bool clear);
+};
+
+
+
+// ---------------------------------------------------------------------
+
 class callback_property : public base_property
 {
 public:
@@ -1848,15 +2016,15 @@
 
   bool is_modified (void) const { return is___modified__ (); }
  
-  virtual void remove_child (const graphics_handle& h);
+  virtual void remove_child (const graphics_handle& h)
+    {
+      if (children.remove_child (h.value ()))
+        mark_modified ();
+    }
 
   virtual void adopt (const graphics_handle& h)
   {
-    octave_idx_type n = children.numel ();
-    children.resize (n+1, 1);
-    for (octave_idx_type i = n; i > 0; i--)
-      children(i) = children(i-1);
-    children(0) = h.value ();
+    children.adopt (h.value ());
     mark_modified ();
   }
 
@@ -1877,11 +2045,20 @@
 
   void set_parent (const octave_value& val);
 
-  Matrix get_all_children (void) const { return children; }
-
-  Matrix get_hidden_children (void) const;
-
-  void set_children (const octave_value& val);
+  Matrix get_children (void) const
+    {
+      return children.get_children ();
+    }
+  
+  Matrix get_all_children (void) const 
+    { 
+      return children.get_all ();
+    }
+
+  Matrix get_hidden_children (void) const
+    {
+      return children.get_hidden ();
+    }
 
   void set_modified (const octave_value& val) { set___modified__ (val); }
 
@@ -1894,8 +2071,14 @@
 
   virtual void update_axis_limits (const std::string& axis_type) const;
 
-  virtual void delete_children (void);
-
+  virtual void update_axis_limits (const std::string& axis_type,
+                                   const graphics_handle& h) const;
+
+  virtual void delete_children (bool clear = false)
+    {
+      children.delete_children (clear);
+    }
+  
   static property_list::pval_map_type factory_defaults (void);
 
   // FIXME -- these functions should be generated automatically by the
@@ -1940,8 +2123,7 @@
     bool_property beingdeleted , "off"
     radio_property busyaction , "{queue}|cancel"
     callback_property buttondownfcn , Matrix ()
-    // FIXME -- use a property class for children.
-    Matrix children Gfs , Matrix ()
+    children_property children gf , Matrix ()
     bool_property clipping , "on"
     callback_property createfcn , Matrix ()
     callback_property deletefcn , Matrix ()
@@ -1983,9 +2165,6 @@
     { insert_property (name, property (&p, true)); }
   
   virtual void init (void) { }
-
-private:
-  Matrix get_children_internal (bool return_hidden) const;
 };
 
 class OCTINTERP_API base_graphics_object
@@ -2151,6 +2330,9 @@
 
   virtual void update_axis_limits (const std::string& axis_type);
 
+  virtual void update_axis_limits (const std::string& axis_type,
+                                   const graphics_handle& h);
+
   virtual bool valid_object (void) const { return false; }
 
   virtual std::string type (void) const
@@ -2336,6 +2518,12 @@
     rep->update_axis_limits (axis_type);
   }
 
+  void update_axis_limits (const std::string& axis_type,
+                           const graphics_handle& h)
+  {
+    rep->update_axis_limits (axis_type, h);
+  }
+
   bool valid_object (void) const { return rep->valid_object (); }
 
   std::string type (void) const { return rep->type (); }
@@ -3191,6 +3379,9 @@
 
   void update_axis_limits (const std::string& axis_type);
 
+  void update_axis_limits (const std::string& axis_type,
+                           const graphics_handle& h);
+
   bool valid_object (void) const { return true; }
 
   void reset_default_properties (void);
@@ -3796,8 +3987,9 @@
 
     void adopt (const graphics_handle& h)
       {
+
         base_properties::adopt (h);
-        update_limits ();
+        update_limits (h);
       }
 
     // See the genprops.awk script for an explanation of the
@@ -3818,18 +4010,14 @@
     END_PROPERTIES
 
   private:
-    void update_limits (void)
-      {
-        update_axis_limits ("xlim");
-        update_axis_limits ("ylim");
-        update_axis_limits ("zlim");
-        update_axis_limits ("clim");
-        update_axis_limits ("alim");
-      }
+      void update_limits (void) const;
+
+      void update_limits (const graphics_handle& h) const;
 
   protected:
     void init (void)
       { }
+
   };
 
 private:
@@ -3849,8 +4037,12 @@
   const base_properties& get_properties (void) const { return xproperties; }
 
   bool valid_object (void) const { return true; }
-  
+
   void update_axis_limits (const std::string& axis_type);
+
+  void update_axis_limits (const std::string& axis_type,
+                           const graphics_handle& h);
+
 };
 
 // ---------------------------------------------------------------------