From: Joe Neeman Date: Fri, 4 May 2007 12:21:17 +0000 (+1000) Subject: simplify and optimize pure-height calculations X-Git-Tag: release/2.11.24-1~8^2~9 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=21930f09f54ab2f1b0dc26b0342caa92c8440e6f;p=lilypond.git simplify and optimize pure-height calculations --- diff --git a/lily/axis-group-interface.cc b/lily/axis-group-interface.cc index b62465322e..da08f53526 100644 --- a/lily/axis-group-interface.cc +++ b/lily/axis-group-interface.cc @@ -82,63 +82,89 @@ Axis_group_interface::relative_group_extent (vector const &elts, */ Interval -Axis_group_interface::cached_pure_height (Grob *me, - vector 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 breaks = ps->get_break_indices (); vector 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 breaks = ps->get_break_indices (); + vector 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 (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 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 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 rank_span = elts[i]->spanned_rank_interval (); - Item *it = dynamic_cast (elts[i]); - if (rank_span[LEFT] <= end && rank_span[RIGHT] >= start && (!it || it->pure_is_visible (start, end))) + Item *it = dynamic_cast (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 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 relevant_elts; + vector relevant_items; + vector 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 (elts[i])) + relevant_items.push_back (elts[i]); + else if (dynamic_cast (elts[i])) + relevant_spanners.push_back (elts[i]); + } + Item *it = dynamic_cast (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 " ); diff --git a/lily/hara-kiri-group-spanner.cc b/lily/hara-kiri-group-spanner.cc index d554bce215..bf07c8ede1 100644 --- a/lily/hara-kiri-group-spanner.cc +++ b/lily/hara-kiri-group-spanner.cc @@ -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 diff --git a/lily/include/axis-group-interface.hh b/lily/include/axis-group-interface.hh index de6cd01ad7..c9b1a58eb0 100644 --- a/lily/include/axis-group-interface.hh +++ b/lily/include/axis-group-interface.hh @@ -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 const &list, Grob *common, Axis); - static Interval relative_pure_height (Grob *me, vector const &list, - Grob *common, int start, int end, - bool use_cache); - static Interval cached_pure_height (Grob *me, vector 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 elements); diff --git a/lily/include/grob.hh b/lily/include/grob.hh index 433ea7ec43..82591eb7c3 100644 --- a/lily/include/grob.hh +++ b/lily/include/grob.hh @@ -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 */ diff --git a/lily/include/item.hh b/lily/include/item.hh index 0838c00a49..ea0af2eb53 100644 --- a/lily/include/item.hh +++ b/lily/include/item.hh @@ -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 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 spanned_time_interval (Item *l, Item *r); diff --git a/lily/include/spanner.hh b/lily/include/spanner.hh index 29905617a8..f0c82bb963 100644 --- a/lily/include/spanner.hh +++ b/lily/include/spanner.hh @@ -65,7 +65,6 @@ public: DECLARE_GROB_INTERFACE(); virtual System *get_system () const; - protected: void set_my_columns (); virtual Grob *clone () const; diff --git a/lily/item.cc b/lily/item.cc index 33e5e2027e..fdf9b00ce9 100644 --- a/lily/item.cc +++ b/lily/item.cc @@ -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 (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 (g1)->get_column ()->get_rank () < dynamic_cast (g2)->get_column ()->get_rank (); +} + ADD_INTERFACE (Item, "Grobs can be distinguished in their role in the horizontal spacing.\n" diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm index 34a87a20cf..014481c0ca 100644 --- a/scm/define-grob-properties.scm +++ b/scm/define-grob-properties.scm @@ -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? "") diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index 5ae742fc8b..35fc4ec0a5 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -2084,6 +2084,7 @@ (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