diff src/graphics.cc @ 12334:63dc132a1000

Move axes labels and title positioning to axes::properties
author Konstantinos Poulios <logari81@gmail.com>
date Thu, 03 Feb 2011 19:30:13 +0100
parents 2ad37783bf01
children f6763ab98609
line wrap: on
line diff
--- a/src/graphics.cc	Thu Feb 03 12:47:05 2011 +0100
+++ b/src/graphics.cc	Thu Feb 03 19:30:13 2011 +0100
@@ -3301,6 +3301,7 @@
   xset (xlabel.handle_value (), "verticalalignmentmode", "auto");
   xset (xlabel.handle_value (), "clipping", "off");
   xset (xlabel.handle_value (), "color", get_xcolor ());
+  update_xlabel_position ();
 }
 
 void
@@ -3313,6 +3314,7 @@
   xset (ylabel.handle_value (), "verticalalignmentmode", "auto");
   xset (ylabel.handle_value (), "clipping", "off");
   xset (ylabel.handle_value (), "color", get_ycolor ());
+  update_ylabel_position ();
 }
 
 void
@@ -3325,6 +3327,7 @@
   xset (zlabel.handle_value (), "verticalalignmentmode", "auto");
   xset (zlabel.handle_value (), "clipping", "off");
   xset (zlabel.handle_value (), "color", get_zcolor ());
+  update_zlabel_position ();
 }
 
 void
@@ -3337,6 +3340,7 @@
   xset (title.handle_value (), "verticalalignment", "bottom");
   xset (title.handle_value (), "verticalalignmentmode", "auto");
   xset (title.handle_value (), "clipping", "off");
+  update_title_position ();
 }
 
 void
@@ -4063,6 +4067,305 @@
   xtickoffset = (mode2d ? std::max (0., xticklen) : std::abs (xticklen)) + 5;
   ytickoffset = (mode2d ? std::max (0., yticklen) : std::abs (yticklen)) + 5;
   ztickoffset = (mode2d ? std::max (0., zticklen) : std::abs (zticklen)) + 5;
+
+  update_xlabel_position ();
+  update_ylabel_position ();
+  update_zlabel_position ();
+  update_title_position ();
+}
+
+void
+axes::properties::update_xlabel_position (void)
+{
+  graphics_xform xform = get_transform ();
+
+  text::properties& xlabel_props = reinterpret_cast<text::properties&>
+    (gh_manager::get_object (get_xlabel ()).get_properties ());
+
+  if (xlabel_props.horizontalalignmentmode_is ("auto"))
+    {
+      xlabel_props.set_horizontalalignment
+        (xstate > AXE_DEPTH_DIR
+         ? "center" : (xyzSym ? "left" : "right"));
+
+      xlabel_props.set_horizontalalignmentmode ("auto");
+    }
+
+  if (xlabel_props.verticalalignmentmode_is ("auto"))
+    {
+      xlabel_props.set_verticalalignment
+        (xstate == AXE_VERT_DIR || x2Dtop ? "bottom" : "top");
+
+      xlabel_props.set_verticalalignmentmode ("auto");
+    }
+
+  if (xlabel_props.positionmode_is ("auto")
+      || xlabel_props.rotationmode_is ("auto"))
+    {
+      Matrix ext (1, 2, 0.0);
+      ext = get_ticklabel_extents (get_xtick ().matrix_value (),
+                                   get_xticklabel ().all_strings (),
+                                   get_xlim ().matrix_value ());
+
+      double wmax = ext(0), hmax = ext(1), angle = 0;
+      ColumnVector p =
+        graphics_xform::xform_vector ((xpTickN+xpTick)/2, ypTick, zpTick);
+
+      bool tick_along_z = nearhoriz || xisinf (fy);
+      if (tick_along_z)
+        p(2) += (signum(zpTick-zpTickN)*fz*xtickoffset);
+      else
+        p(1) += (signum(ypTick-ypTickN)*fy*xtickoffset);
+
+      p = xform.transform (p(0), p(1), p(2), false);
+
+      switch (xstate)
+        {
+          case AXE_ANY_DIR:
+            p(0) += (xyzSym ? wmax : -wmax);
+            p(1) += hmax;
+            break;
+
+          case AXE_VERT_DIR:
+            p(0) -= wmax;
+            angle = 90;
+            break;
+
+          case AXE_HORZ_DIR:
+            p(1) += (x2Dtop ? -hmax : hmax);
+            break;
+        }
+
+      if (xlabel_props.positionmode_is ("auto"))
+        {
+          p = xform.untransform (p(0), p(1), p(2), true);
+          xlabel_props.set_position (p.extract_n (0, 3).transpose ());
+          xlabel_props.set_positionmode ("auto");
+        }
+
+      if (xlabel_props.rotationmode_is ("auto"))
+        {
+          xlabel_props.set_rotation (angle);
+          xlabel_props.set_rotationmode ("auto");
+        }
+    }
+}
+
+void
+axes::properties::update_ylabel_position (void)
+{
+  graphics_xform xform = get_transform ();
+
+  text::properties& ylabel_props = reinterpret_cast<text::properties&>
+    (gh_manager::get_object (get_ylabel ()).get_properties ());
+
+  if (ylabel_props.horizontalalignmentmode_is ("auto"))
+	{
+	  ylabel_props.set_horizontalalignment
+		(ystate > AXE_DEPTH_DIR
+		 ? "center" : (!xyzSym ? "left" : "right"));
+
+	  ylabel_props.set_horizontalalignmentmode ("auto");
+	}
+
+  if (ylabel_props.verticalalignmentmode_is ("auto"))
+	{
+	  ylabel_props.set_verticalalignment
+		(ystate == AXE_VERT_DIR && !y2Dright ? "bottom" : "top");
+
+	  ylabel_props.set_verticalalignmentmode ("auto");
+	}
+
+  if (ylabel_props.positionmode_is ("auto")
+	  || ylabel_props.rotationmode_is ("auto"))
+	{
+      Matrix ext (1, 2, 0.0);
+      ext = get_ticklabel_extents (get_ytick ().matrix_value (),
+                                   get_yticklabel ().all_strings (),
+                                   get_ylim ().matrix_value ());
+
+      double wmax = ext(0), hmax = ext(1), angle = 0;
+	  ColumnVector p =
+	    graphics_xform::xform_vector (xpTick, (ypTickN+ypTick)/2, zpTick);
+
+      bool tick_along_z = nearhoriz || xisinf (fx);
+	  if (tick_along_z)
+		p(2) += (signum(zpTick-zpTickN)*fz*ytickoffset);
+	  else
+		p(0) += (signum(xpTick-xpTickN)*fx*ytickoffset);
+
+	  p = xform.transform (p(0), p(1), p(2), false);
+
+	  switch (ystate)
+		{
+		  case AXE_ANY_DIR:
+			p(0) += (!xyzSym ? wmax : -wmax);
+			p(1) += hmax;
+			break;
+
+		  case AXE_VERT_DIR:
+			p(0) += (y2Dright ? wmax : -wmax);
+			angle = 90;
+			break;
+
+		  case AXE_HORZ_DIR:
+			p(1) += hmax;
+			break;
+		}
+
+	  if (ylabel_props.positionmode_is ("auto"))
+		{
+		  p = xform.untransform (p(0), p(1), p(2), true);
+		  ylabel_props.set_position (p.extract_n (0, 3).transpose ());
+		  ylabel_props.set_positionmode ("auto");
+		}
+
+	  if (ylabel_props.rotationmode_is ("auto"))
+		{
+		  ylabel_props.set_rotation (angle);
+		  ylabel_props.set_rotationmode ("auto");
+		}
+	}
+}
+
+void
+axes::properties::update_zlabel_position (void)
+{
+  graphics_xform xform = get_transform ();
+
+  text::properties& zlabel_props = reinterpret_cast<text::properties&>
+    (gh_manager::get_object (get_zlabel ()).get_properties ());
+
+  bool camAuto = cameraupvectormode_is ("auto");
+
+  if (zlabel_props.horizontalalignmentmode_is ("auto"))
+	{
+	  zlabel_props.set_horizontalalignment
+		((zstate > AXE_DEPTH_DIR || camAuto) ? "center" : "right");
+
+	  zlabel_props.set_horizontalalignmentmode ("auto");
+	}
+
+  if (zlabel_props.verticalalignmentmode_is ("auto"))
+	{
+	  zlabel_props.set_verticalalignment
+		(zstate == AXE_VERT_DIR
+		 ? "bottom" : ((zSign || camAuto) ? "bottom" : "top"));
+
+	  zlabel_props.set_verticalalignmentmode ("auto");
+	}
+
+  if (zlabel_props.positionmode_is ("auto")
+	  || zlabel_props.rotationmode_is ("auto"))
+	{
+      Matrix ext (1, 2, 0.0);
+      ext = get_ticklabel_extents (get_ztick ().matrix_value (),
+                                   get_zticklabel ().all_strings (),
+                                   get_zlim ().matrix_value ());
+
+      double wmax = ext(0), hmax = ext(1), angle = 0;
+	  ColumnVector p;
+
+	  if (xySym)
+		{
+		  p = graphics_xform::xform_vector (xPlaneN, yPlane,
+											(zpTickN+zpTick)/2);
+		  if (xisinf (fy))
+			p(0) += (signum(xPlaneN-xPlane)*fx*ztickoffset);
+		  else
+			p(1) += (signum(yPlane-yPlaneN)*fy*ztickoffset);
+		}
+	  else
+		{
+		  p = graphics_xform::xform_vector (xPlane, yPlaneN,
+											(zpTickN+zpTick)/2);
+		  if (xisinf (fx))
+			p(1) += (signum(yPlaneN-yPlane)*fy*ztickoffset);
+		  else
+			p(0) += (signum(xPlane-xPlaneN)*fx*ztickoffset);
+		}
+
+	  p = xform.transform (p(0), p(1), p(2), false);
+
+	  switch (zstate)
+		{
+		  case AXE_ANY_DIR:
+			if (camAuto)
+			  {
+				p(0) -= wmax;
+				angle = 90;
+			  }
+
+			// FIXME -- what's the correct offset?
+			//
+			//   p[0] += (!xySym ? wmax : -wmax);
+			//   p[1] += (zSign ? hmax : -hmax);
+
+			break;
+
+		  case AXE_VERT_DIR:
+			p(0) -= wmax;
+			angle = 90;
+			break;
+
+		  case AXE_HORZ_DIR:
+			p(1) += hmax;
+			break;
+		}
+
+	  if (zlabel_props.positionmode_is ("auto"))
+		{
+		  p = xform.untransform (p(0), p(1), p(2), true);
+		  zlabel_props.set_position (p.extract_n (0, 3).transpose ());
+		  zlabel_props.set_positionmode ("auto");
+		}
+
+	  if (zlabel_props.rotationmode_is ("auto"))
+		{
+		  zlabel_props.set_rotation (angle);
+		  zlabel_props.set_rotationmode ("auto");
+		}
+	}
+}
+
+void
+axes::properties::update_title_position (void)
+{
+  graphics_xform xform = get_transform ();
+
+  text::properties& title_props = reinterpret_cast<text::properties&>
+    (gh_manager::get_object (get_title ()).get_properties ());
+
+  if (title_props.positionmode_is ("auto"))
+    {
+	  // FIXME: bbox should be stored in axes::properties
+	  ColumnVector bbox(4);
+	  bbox(0) = octave_Inf;
+	  bbox(1) = octave_Inf;
+	  bbox(2) = -octave_Inf;
+	  bbox(3) = -octave_Inf;
+	  for (int i = 0; i <= 1; i++)
+	    for (int j = 0; j <= 1; j++)
+	      for (int k = 0; k <= 1; k++)
+	        {
+	          ColumnVector p = xform.transform (i ? xPlaneN : xPlane,
+	                                            j ? yPlaneN : yPlane,
+	                                            k ? zPlaneN : zPlane, false);
+	          bbox(0) = std::min (bbox(0), p(0));
+	          bbox(1) = std::min (bbox(1), p(1));
+	          bbox(2) = std::max (bbox(2), p(0));
+	          bbox(3) = std::max (bbox(3), p(1));
+	        }
+	
+	  bbox(2) = bbox(2)-bbox(0);
+	  bbox(3) = bbox(3)-bbox(1);
+
+      ColumnVector p = xform.untransform (bbox(0)+bbox(2)/2, (bbox(1)-10),
+                                          (x_zlim(0)+x_zlim(1))/2, true);
+
+      title_props.set_position (p.extract_n(0, 3).transpose ());
+      title_props.set_positionmode ("auto");
+    }
 }
 
 static void
@@ -4637,6 +4940,48 @@
   labels = c;
 }
 
+Matrix
+axes::properties::get_ticklabel_extents (const Matrix& ticks,
+                                         const string_vector& ticklabels,
+                                         const Matrix& limits)
+{
+#ifdef HAVE_FREETYPE
+  //FIXME: text_renderer could be cached
+  ft_render text_renderer;
+  text_renderer.set_font (get ("fontname").string_value (),
+                          get ("fontweight").string_value (),
+                          get ("fontangle").string_value (),
+                          get ("fontsize").double_value ());
+#else
+  double fontsize = get ("fontsize").double_value ();
+#endif
+
+  Matrix ext (1, 2, 0.0);
+  double wmax = 0., hmax = 0.;
+  int n = std::min (ticklabels.numel (), ticks.numel ());
+  for (int i = 0; i < n; i++)
+    {
+      double val = ticks(i);
+      if (limits(0) <= val && val <= limits(1))
+        {
+#ifdef HAVE_FREETYPE
+          ext = text_renderer.get_extent (ticklabels(i));
+          wmax = std::max (wmax, ext(0));
+          hmax = std::max (hmax, ext(1));
+#else
+          //FIXME: find a better approximation
+          int len = ticklabels(i).length();
+          wmax = std::max (wmax, 0.5*fontsize*len);
+          hmax = fontsize;
+#endif
+        }
+    }
+
+  ext(0) = wmax;
+  ext(1) = hmax;
+  return ext;
+}
+
 void
 get_children_limits (double& min_val, double& max_val, double& min_pos,
                      const Matrix& kids, char limit_type)