# HG changeset patch
# User Markus Mützel <markus.muetzel@gmx.de>
# Date 1478351890 -3600
#      Sat Nov 05 14:18:10 2016 +0100
# Node ID ccc70d82adc1047aa6ab6946716e8d0511be3b4a
# Parent  03cebe1fb0e3a65b89413702b6871e7e4104632b
Improve support of "(xy)axislocation" "origin" (bug #48562).

* graphics.[cc,in.h] (calc_ticklabels): Omit tick labels that are
obstructed by axes.
* gl-render.cc (opengl_renderer::draw_axes_[xy]_grid): Swap ticks and
labels when origin crosses the middle of the plot. Draw axis at border
if origin is outside of axis limits.

diff -r 03cebe1fb0e3 -r ccc70d82adc1 libinterp/corefcn/gl-render.cc
--- a/libinterp/corefcn/gl-render.cc	Thu Nov 03 13:24:21 2016 +0100
+++ b/libinterp/corefcn/gl-render.cc	Sat Nov 05 14:18:10 2016 +0100
@@ -1362,6 +1362,8 @@
         double fz = props.get_fz ();
         double x_min = props.get_x_min ();
         double x_max = props.get_x_max ();
+        double y_min = props.get_y_min ();
+        double y_max = props.get_y_max ();
         double yPlane = props.get_yPlane ();
         double yPlaneN = props.get_yPlaneN ();
         double ypTick = props.get_ypTick ();
@@ -1385,6 +1387,7 @@
                               && (minorgridstyle != "none"));
         bool do_xminortick = props.is_xminortick ();
         bool is_origin = props.xaxislocation_is ("origin") && props.get_is2D ();
+        bool is_origin_low = is_origin && (y_min+y_max)<0;
         Matrix xticks = xform.xscale (props.get_xtick ().matrix_value ());
         Matrix xmticks = xform.xscale (props.get_xminortickvalues ().matrix_value ());
         string_vector xticklabels = props.get_xticklabel ().string_vector_value ();
@@ -1430,11 +1433,13 @@
         set_color (props.get_xcolor_rgb ());
 
         // axis line
+        double y_axis_pos = 0.;
         if (is_origin)
           {
             glBegin (GL_LINES);
-            glVertex3d (x_min, 0, zpTick);
-            glVertex3d (x_max, 0, zpTick);
+            y_axis_pos = octave::math::max (octave::math::min (0., y_max), y_min);
+            glVertex3d (x_min, y_axis_pos, zpTick);
+            glVertex3d (x_max, y_axis_pos, zpTick);
             glEnd ();
           }
 
@@ -1443,50 +1448,56 @@
           {
             if (tick_along_z)
               render_tickmarks (xmticks, x_min, x_max,
-                                (is_origin ? 0. : ypTick), ypTick,
+                                is_origin ? y_axis_pos : ypTick, ypTick,
                                 zpTick, zpTickN, 0., 0.,
+                                (is_origin_low ? -1. : 1.) * 
                                 octave::math::signum (zpTick-zpTickN)*fz*xticklen/2,
-                                0, mirror);
+                                0, ! is_origin && mirror);
             else
               render_tickmarks (xmticks, x_min, x_max,
-                                (is_origin ? 0. : ypTick), ypTickN,
+                                is_origin ? y_axis_pos : ypTick, ypTickN,
                                 zpTick, zpTick, 0.,
+                                (is_origin_low ? -1. : 1.) * 
                                 octave::math::signum (ypTick-ypTickN)*fy*xticklen/2,
-                                0., 0, mirror);
+                                0., 0, ! is_origin && mirror);
           }
 
         // tick marks
         if (tick_along_z)
-          {
-            render_tickmarks (xticks, x_min, x_max,
-                              (is_origin ? 0. : ypTick), ypTick,
-                              zpTick, zpTickN, 0., 0.,
-                              octave::math::signum (zpTick-zpTickN)*fz*xticklen,
-                              0, mirror);
-          }
+          render_tickmarks (xticks, x_min, x_max,
+                            is_origin ? y_axis_pos : ypTick, ypTick,
+                            zpTick, zpTickN, 0., 0.,
+                            (is_origin_low ? -1. : 1.) * 
+                            octave::math::signum (zpTick-zpTickN)*fz*xticklen,
+                            0, ! is_origin && mirror);
         else
-          {
-            render_tickmarks (xticks, x_min, x_max,
-                              (is_origin ? 0. : ypTick), ypTickN,
-                              zpTick, zpTick, 0.,
-                              octave::math::signum (ypTick-ypTickN)*fy*xticklen,
-                              0., 0, mirror);
-          }
+          render_tickmarks (xticks, x_min, x_max,
+                            is_origin ? y_axis_pos : ypTick, ypTickN,
+                            zpTick, zpTick, 0.,
+                            (is_origin_low ? -1. : 1.) * 
+                            octave::math::signum (ypTick-ypTickN)*fy*xticklen,
+                            0., 0, ! is_origin && mirror);
 
         // tick texts
         if (xticklabels.numel () > 0)
           {
-            int halign = (xstate == AXE_HORZ_DIR ? 1 : (xyzSym ? 0 : 2));
-            int valign = (xstate == AXE_VERT_DIR ? 1 : (x2Dtop ? 0 : 2));
+            int halign = (xstate == AXE_HORZ_DIR ? 1 :
+                          (xyzSym || is_origin_low ? 0 : 2));
+            int valign = (xstate == AXE_VERT_DIR ? 1 :
+                          (x2Dtop || is_origin_low ? 0 : 2));
 
             if (tick_along_z)
               render_ticktexts (xticks, xticklabels, x_min, x_max,
-                                (is_origin ? 0. : ypTick),
-                                zpTick+octave::math::signum (zpTick-zpTickN)*fz*xtickoffset,
+                                is_origin ? y_axis_pos : ypTick,
+                                zpTick +
+                                (is_origin_low ? -1. : 1.) * 
+                                octave::math::signum (zpTick-zpTickN)*fz*xtickoffset,
                                 0, halign, valign, wmax, hmax);
             else
               render_ticktexts (xticks, xticklabels, x_min, x_max,
-                                (is_origin ? 0. : ypTick) + octave::math::signum (ypTick-ypTickN)*fy*xtickoffset,
+                                (is_origin ? y_axis_pos : ypTick) +
+                                (is_origin_low ?  -1. : 1.) *
+                                octave::math::signum (ypTick-ypTickN)*fy*xtickoffset,
                                 zpTick, 0, halign, valign, wmax, hmax);
           }
 
@@ -1518,6 +1529,8 @@
         double xpTickN = props.get_xpTickN ();
         double y_min = props.get_y_min ();
         double y_max = props.get_y_max ();
+        double x_min = props.get_x_min ();
+        double x_max = props.get_x_max ();
         double zPlane = props.get_zPlane ();
         double zPlaneN = props.get_zPlaneN ();
         double zpTick = props.get_zpTick ();
@@ -1537,6 +1550,7 @@
                               && (minorgridstyle != "none"));
         bool do_yminortick = props.is_yminortick ();
         bool is_origin = props.yaxislocation_is ("origin") && props.get_is2D ();
+        bool is_origin_low = is_origin && (x_min+x_max)<0;
         Matrix yticks = xform.yscale (props.get_ytick ().matrix_value ());
         Matrix ymticks = xform.yscale (props.get_yminortickvalues ().matrix_value ());
         string_vector yticklabels = props.get_yticklabel ().string_vector_value ();
@@ -1583,11 +1597,13 @@
         set_color (props.get_ycolor_rgb ());
 
         // axis line
+        double x_axis_pos = 0.;
         if (is_origin)
           {
             glBegin (GL_LINES);
-            glVertex3d (0., y_min, zpTick);
-            glVertex3d (0., y_max, zpTick);
+            x_axis_pos = octave::math::max (octave::math::min (0., x_max), x_min);
+            glVertex3d (x_axis_pos, y_min, zpTick);
+            glVertex3d (x_axis_pos, y_max, zpTick);
             glEnd ();
           }
 
@@ -1596,47 +1612,55 @@
           {
             if (tick_along_z)
               render_tickmarks (ymticks, y_min, y_max,
-                                (is_origin ? 0. : xpTick), xpTick,
+                                is_origin ? x_axis_pos : xpTick, xpTick,
                                 zpTick, zpTickN, 0., 0.,
+                                (is_origin_low ? -1. : 1.) * 
                                 octave::math::signum (zpTick-zpTickN)*fz*yticklen/2,
-                                1, mirror);
+                                1, ! is_origin && mirror);
             else
               render_tickmarks (ymticks, y_min, y_max,
-                                (is_origin ? 0. : xpTick), xpTickN,
+                                is_origin ? x_axis_pos : xpTick, xpTickN,
                                 zpTick, zpTick,
+                                (is_origin_low ? -1. : 1.) * 
                                 octave::math::signum (xpTick-xpTickN)*fx*yticklen/2,
-                                0., 0., 1, mirror);
+                                0., 0., 1, ! is_origin && mirror);
           }
 
         // tick marks
         if (tick_along_z)
           render_tickmarks (yticks, y_min, y_max,
-                            (is_origin ? 0. : xpTick), xpTick,
+                            is_origin ? x_axis_pos : xpTick, xpTick,
                             zpTick, zpTickN, 0., 0.,
+                            (is_origin_low ? -1. : 1.) * 
                             octave::math::signum (zpTick-zpTickN)*fz*yticklen,
-                            1, mirror);
+                            1, ! is_origin && mirror);
         else
           render_tickmarks (yticks, y_min, y_max,
-                            (is_origin ? 0. : xpTick), xpTickN,
+                            is_origin ? x_axis_pos : xpTick, xpTickN,
                             zpTick, zpTick,
+                            (is_origin_low ? -1. : 1.) * 
                             octave::math::signum (xPlaneN-xPlane)*fx*yticklen,
-                            0., 0., 1, mirror);
+                            0., 0., 1, ! is_origin && mirror);
 
         // tick texts
         if (yticklabels.numel () > 0)
           {
-            int halign = (ystate == AXE_HORZ_DIR
-                          ? 1 : (! xyzSym || y2Dright ? 0 : 2));
-            int valign = (ystate == AXE_VERT_DIR ? 1 : 2);
+            int halign = (ystate == AXE_HORZ_DIR ? 1 :
+                          (! xyzSym || y2Dright || is_origin_low ? 0 : 2));
+            int valign = (ystate == AXE_VERT_DIR ? 1 : (is_origin_low ? 0 : 2));
 
             if (tick_along_z)
               render_ticktexts (yticks, yticklabels, y_min, y_max,
-                                (is_origin ? 0. : xpTick),
-                                zpTick+octave::math::signum (zpTick-zpTickN)*fz*ytickoffset,
+                                is_origin ? x_axis_pos : xpTick,
+                                zpTick +
+                                (is_origin_low ? -1. : 1.) * 
+                                octave::math::signum (zpTick-zpTickN)*fz*ytickoffset,
                                 1, halign, valign, wmax, hmax);
             else
               render_ticktexts (yticks, yticklabels, y_min, y_max,
-                                (is_origin ? 0. : xpTick) + octave::math::signum (xpTick-xpTickN)*fx*ytickoffset,
+                                (is_origin ? x_axis_pos : xpTick) +
+                                (is_origin_low ?  -1. : 1.) *
+                                octave::math::signum (xpTick-xpTickN)*fx*ytickoffset,
                                 zpTick, 1, halign, valign, wmax, hmax);
           }
 
diff -r 03cebe1fb0e3 -r ccc70d82adc1 libinterp/corefcn/graphics.cc
--- a/libinterp/corefcn/graphics.cc	Thu Nov 03 13:24:21 2016 +0100
+++ b/libinterp/corefcn/graphics.cc	Sat Nov 05 14:18:10 2016 +0100
@@ -4517,9 +4517,13 @@
   sy = "linear";
   sz = "linear";
 
-  calc_ticklabels (xtick, xticklabel, xscale.is ("log"));
-  calc_ticklabels (ytick, yticklabel, yscale.is ("log"));
-  calc_ticklabels (ztick, zticklabel, zscale.is ("log"));
+  calc_ticklabels (xtick, xticklabel, xscale.is ("log"), xaxislocation_is ("origin"),
+                   yaxislocation_is ("origin") ? 0 : (yaxislocation_is ("left") ? -1 : 1),
+                   xlim);
+  calc_ticklabels (ytick, yticklabel, yscale.is ("log"), yaxislocation_is ("origin"),
+                   xaxislocation_is ("origin") ? 0 : (xaxislocation_is ("bottom") ? -1 : 1),
+                   ylim);
+  calc_ticklabels (ztick, zticklabel, zscale.is ("log"), false, 2, zlim);
 
   xset (xlabel.handle_value (), "handlevisibility", "off");
   xset (ylabel.handle_value (), "handlevisibility", "off");
@@ -7022,12 +7026,38 @@
 
 void
 axes::properties::calc_ticklabels (const array_property& ticks,
-                                   any_property& labels, bool logscale)
+                                   any_property& labels, bool logscale,
+                                   const bool is_origin,
+                                   const int other_axislocation,
+                                   const array_property& axis_lims)
 {
   Matrix values = ticks.get ().matrix_value ();
+  Matrix lims = axis_lims.get ().matrix_value ();
   Cell c (values.dims ());
   std::ostringstream os;
 
+  // omit tick labels depending on location of other axis
+  ColumnVector omit_ticks (3, octave::numeric_limits<double>::NaN ());
+  if (get_is2D () && is_origin)
+    {
+      if (other_axislocation == 0)
+        {
+          if (logscale)
+            omit_ticks(0) = 1.;
+          else
+            omit_ticks(0) = 0.;
+        }
+      else if (other_axislocation == 1)
+        omit_ticks(0) = lims(1);
+      else if (other_axislocation == -1)
+        omit_ticks(0) = lims(0);
+      if (is_box ())
+        {
+          omit_ticks(1) = lims(0);
+          omit_ticks(2) = lims(1);
+        }
+    }
+
   if (logscale)
     {
       double significand;
@@ -7044,6 +7074,16 @@
 
       for (int i = 0; i < values.numel (); i++)
         {
+          bool omit_tick = false;
+          for (int i_omit = 0; i_omit < omit_ticks.numel (); i_omit++)
+            if (values(i) == omit_ticks(i_omit))
+              omit_tick = true;
+          if (omit_tick)
+            {
+              c(i) = "";
+              continue;
+            }
+
           if (values(i) < 0.0)
             exponent = std::floor (std::log10 (-values(i)));
           else
@@ -7074,9 +7114,18 @@
     {
       for (int i = 0; i < values.numel (); i++)
         {
-          os.str ("");
-          os << values(i);
-          c(i) = os.str ();
+          bool omit_tick = false;
+          for (int i_omit = 0; i_omit < omit_ticks.numel (); i_omit++)
+            if (values(i) == omit_ticks(i_omit))
+              omit_tick = true;
+          if (omit_tick)
+            c(i) = "";
+          else
+            {
+              os.str ("");
+              os << values(i);
+              c(i) = os.str ();
+            }
         }
     }
 
diff -r 03cebe1fb0e3 -r ccc70d82adc1 libinterp/corefcn/graphics.in.h
--- a/libinterp/corefcn/graphics.in.h	Thu Nov 03 13:24:21 2016 +0100
+++ b/libinterp/corefcn/graphics.in.h	Sat Nov 05 14:18:10 2016 +0100
@@ -3812,7 +3812,7 @@
       row_vector_property alim m , default_lim ()
       radio_property alimmode , "{auto}|manual"
       color_property ambientlightcolor , color_values (1, 1, 1)
-      bool_property box , "off"
+      bool_property box u , "off"
       radio_property boxstyle , "{back}|full"
       array_property cameraposition m , Matrix (1, 3, 0.0)
       radio_property camerapositionmode , "{auto}|manual"
@@ -3982,6 +3982,15 @@
     void update_plotboxaspectratiomode (void) { sync_positions (); }
 
     void update_layer (void) { update_axes_layout (); }
+    void update_box (void)
+    {
+      calc_ticklabels (xtick, xticklabel, xscale.is ("log"), xaxislocation_is ("origin"),
+                   yaxislocation_is ("origin") ? 0 : (yaxislocation_is ("left") ? -1 : 1),
+                   xlim);
+      calc_ticklabels (ytick, yticklabel, yscale.is ("log"), yaxislocation_is ("origin"),
+                   xaxislocation_is ("origin") ? 0 : (xaxislocation_is ("bottom") ? -1 : 1),
+                   ylim);
+    }
     void update_yaxislocation (void)
     {
       // FIXME: Remove warning with "zero" in 4.6
@@ -3991,6 +4000,12 @@
                          "set to 'origin' instead.");
       sync_positions ();
       update_axes_layout ();
+      calc_ticklabels (xtick, xticklabel, xscale.is ("log"), xaxislocation_is ("origin"),
+                   yaxislocation_is ("origin") ? 0 : (yaxislocation_is ("left") ? -1 : 1),
+                   xlim);
+      calc_ticklabels (ytick, yticklabel, yscale.is ("log"), yaxislocation_is ("origin"),
+                   xaxislocation_is ("origin") ? 0 : (xaxislocation_is ("bottom") ? -1 : 1),
+                   ylim);
       update_ylabel_position ();
     }
     void update_xaxislocation (void)
@@ -4002,6 +4017,12 @@
                          "set to 'origin' instead.");
       sync_positions ();
       update_axes_layout ();
+      calc_ticklabels (xtick, xticklabel, xscale.is ("log"), xaxislocation_is ("origin"),
+                   yaxislocation_is ("origin") ? 0 : (yaxislocation_is ("left") ? -1 : 1),
+                   xlim);
+      calc_ticklabels (ytick, yticklabel, yscale.is ("log"), yaxislocation_is ("origin"),
+                   xaxislocation_is ("origin") ? 0 : (xaxislocation_is ("bottom") ? -1 : 1),
+                   ylim);
       update_xlabel_position ();
     }
 
@@ -4018,7 +4039,9 @@
       calc_ticks_and_lims (xlim, xtick, xminortickvalues, xlimmode.is ("auto"),
                            xtickmode.is ("auto"), xscale.is ("log"));
       if (xticklabelmode.is ("auto"))
-        calc_ticklabels (xtick, xticklabel, xscale.is ("log"));
+        calc_ticklabels (xtick, xticklabel, xscale.is ("log"), xaxislocation_is ("origin"),
+                   yaxislocation_is ("origin") ? 0 : (yaxislocation_is ("left") ? -1 : 1),
+                   xlim);
       sync_positions ();
     }
     void update_ytick (void)
@@ -4026,7 +4049,9 @@
       calc_ticks_and_lims (ylim, ytick, yminortickvalues, ylimmode.is ("auto"),
                            ytickmode.is ("auto"), yscale.is ("log"));
       if (yticklabelmode.is ("auto"))
-        calc_ticklabels (ytick, yticklabel, yscale.is ("log"));
+        calc_ticklabels (ytick, yticklabel, yscale.is ("log"), yaxislocation_is ("origin"),
+                   xaxislocation_is ("origin") ? 0 : (xaxislocation_is ("bottom") ? -1 : 1),
+                   ylim);
       sync_positions ();
     }
     void update_ztick (void)
@@ -4034,7 +4059,7 @@
       calc_ticks_and_lims (zlim, ztick, zminortickvalues, zlimmode.is ("auto"),
                            ztickmode.is ("auto"), zscale.is ("log"));
       if (zticklabelmode.is ("auto"))
-        calc_ticklabels (ztick, zticklabel, zscale.is ("log"));
+        calc_ticklabels (ztick, zticklabel, zscale.is ("log"), false, 2, zlim);
       sync_positions ();
     }
 
@@ -4057,17 +4082,21 @@
     void update_xticklabelmode (void)
     {
       if (xticklabelmode.is ("auto"))
-        calc_ticklabels (xtick, xticklabel, xscale.is ("log"));
+        calc_ticklabels (xtick, xticklabel, xscale.is ("log"), xaxislocation_is ("origin"),
+                   yaxislocation_is ("origin") ? 0 : (yaxislocation_is ("left") ? -1 : 1),
+                   xlim);
     }
     void update_yticklabelmode (void)
     {
       if (yticklabelmode.is ("auto"))
-        calc_ticklabels (ytick, yticklabel, yscale.is ("log"));
+        calc_ticklabels (ytick, yticklabel, yscale.is ("log"), yaxislocation_is ("origin"),
+                   xaxislocation_is ("origin") ? 0 : (xaxislocation_is ("bottom") ? -1 : 1),
+                   ylim);
     }
     void update_zticklabelmode (void)
     {
       if (zticklabelmode.is ("auto"))
-        calc_ticklabels (ztick, zticklabel, zscale.is ("log"));
+        calc_ticklabels (ztick, zticklabel, zscale.is ("log"), false, 2, zlim);
     }
 
     void update_font (std::string prop = "");
@@ -4195,7 +4224,9 @@
                               array_property& mticks, bool limmode_is_auto,
                               bool tickmode_is_auto, bool is_logscale);
     void calc_ticklabels (const array_property& ticks, any_property& labels,
-                          bool is_logscale);
+                          bool is_logscale, const bool is_origin,
+                          const int other_axislocation,
+                          const array_property& axis_lims);
     Matrix get_ticklabel_extents (const Matrix& ticks,
                                   const string_vector& ticklabels,
                                   const Matrix& limits);
@@ -4232,7 +4263,9 @@
       calc_ticks_and_lims (xlim, xtick, xminortickvalues, xlimmode.is ("auto"),
                            xtickmode.is ("auto"), xscale.is ("log"));
       if (xticklabelmode.is ("auto"))
-        calc_ticklabels (xtick, xticklabel, xscale.is ("log"));
+        calc_ticklabels (xtick, xticklabel, xscale.is ("log"), xaxislocation.is ("origin"),
+                   yaxislocation_is ("origin") ? 0 : (yaxislocation_is ("left") ? -1 : 1),
+                   xlim);
 
       fix_limits (xlim);
 
@@ -4246,7 +4279,9 @@
       calc_ticks_and_lims (ylim, ytick, yminortickvalues, ylimmode.is ("auto"),
                            ytickmode.is ("auto"), yscale.is ("log"));
       if (yticklabelmode.is ("auto"))
-        calc_ticklabels (ytick, yticklabel, yscale.is ("log"));
+        calc_ticklabels (ytick, yticklabel, yscale.is ("log"), yaxislocation_is ("origin"),
+                   xaxislocation_is ("origin") ? 0 : (xaxislocation_is ("bottom") ? -1 : 1),
+                   ylim);
 
       fix_limits (ylim);
 
@@ -4260,7 +4295,7 @@
       calc_ticks_and_lims (zlim, ztick, zminortickvalues, zlimmode.is ("auto"),
                            ztickmode.is ("auto"), zscale.is ("log"));
       if (zticklabelmode.is ("auto"))
-        calc_ticklabels (ztick, zticklabel, zscale.is ("log"));
+        calc_ticklabels (ztick, zticklabel, zscale.is ("log"), false, 2, zlim);
 
       fix_limits (zlim);
 
