]> git.donarmstrong.com Git - lilypond.git/commitdiff
simplify and optimize pure-height calculations
authorJoe Neeman <joeneeman@gmail.com>
Fri, 4 May 2007 12:21:17 +0000 (22:21 +1000)
committerJoe Neeman <joeneeman@gmail.com>
Fri, 4 May 2007 12:21:17 +0000 (22:21 +1000)
lily/axis-group-interface.cc
lily/hara-kiri-group-spanner.cc
lily/include/axis-group-interface.hh
lily/include/grob.hh
lily/include/item.hh
lily/include/spanner.hh
lily/item.cc
scm/define-grob-properties.scm
scm/define-grobs.scm

index b62465322eb8044081bd5801b560c3b60ef21ea5..da08f53526eb4f1fa333df1126cd3ccdb77478c1 100644 (file)
@@ -82,63 +82,89 @@ Axis_group_interface::relative_group_extent (vector<Grob*> const &elts,
 */
 
 Interval
-Axis_group_interface::cached_pure_height (Grob *me,
-                                         vector<Grob*> const &elts,
-                                         Grob *common,
-                                         int start, int end)
+Axis_group_interface::cached_pure_height (Grob *me, int start, int end)
 {
   Paper_score *ps = get_root_system (me)->paper_score ();
   vector<vsize> breaks = ps->get_break_indices ();
   vector<Grob*> cols = ps->get_columns ();
-  vsize start_index = VPOS;
-  vsize end_index = VPOS;
 
-  for (vsize i = 0; i < breaks.size (); i++)
+  SCM extents = me->get_property ("adjacent-pure-heights");
+
+  Interval ext;
+  for (vsize i = 0; i + 1 < breaks.size (); i++)
     {
       int r = Paper_column::get_rank (cols[breaks[i]]);
-      if (start == r)
-       start_index = i;
-      if (end == r)
-       end_index = i;
-    }
-  if (end == INT_MAX)
-    end_index = breaks.size () - 1;
+      if (r > end)
+       break;
 
-  if (start_index == VPOS || end_index == VPOS)
-    {
-      programming_error (_ ("tried to calculate pure-height at a non-breakpoint"));
-      return Interval (0, 0);
+      if (r >= start)
+       ext.unite (ly_scm2interval (scm_c_vector_ref (extents, i)));
     }
 
-  SCM extents = me->get_property ("cached-pure-extents");
-  if (!scm_is_vector (extents))
+  return ext;
+}
+
+MAKE_SCHEME_CALLBACK (Axis_group_interface, adjacent_pure_heights, 1)
+SCM
+Axis_group_interface::adjacent_pure_heights (SCM smob)
+{
+  Grob *me = unsmob_grob (smob);
+
+  Grob *common = calc_pure_elts_and_common (me);
+  extract_grob_set (me, "pure-relevant-items", items);
+  extract_grob_set (me, "pure-relevant-spanners", spanners);
+
+  Paper_score *ps = get_root_system (me)->paper_score ();
+  vector<vsize> breaks = ps->get_break_indices ();
+  vector<Grob*> cols = ps->get_columns ();
+
+  SCM ret = scm_c_make_vector (breaks.size () - 1, SCM_EOL);
+  vsize it_index = 0;
+  for (vsize i = 0; i + 1 < breaks.size (); i++)
     {
-      extents = scm_c_make_vector (breaks.size () - 1, SCM_EOL);
-      for (vsize i = 0; i + 1 < breaks.size (); i++)
+      int start = Paper_column::get_rank (cols[breaks[i]]);
+      int end = Paper_column::get_rank (cols[breaks[i+1]]);
+      Interval iv;
+
+      for (vsize j = it_index; j < items.size (); j++)
        {
-         int st = Paper_column::get_rank (cols[breaks[i]]);
-         int ed = Paper_column::get_rank (cols[breaks[i+1]]);
-         Interval iv = relative_pure_height (me, elts, common, st, ed, false);
-         scm_vector_set_x (extents, scm_from_int (i), ly_interval2scm (iv));
+         Item *it = dynamic_cast<Item*> (items[j]);
+         int rank = it->get_column ()->get_rank ();
+
+         if (rank <= end && it->pure_is_visible (start, end))
+           {
+             Interval dims = items[j]->pure_height (common, start, end);
+             if (!dims.is_empty ())
+               iv.unite (dims);
+           }
+
+         if (rank < end)
+           it_index++;
+         else if (rank > end)
+           break;
        }
-      me->set_property ("cached-pure-extents", extents);
-    }
 
-  Interval ext (0, 0);
-  for (vsize i = start_index; i < end_index; i++)
-    ext.unite (ly_scm2interval (scm_c_vector_ref (extents, i)));
-  return ext;
+      for (vsize j = 0; j < spanners.size (); j++)
+       {
+         Interval_t<int> rank_span = spanners[j]->spanned_rank_interval ();
+         if (rank_span[LEFT] <= end && rank_span[RIGHT] >= start)
+           {
+             Interval dims = spanners[j]->pure_height (common, start, end);
+             if (!dims.is_empty ())
+               iv.unite (dims);
+           }
+       }
+
+      scm_vector_set_x (ret, scm_from_int (i), ly_interval2scm (iv));
+    }
+  return ret;
 }
 
 Interval
-Axis_group_interface::relative_pure_height (Grob *me,
-                                           vector<Grob*> const &elts,
-                                           Grob *common,
-                                           int start, int end,
-                                           bool use_cache)
+Axis_group_interface::relative_pure_height (Grob *me, int start, int end)
 {
   /* It saves a _lot_ of time if we assume a VerticalAxisGroup is additive
-     (ie. height (i, k) = height (i, j) + height (j, k) for all i <= j <= k).
+     (ie. height (i, k) = max (height (i, j) height (j, k)) for all i <= j <= k).
      Unfortunately, it isn't always true, particularly if there is a
      VerticalAlignment somewhere in the descendants.
 
@@ -147,18 +173,36 @@ Axis_group_interface::relative_pure_height (Grob *me,
      reasonably safe to assume that if our parent is a VerticalAlignment,
      we can assume additivity and cache things nicely. */
   Grob *p = me->get_parent (Y_AXIS);
-  if (use_cache && p && Align_interface::has_interface (p))
-    return Axis_group_interface::cached_pure_height (me, elts, common, start, end);
+  if (p && Align_interface::has_interface (p))
+    return Axis_group_interface::cached_pure_height (me, start, end);
+
+  Grob *common = calc_pure_elts_and_common (me);
+  extract_grob_set (me, "pure-relevant-items", items);
+  extract_grob_set (me, "pure-relevant-spanners", spanners);
 
   Interval r;
 
-  for (vsize i = 0; i < elts.size (); i++)
+  for (vsize i = 0; i < items.size (); i++)
     {
-      Interval_t<int> rank_span = elts[i]->spanned_rank_interval ();
-      Item *it = dynamic_cast<Item*> (elts[i]);
-      if (rank_span[LEFT] <= end && rank_span[RIGHT] >= start && (!it || it->pure_is_visible (start, end)))
+      Item *it = dynamic_cast<Item*> (items[i]);
+      int rank = it->get_column ()->get_rank ();
+
+      if (rank > end)
+       break;
+      else if (rank >= start && it->pure_is_visible (start, end))
+       {
+         Interval dims = it->pure_height (common, start, end);
+         if (!dims.is_empty ())
+           r.unite (dims);
+       }
+    }
+
+  for (vsize i = 0; i < spanners.size (); i++)
+    {
+      Interval_t<int> rank_span = spanners[i]->spanned_rank_interval ();
+      if (rank_span[LEFT] <= end && rank_span[RIGHT] >= start)
        {
-         Interval dims = elts[i]->pure_height (common, start, end);
+         Interval dims = spanners[i]->pure_height (common, start, end);
          if (!dims.is_empty ())
            r.unite (dims);
        }
@@ -201,7 +245,7 @@ Axis_group_interface::pure_height (SCM smob, SCM start_scm, SCM end_scm)
        return scm_cdr (system_y_extent);
     }
 
-  return pure_group_height (me, start, end);
+  return ly_interval2scm (pure_group_height (me, start, end));
 }
 
 MAKE_SCHEME_CALLBACK (Axis_group_interface, calc_skylines, 1);
@@ -278,13 +322,20 @@ Axis_group_interface::calc_pure_elts_and_common (Grob *me)
   
   extract_grob_set (me, "elements", elts);
 
-  vector<Grob*> relevant_elts;
+  vector<Grob*> relevant_items;
+  vector<Grob*> relevant_spanners;
   SCM pure_relevant_p = ly_lily_module_constant ("pure-relevant?");
 
   for (vsize i = 0; i < elts.size (); i++)
     {
       if (to_boolean (scm_apply_1 (pure_relevant_p, elts[i]->self_scm (), SCM_EOL)))
-       relevant_elts.push_back (elts[i]);
+       {
+         if (dynamic_cast<Item*> (elts[i]))
+           relevant_items.push_back (elts[i]);
+         else if (dynamic_cast<Spanner*> (elts[i]))
+           relevant_spanners.push_back (elts[i]);
+       }
+           
 
       Item *it = dynamic_cast<Item*> (elts[i]);
       Direction d = LEFT;
@@ -293,18 +344,24 @@ Axis_group_interface::calc_pure_elts_and_common (Grob *me)
          {
            Item *piece = it->find_prebroken_piece (d);
            if (piece && to_boolean (scm_apply_1 (pure_relevant_p, piece->self_scm (), SCM_EOL)))
-             relevant_elts.push_back (piece);
+             relevant_items.push_back (piece);
          }
        while (flip (&d) != LEFT);
     }
+  vector_sort (relevant_items, Item::less);
+
+  Grob *common = common_refpoint_of_array (relevant_items, me, Y_AXIS);
+  common = common_refpoint_of_array (relevant_spanners, common, Y_AXIS);
 
-  Grob *common = common_refpoint_of_array (relevant_elts, me, Y_AXIS);
   me->set_object ("pure-Y-common", common->self_scm ());
   
-  SCM ga_scm = Grob_array::make_array ();
-  Grob_array *ga = unsmob_grob_array (ga_scm);
-  ga->set_array (relevant_elts);
-  me->set_object ("pure-relevant-elements", ga_scm);
+  SCM items_scm = Grob_array::make_array ();
+  SCM spanners_scm = Grob_array::make_array ();
+
+  unsmob_grob_array (items_scm)->set_array (relevant_items);
+  unsmob_grob_array (spanners_scm)->set_array (relevant_spanners);
+  me->set_object ("pure-relevant-items", items_scm);
+  me->set_object ("pure-relevant-spanners", spanners_scm);
 
   return common;
 }
@@ -331,16 +388,15 @@ Axis_group_interface::calc_y_common (SCM grob)
   return common->self_scm ();
 }
 
-SCM
+Interval
 Axis_group_interface::pure_group_height (Grob *me, int start, int end)
 {
   Grob *common = calc_pure_elts_and_common (me);
        
-  extract_grob_set (me, "pure-relevant-elements", elts);
   Real my_coord = me->relative_coordinate (common, Y_AXIS);
-  Interval r (relative_pure_height (me, elts, common, start, end, true));
+  Interval r (relative_pure_height (me, start, end));
 
-  return ly_interval2scm (r - my_coord);
+  return r - my_coord;
 }
 
 void
@@ -559,12 +615,13 @@ ADD_INTERFACE (Axis_group_interface,
               /* properties */
               "X-common "
               "Y-common "
+              "adjacent-pure-heights "
               "axes "
               "elements "
               "keep-fixed-while-stretching "
               "max-stretch "
               "pure-Y-common "
-              "pure-relevant-elements "
+              "pure-relevant-items "
+              "pure-relevant-spanners "
               "vertical-skylines "
-              "cached-pure-extents "
               );
index d554bce21568bca63a4ec900d163d3a3f98ad8ff..bf07c8ede13ec532d58debd7a58cfd6168cc671c 100644 (file)
@@ -43,7 +43,8 @@ Hara_kiri_group_spanner::pure_height (SCM smob, SCM start_scm, SCM end_scm)
 
   if (request_suicide (me, start, end))
     return ly_interval2scm (Interval ());
-  return Axis_group_interface::pure_group_height (me, start, end);
+
+  return ly_interval2scm (Axis_group_interface::pure_group_height (me, start, end));
 }
 
 /* there is probably a way that doesn't involve re-implementing a binary
index de6cd01ad7608104b6ac2eabf1df2f8678b301d1..c9b1a58eb09f8b924bcfd57b41da165a1dc100d8 100644 (file)
@@ -17,7 +17,7 @@
 struct Axis_group_interface
 {
   static SCM generic_group_extent (Grob *me, Axis a);
-  static SCM pure_group_height (Grob *me, int start, int end);
+  static Interval pure_group_height (Grob *me, int start, int end);
   DECLARE_SCHEME_CALLBACK (width, (SCM smob));
   DECLARE_SCHEME_CALLBACK (calc_x_common, (SCM smob));
   DECLARE_SCHEME_CALLBACK (calc_y_common, (SCM smob));
@@ -27,13 +27,11 @@ struct Axis_group_interface
   DECLARE_SCHEME_CALLBACK (combine_skylines, (SCM smob));
   DECLARE_SCHEME_CALLBACK (calc_max_stretch, (SCM smob));
   DECLARE_SCHEME_CALLBACK (print, (SCM smob));
+  DECLARE_SCHEME_CALLBACK (adjacent_pure_heights, (SCM));
   static Interval relative_group_extent (vector<Grob*> const &list,
                                         Grob *common, Axis);
-  static Interval relative_pure_height (Grob *me, vector<Grob*> const &list,
-                                       Grob *common, int start, int end,
-                                       bool use_cache);
-  static Interval cached_pure_height (Grob *me, vector<Grob*> const &list,
-                                     Grob *common, int, int);
+  static Interval relative_pure_height (Grob *me, int start, int end);
+  static Interval cached_pure_height (Grob *me, int, int);
 
   static Grob *calc_pure_elts_and_common (Grob*);
   static Skyline_pair skyline_spacing (Grob *me, vector<Grob*> elements);
index 433ea7ec436a363bd3d40cab9ae70e8493b74c09..82591eb7c37240f75e0b98b1f0893e4490820805 100644 (file)
@@ -118,7 +118,7 @@ public:
   /* extents */
   Interval extent (Grob *refpoint, Axis) const;
   void flush_extent_cache (Axis);
-  Interval pure_height (Grob *refpoint, int start_col, int end_col);
+  virtual Interval pure_height (Grob *refpoint, int start_col, int end_col);
   Interval maybe_pure_extent (Grob *refpoint, Axis, bool pure, int start, int end);
 
   /* refpoints */
index 0838c00a49be7e85659245b3b1b392aa9f478729..ea0af2eb53de023dfc8c3a7b93f67d731d7dcbd7 100644 (file)
@@ -29,6 +29,7 @@ public:
 
   static bool is_non_musical (Grob *);
   static bool break_visible(Grob *);
+  static bool less (Grob * const&, Grob * const&);
   bool is_broken () const;
   bool pure_is_visible (int start, int end) const;
 
@@ -40,11 +41,15 @@ public:
   virtual Paper_column *get_column () const;
   virtual void handle_prebroken_dependencies ();
   virtual Interval_t<int> spanned_rank_interval () const;
+  virtual Interval pure_height (Grob *ref, int start, int end);
   DECLARE_GROB_INTERFACE();
 protected:
   virtual void discretionary_processing ();
   void copy_breakable_items ();
   virtual void derived_mark () const;
+
+  bool cached_pure_height_valid_;
+  Interval cached_pure_height_;
 };
 
 Interval_t<Moment> spanned_time_interval (Item *l, Item *r);
index 29905617a8d74e711f7e0de3fe0bf2cff8ae144b..f0c82bb963dc31107129688f8440e6d88798bbb8 100644 (file)
@@ -65,7 +65,6 @@ public:
   DECLARE_GROB_INTERFACE();
   virtual System *get_system () const;
 
-  
 protected:
   void set_my_columns ();
   virtual Grob *clone () const;
index 33e5e2027edf86e72395da4e590112b99741bca3..fdf9b00ce9d36c1498076dc221e6ab01f992be61 100644 (file)
@@ -29,6 +29,7 @@ Item::Item (SCM s)
   : Grob (s)
 {
   broken_to_drul_[LEFT] = broken_to_drul_[RIGHT] = 0;
+  cached_pure_height_valid_ = false;
 }
 
 /**
@@ -38,6 +39,7 @@ Item::Item (Item const &s)
   : Grob (s)
 {
   broken_to_drul_[LEFT] = broken_to_drul_[RIGHT] = 0;
+  cached_pure_height_valid_ = false;
 }
 
 bool
@@ -229,6 +231,23 @@ unsmob_item (SCM s)
   return dynamic_cast<Item *> (unsmob_grob (s));
 }
 
+Interval
+Item::pure_height (Grob *g, int start, int end)
+{
+  if (cached_pure_height_valid_)
+    return cached_pure_height_ + pure_relative_y_coordinate (g, start, end);
+
+  cached_pure_height_ = Grob::pure_height (this, start, end);
+  cached_pure_height_valid_ = true;
+  return cached_pure_height_ + pure_relative_y_coordinate (g, start, end);
+}
+
+bool
+Item::less (Grob * const &g1, Grob * const &g2)
+{
+  return dynamic_cast<Item*> (g1)->get_column ()->get_rank () < dynamic_cast<Item*> (g2)->get_column ()->get_rank ();
+}
+
 ADD_INTERFACE (Item,
 
               "Grobs can be distinguished in their role in the horizontal spacing.\n"
index 34a87a20cf46b8d0c45c0b94111da72e08149497..014481c0ca7ffd195b42b4851fa6e3d914cae1bc 100644 (file)
@@ -573,7 +573,7 @@ be constructed from a whole number of squiggles.")
      ;; grobs & grob arrays. (alphabetical)
      (X-common ,ly:grob? "Common refpoint for axis group.")
      (Y-common ,ly:grob? "See @code{X-common}.")
-     (cached-pure-extents ,vector? "Used by a VerticalAxisGroup to cache the Y-extents of different column ranges.")
+     (adjacent-pure-heights ,vector? "Used by a VerticalAxisGroup to cache the Y-extents of different column ranges.")
      (axis-group-parent-X ,ly:grob? "Containing X axis group")
      (axis-group-parent-Y ,ly:grob? "Containing Y axis group")
      (accidental-grobs ,list? "Alist with (NOTENAME . GROBLIST) entries")
@@ -604,7 +604,8 @@ columns.
      (pedal-text ,ly:grob? "Pointer to the text of a mixed-style piano pedal.")
      
      (pure-Y-common ,ly:grob? "Caches the common_refpoint_of_array of the elements grob-set")
-     (pure-relevant-elements ,ly:grob-array? "The subset of elements that are relevant for finding the pure-Y-extent.")
+     (pure-relevant-items ,ly:grob-array? "A subset of elements that are relevant for finding the pure-Y-extent.")
+     (pure-relevant-spanners ,ly:grob-array? "A subset of elements that are relevant for finding the pure-Y-extent.")
      (stem ,ly:grob? "pointer to Stem object.")
      (tremolo-flag ,ly:grob? "The tremolo object on a stem.")
      (tie ,ly:grob? "")
index 5ae742fc8b43b747f5007d4594fde0f2ba166597..35fc4ec0a5aca8a71d37b7094874cc24978b9509 100644 (file)
        (vertical-skylines . ,ly:hara-kiri-group-spanner::calc-skylines)
        (max-stretch . ,ly:axis-group-interface::calc-max-stretch)
        (stencil . ,ly:axis-group-interface::print)
+       (adjacent-pure-heights . ,ly:axis-group-interface::adjacent-pure-heights)
        (meta . ((class . Spanner)
                 (object-callbacks . ((X-common . ,ly:axis-group-interface::calc-x-common)))
                 (interfaces . (axis-group-interface