diff src/graphics.cc @ 10402:9f2bf537a651

Implement text extent property
author Michael Goffioul <michael.goffioul@gmail.com>
date Sun, 07 Mar 2010 21:00:07 +0000
parents 57a59eae83cc
children 660c244d3206
line wrap: on
line diff
--- a/src/graphics.cc	Fri Mar 05 14:38:32 2010 -0800
+++ b/src/graphics.cc	Sun Mar 07 21:00:07 2010 +0000
@@ -50,10 +50,13 @@
 #include "ov-fcn-handle.h"
 #include "parse.h"
 #include "toplev.h"
+#include "txt-eng-ft.h"
 #include "unwind-prot.h"
 
-// forward declaration
+// forward declarations
 static octave_value xget (const graphics_handle& h, const caseless_str& name);
+static graphics_object xget_ancestor (const graphics_object& go_arg,
+                                      const std::string& type);
 
 static void
 gripe_set_invalid (const std::string& pname)
@@ -311,8 +314,9 @@
                   const caseless_str& to_units,
                   const Matrix& parent_dim = Matrix (1, 2, 0.0))
 {
-  Matrix retval (1, 4);
+  Matrix retval (1, pos.numel ());
   double res = 0;
+  bool is_rectangle = (pos.numel () == 4);
 
   if (from_units.compare ("pixels"))
     retval = pos;
@@ -320,8 +324,13 @@
     {
       retval(0) = pos(0) * parent_dim(0) + 1;
       retval(1) = pos(1) * parent_dim(1) + 1;
-      retval(2) = pos(2) * parent_dim(0);
-      retval(3) = pos(3) * parent_dim(1);
+      if (is_rectangle)
+        {
+          retval(2) = pos(2) * parent_dim(0);
+          retval(3) = pos(3) * parent_dim(1);
+        }
+      else
+        retval(2) = 0;
     }
   else if (from_units.compare ("characters"))
     {
@@ -338,8 +347,13 @@
         {
           retval(0) = 0.5 * pos(0) * f;
           retval(1) = pos(1) * f;
-          retval(2) = 0.5 * pos(2) * f;
-          retval(3) = pos(3) * f;
+          if (is_rectangle)
+            {
+              retval(2) = 0.5 * pos(2) * f;
+              retval(3) = pos(3) * f;
+            }
+          else
+            retval(2) = 0;
         }
     }
   else
@@ -360,8 +374,13 @@
         {
           retval(0) = pos(0) * f + 1;
           retval(1) = pos(1) * f + 1;
-          retval(2) = pos(2) * f;
-          retval(3) = pos(3) * f;
+          if (is_rectangle)
+            {
+              retval(2) = pos(2) * f;
+              retval(3) = pos(3) * f;
+            }
+          else
+            retval(2) = 0;
         }
     }
 
@@ -371,8 +390,13 @@
         {
           retval(0) = (retval(0) - 1) / parent_dim(0);
           retval(1) = (retval(1) - 1) / parent_dim(1);
-          retval(2) /= parent_dim(0);
-          retval(3) /= parent_dim(1);
+          if (is_rectangle)
+            {
+              retval(2) /= parent_dim(0);
+              retval(3) /= parent_dim(1);
+            }
+          else
+            retval(2) = 0;
         }
       else if (to_units.compare ("characters"))
         {
@@ -387,8 +411,13 @@
             {
               retval(0) = 2 * retval(0) / f;
               retval(1) = retval(1) / f;
-              retval(2) = 2 * retval(2) / f;
-              retval(3) = retval(3) / f;
+              if (is_rectangle)
+                {
+                  retval(2) = 2 * retval(2) / f;
+                  retval(3) = retval(3) / f;
+                }
+              else
+                retval(2) = 0;
             }
         }
       else
@@ -409,11 +438,96 @@
             {
               retval(0) = (retval(0) - 1) / f;
               retval(1) = (retval(1) - 1) / f;
-              retval(2) /= f;
-              retval(3) /= f;
+              if (is_rectangle)
+                {
+                  retval(2) /= f;
+                  retval(3) /= f;
+                }
+              else
+                retval(2) = 0;
             }
         }
     }
+  else if (! is_rectangle)
+    retval(2) = 0;
+
+  return retval;
+}
+
+static Matrix
+convert_text_position (const Matrix& pos, const text::properties& props,
+                       const caseless_str& from_units,
+                       const caseless_str& to_units)
+{
+  graphics_object go = gh_manager::get_object (props.get___myhandle__ ());
+  graphics_object ax = xget_ancestor (go, "axes");
+
+  Matrix retval (1, pos.numel (), 0);
+
+  if (ax.valid_object ())
+    {
+      const axes::properties& ax_props =
+          dynamic_cast<const axes::properties&> (ax.get_properties ());
+      graphics_xform ax_xform = ax_props.get_transform ();
+      bool is_rectangle = (pos.numel () == 4);
+      Matrix ax_bbox = ax_props.get_boundingbox (true),
+             ax_size = ax_bbox.extract_n (0, 2, 1, 2);
+
+      if (from_units.compare ("data"))
+        {
+          if (is_rectangle)
+            {
+              ColumnVector v1 = ax_xform.transform (pos(0), pos(1), 0),
+                           v2 = ax_xform.transform (pos(0) + pos(2),
+                                                    pos(1) + pos(3), 0);
+
+              retval(0) = v1(0) - ax_bbox(0) + 1;
+              retval(1) = ax_bbox(1) + ax_bbox(3) - v1(1) + 1;
+              retval(2) = v2(0) - v1(0);
+              retval(3) = v1(1) - v2(1);
+            }
+          else
+            {
+              ColumnVector v = ax_xform.transform (pos(0), pos(1), pos(2));
+
+              retval(0) = v(0) - ax_bbox(0) + 1;
+              retval(1) = ax_bbox(1) + ax_bbox(3) - v(1) + 1;
+              retval(2) = 0;
+            }
+        }
+      else
+        retval = convert_position (pos, from_units, "pixels", ax_size);
+
+      if (! to_units.compare ("pixels"))
+        {
+          if (to_units.compare ("data"))
+            {
+              if (is_rectangle)
+                {
+                  ColumnVector v1 = ax_xform.untransform (retval(0) + ax_bbox(0) - 1,
+                                                          ax_bbox(1) + ax_bbox(3)  - retval(1) + 1),
+                               v2 = ax_xform.untransform (retval(0) + retval(2) + ax_bbox(0) - 1,
+                                                          ax_bbox(1) + ax_bbox(3)  - (retval(1) + retval(3)) + 1);
+
+                  retval(0) = v1(0);
+                  retval(1) = v1(1);
+                  retval(2) = v2(0) - v1(0);
+                  retval(3) = v2(1) - v1(1);
+                }
+              else
+                {
+                  ColumnVector v = ax_xform.untransform (retval(0) + ax_bbox(0) - 1,
+                                                         ax_bbox(1) + ax_bbox(3)  - retval(1) + 1);
+
+                  retval(0) = v(0);
+                  retval(1) = v(1);
+                  retval(2) = v(2);
+                }
+            }
+          else
+            retval = convert_position (retval, "pixels", to_units, ax_size);
+        }
+    }
 
   return retval;
 }
@@ -3378,6 +3492,7 @@
 
   pos = convert_position (pos, get_units (), "pixels",
                           parent_bb.extract_n (0, 2, 1, 2));
+
   pos(0)--;
   pos(1)--;
   pos(1) = parent_bb(3) - pos(1) - pos(3);
@@ -4099,7 +4214,81 @@
 
 // ---------------------------------------------------------------------
 
-// Note: "text" code is entirely auto-generated
+Matrix
+text::properties::get_data_position (void) const
+{
+  Matrix pos = get_position ().matrix_value ();
+
+  if (! units_is ("data"))
+    pos = convert_text_position (pos, *this, get_units (), "data");
+
+  return pos;
+}
+
+octave_value
+text::properties::get_extent (void) const
+{
+  Matrix m = extent.get ().matrix_value ();
+
+  return convert_text_position (m, *this, "pixels", get_units ());
+}
+
+void
+text::properties::update_text_extent (void)
+{
+#ifdef HAVE_FREETYPE
+
+  text_element *elt;
+  ft_render text_renderer;
+  Matrix box;
+
+  // FIXME: parsed content should be cached for efficiency
+  
+  elt = text_parser_none ().parse (get_string ());
+  text_renderer.set_font (*this);
+  box = text_renderer.get_extent (elt, get_rotation ());
+
+  Matrix extent (1, 4, 0.0);
+
+  // FIXME: also handle left and bottom components
+
+  extent(0) = extent(1) = 1;
+  extent(2) = box(0);
+  extent(3) = box(1);
+
+  set_extent (extent);
+
+#endif
+}
+
+void
+text::properties::update_units (void)
+{
+  if (! units_is ("data"))
+    {
+      set_xliminclude ("off");
+      set_yliminclude ("off");
+      set_zliminclude ("off");
+    }
+
+  Matrix pos = get_position ().matrix_value ();
+
+  pos = convert_text_position (pos, *this, cached_units, get_units ());
+  // FIXME: if the current axes view is 2D, then one should
+  // probably drop the z-component of "pos" and leave "zliminclude"
+  // to "off".
+  set_position (pos);
+
+  if (units_is ("data"))
+    {
+      set_xliminclude ("on");
+      set_yliminclude ("on");
+      // FIXME: see above
+      set_zliminclude ("off");
+    }
+
+  cached_units = get_units ();
+}
 
 // ---------------------------------------------------------------------