From: Joe Neeman Date: Thu, 14 May 2009 18:37:59 +0000 (-0700) Subject: Improve the accuracy of pure-heights for systems with many staves. X-Git-Tag: release/2.13.1-1~11^2~4^2~2 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=e4e0be528632168d8f769615cd75593554095c93;p=lilypond.git Improve the accuracy of pure-heights for systems with many staves. --- diff --git a/lily/align-interface.cc b/lily/align-interface.cc index 27839aca92..d69930c3aa 100644 --- a/lily/align-interface.cc +++ b/lily/align-interface.cc @@ -84,6 +84,8 @@ Align_interface::stretch_after_break (SCM grob) an empty extent, delete it from the list instead. If the extent is non-empty but there is no skyline available (or pure is true), just create a flat skyline from the bounding box */ +// TODO(jneem): the pure and non-pure parts seem to share very little +// code. Split them into 2 functions, perhaps? static void get_skylines (Grob *me, vector *const elements, @@ -137,9 +139,32 @@ get_skylines (Grob *me, { Box b; b[a] = extent; - b[other_axis (a)] = Interval (-infinity_f, infinity_f); + b[other_axis (a)] = Interval (0, infinity_f); skylines.insert (b, 0, other_axis (a)); } + + // This is a hack to get better accuracy on the pure-height of VerticalAlignment. + // It's quite common for a treble clef to be the highest element of one system + // and for a low note (or lyrics) to be the lowest note on another. The two will + // never collide, but the pure-height stuff only works with bounding boxes, so it + // doesn't know that. The result is a significant over-estimation of the pure-height, + // especially on systems with many staves. To correct for this, we build a skyline + // in two parts: the part we did above contains most of the grobs (note-heads, etc.) + // while the bit we're about to do only contains the breakable grobs at the beginning + // of the system. This way, the tall treble clefs are only compared with the treble + // clefs of the other staff and they will be ignored if the staff above is, for example, + // lyrics. + if (Axis_group_interface::has_interface (g)) + { + Interval begin_of_line_extent = Axis_group_interface::begin_of_line_pure_height (g, start); + if (!begin_of_line_extent.is_empty ()) + { + Box b; + b[a] = begin_of_line_extent; + b[other_axis (a)] = Interval (-infinity_f, -1); + skylines.insert (b, 0, other_axis (a)); + } + } } if (skylines.is_empty ()) diff --git a/lily/axis-group-interface.cc b/lily/axis-group-interface.cc index 639c8b6267..d14a56c084 100644 --- a/lily/axis-group-interface.cc +++ b/lily/axis-group-interface.cc @@ -74,26 +74,37 @@ Axis_group_interface::relative_group_extent (vector const &elts, return r; } +Interval +Axis_group_interface::cached_pure_height (Grob *me, int start, int end) +{ + SCM adjacent_pure_heights = me->get_property ("adjacent-pure-heights"); -/* - FIXME: pure extent handling has a lot of ad-hoc caching. - This should be done with grob property callbacks. + if (!scm_is_pair (adjacent_pure_heights) + || !scm_is_vector (scm_cdr (adjacent_pure_heights))) + return Interval (0, 0); - --hwn -*/ + return combine_pure_heights (me, scm_cdr (adjacent_pure_heights), start, end); +} Interval -Axis_group_interface::cached_pure_height (Grob *me, int start, int end) +Axis_group_interface::begin_of_line_pure_height (Grob *me, int start) +{ + SCM adjacent_pure_heights = me->get_property ("adjacent-pure-heights"); + + if (!scm_is_pair (adjacent_pure_heights) + || !scm_is_vector (scm_car (adjacent_pure_heights))) + return Interval (0, 0); + + return combine_pure_heights (me, scm_car (adjacent_pure_heights), start, start+1); +} + +Interval +Axis_group_interface::combine_pure_heights (Grob *me, SCM measure_extents, int start, int end) { Paper_score *ps = get_root_system (me)->paper_score (); vector breaks = ps->get_break_indices (); vector cols = ps->get_columns (); - SCM extents = me->get_property ("adjacent-pure-heights"); - - if (!scm_is_vector (extents)) - return Interval (0, 0); - Interval ext; for (vsize i = 0; i + 1 < breaks.size (); i++) { @@ -102,12 +113,19 @@ Axis_group_interface::cached_pure_height (Grob *me, int start, int end) break; if (r >= start) - ext.unite (ly_scm2interval (scm_c_vector_ref (extents, i))); + ext.unite (ly_scm2interval (scm_c_vector_ref (measure_extents, i))); } return ext; } +// adjacent-pure-heights is a pair of vectors, each of which has one element +// for every measure in the score. The first vector stores, for each measure, +// the combined height of the elements that are present only when the bar +// is at the beginning of a line. The second vector stores, for each measure, +// the combined height of the elements that are present only when the bar +// is not at the beginning of a line. + MAKE_SCHEME_CALLBACK (Axis_group_interface, adjacent_pure_heights, 1) SCM Axis_group_interface::adjacent_pure_heights (SCM smob) @@ -122,13 +140,16 @@ Axis_group_interface::adjacent_pure_heights (SCM smob) vector breaks = ps->get_break_indices (); vector cols = ps->get_columns (); - SCM ret = scm_c_make_vector (breaks.size () - 1, SCM_EOL); + SCM begin_line_heights = scm_c_make_vector (breaks.size () - 1, SCM_EOL); + SCM mid_line_heights = scm_c_make_vector (breaks.size () - 1, SCM_EOL); + vsize it_index = 0; 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; + Interval begin_line_iv; + Interval mid_line_iv; for (vsize j = it_index; j < items.size (); j++) { @@ -139,8 +160,10 @@ Axis_group_interface::adjacent_pure_heights (SCM smob) && !to_boolean (it->get_property ("cross-staff"))) { Interval dims = items[j]->pure_height (common, start, end); + Interval &target_iv = it->pure_is_visible (start-1, end) ? mid_line_iv : begin_line_iv; + if (!dims.is_empty ()) - iv.unite (dims); + target_iv.unite (dims); } if (rank < end) @@ -156,14 +179,16 @@ Axis_group_interface::adjacent_pure_heights (SCM smob) && !to_boolean (spanners[j]->get_property ("cross-staff"))) { Interval dims = spanners[j]->pure_height (common, start, end); + if (!dims.is_empty ()) - iv.unite (dims); + mid_line_iv.unite (dims); } } - scm_vector_set_x (ret, scm_from_int (i), ly_interval2scm (iv)); + scm_vector_set_x (begin_line_heights, scm_from_int (i), ly_interval2scm (begin_line_iv)); + scm_vector_set_x (mid_line_heights, scm_from_int (i), ly_interval2scm (mid_line_iv)); } - return ret; + return scm_cons (begin_line_heights, mid_line_heights); } Interval diff --git a/lily/include/axis-group-interface.hh b/lily/include/axis-group-interface.hh index 6dd2e7b95c..f852c92a34 100644 --- a/lily/include/axis-group-interface.hh +++ b/lily/include/axis-group-interface.hh @@ -31,7 +31,9 @@ struct Axis_group_interface static Interval relative_group_extent (vector const &list, Grob *common, Axis); static Interval relative_pure_height (Grob *me, int start, int end); + static Interval combine_pure_heights (Grob *me, SCM, int, int); static Interval cached_pure_height (Grob *me, int, int); + static Interval begin_of_line_pure_height (Grob *me, int); static Grob *calc_pure_elts_and_common (Grob*); static Skyline_pair skyline_spacing (Grob *me, vector elements); diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm index 8d166a4d23..af9aa948d0 100644 --- a/scm/define-grob-properties.scm +++ b/scm/define-grob-properties.scm @@ -841,7 +841,7 @@ constructed from a whole number of squiggles.") (accidental-grob ,ly:grob? "The accidental for this note.") (accidental-grobs ,list? "An alist with @code{(@var{notename} . @var{groblist})} entries.") - (adjacent-pure-heights ,vector? "Used by a @code{VerticalAxisGroup} to + (adjacent-pure-heights ,pair? "A pair of vectors. Used by a @code{VerticalAxisGroup} to cache the @code{Y-extent}s of different column ranges.") (adjacent-hairpins ,ly:grob-array? "A list of directly neighboring hairpins.")