From 7ce94ab2bcd9d12b6f7e40020db4c51185fe99db Mon Sep 17 00:00:00 2001 From: Mike Solomon Date: Mon, 19 Dec 2011 11:00:51 +0100 Subject: [PATCH] Prevents cross-staff Stems from colliding with articulations. Does so by creating a StemStub grob for each Stem whose only effect on spacing comes from its extra-spacing-height, which blocks articulations from bumping into the Stems. Beamed stems cannot be considered in extra-spacing-height because they trigger a circular dependency in the calculation of direction. --- .../stem-cross-staff-articulation.ly | 33 +++++++++++++++++++ lily/grob-scheme.cc | 21 ++++++++++++ lily/score-engraver.cc | 4 +-- lily/stem-engraver.cc | 1 + lily/stem.cc | 31 ++++++++++++++--- scm/define-grobs.scm | 8 +++++ scm/output-lib.scm | 27 +++++++++++++++ 7 files changed, 119 insertions(+), 6 deletions(-) create mode 100644 input/regression/stem-cross-staff-articulation.ly diff --git a/input/regression/stem-cross-staff-articulation.ly b/input/regression/stem-cross-staff-articulation.ly new file mode 100644 index 0000000000..1d8ca550da --- /dev/null +++ b/input/regression/stem-cross-staff-articulation.ly @@ -0,0 +1,33 @@ +\version "2.15.22" + +\header { + texidoc = "Cross-staff stems avoid articulations. Articulations that don't +get in the way of stems do not cause unwanted horizontal space. +" +} + +\new GrandStaff << + \new Staff = "a" { s1 } + \new Staff = "b" { + \stemDown + \clef bass + d'8^\prall^\espressivo [\change Staff="a" g'' ] + g'' [\change Staff="b" d'8^\prall^\espressivo ] + \stemUp + f, [\change Staff="a" b8_\prall_\espressivo ] + b_\prall_\espressivo [\change Staff="b" f,8 ] + } +>> + +\new GrandStaff << + \new Staff = "a" { s1 } + \new Staff = "b" { + \stemDown + \clef bass + d'8 [\change Staff="a" g'' ] + g'' [\change Staff="b" d'8 ] + \stemUp + f, [\change Staff="a" b8 ] + b [\change Staff="b" f,8 ] + } +>> diff --git a/lily/grob-scheme.cc b/lily/grob-scheme.cc index 92f755d7a7..3983cac70c 100644 --- a/lily/grob-scheme.cc +++ b/lily/grob-scheme.cc @@ -100,6 +100,27 @@ LY_DEFINE (ly_grob_pure_property, "ly:grob-pure-property", return retval; } +LY_DEFINE (ly_grob_pure_height, "ly:grob-pure-height", + 4, 1, 0, (SCM grob, SCM refp, SCM beg, SCM end, SCM val), + "Return the pure height of @var{grob} given refpoint @var{refp}." + " If no value is found, return @var{val} or @code{'()}" + " if @var{val} is not specified.") +{ + Grob *sc = unsmob_grob (grob); + Grob *ref = unsmob_grob (refp); + + LY_ASSERT_SMOB (Grob, grob, 1); + LY_ASSERT_SMOB (Grob, refp, 2); + LY_ASSERT_TYPE (scm_is_integer, beg, 3); + LY_ASSERT_TYPE (scm_is_integer, end, 4); + if (val == SCM_UNDEFINED) + val = SCM_EOL; + + Interval retval = sc->pure_height (ref, scm_to_int (beg), scm_to_int (end)); + + return ly_interval2scm (retval); +} + LY_DEFINE (ly_grob_property, "ly:grob-property", 2, 1, 0, (SCM grob, SCM sym, SCM val), "Return the value for property @var{sym} of @var{grob}." diff --git a/lily/score-engraver.cc b/lily/score-engraver.cc index 227c86c41e..cb3808d948 100644 --- a/lily/score-engraver.cc +++ b/lily/score-engraver.cc @@ -155,13 +155,13 @@ Score_engraver::one_time_step (SCM) precomputed_recurse_over_translators (context (), STOP_TRANSLATION_TIMESTEP, UP); typeset_all (); } - +#include void Score_engraver::announce_grob (Grob_info info) { Engraver_group::announce_grob (info); if (info.start_end () == START) - { + {if (info.grob ()->name () == "StemStub") VALGRIND_PRINTF_BACKTRACE ("foo"); pscore_->root_system ()->typeset_grob (info.grob ()); elems_.push_back (info.grob ()); } diff --git a/lily/stem-engraver.cc b/lily/stem-engraver.cc index 04184a9020..67a2bffb73 100644 --- a/lily/stem-engraver.cc +++ b/lily/stem-engraver.cc @@ -68,6 +68,7 @@ Stem_engraver::make_stem (Grob_info gi) /* Announce the cause of the head as cause of the stem. The stem needs a rhythmic structure to fit it into a beam. */ stem_ = make_item ("Stem", gi.grob ()->self_scm ()); + (void) make_item ("StemStub", gi.grob ()->self_scm ()); if (tremolo_ev_) { /* Stem tremolo is never applied to a note by default, diff --git a/lily/stem.cc b/lily/stem.cc index 568e1846c3..c07a2164a5 100644 --- a/lily/stem.cc +++ b/lily/stem.cc @@ -302,7 +302,7 @@ Stem::internal_pure_height (Grob *me, bool calc_beam) if (!beam) return iv; - if (!to_boolean (me->get_property ("cross-staff")) && calc_beam) + if (calc_beam) { Interval overshoot; Direction dir = get_grob_direction (me); @@ -315,12 +315,35 @@ Stem::internal_pure_height (Grob *me, bool calc_beam) vector my_stems; extract_grob_set (beam, "normal-stems", normal_stems); for (vsize i = 0; i < normal_stems.size (); i++) - if (normal_stems[i] != me && get_grob_direction (normal_stems[i]) == dir) + if (get_grob_direction (normal_stems[i]) == dir) { - heights.push_back (Stem::internal_pure_height (normal_stems[i], false)); + if (normal_stems[i] != me) + heights.push_back (Stem::internal_pure_height (normal_stems[i], false)); + else + heights.push_back (iv); my_stems.push_back (normal_stems[i]); - iv.unite (heights.back ()); } + //iv.unite (heights.back ()); + // look for cross staff effects + vector coords; + Grob *common = common_refpoint_of_array (my_stems, me, Y_AXIS); + Real min_pos = infinity_f; + Real max_pos = -infinity_f; + for (vsize i = 0; i < my_stems.size (); i++) + { + coords.push_back (my_stems[i]->pure_relative_y_coordinate (common, 0, INT_MAX)); + min_pos = min (min_pos, coords[i]); + max_pos = max (max_pos, coords[i]); + } + for (vsize i = 0; i < heights.size (); i++) + { + heights[i][dir] += dir == DOWN + ? coords[i] - max_pos + : coords[i] - min_pos; + } + + for (vsize i = 0; i < heights.size (); i++) iv.unite (heights[i]); + for (vsize i = 0; i < my_stems.size (); i++) cache_pure_height (my_stems[i], iv, heights[i]); iv.intersect (overshoot); diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index 08b3ff5f14..2009b46dee 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -1978,6 +1978,14 @@ (meta . ((class . Item) (interfaces . (stem-interface)))))) + (StemStub + . ( + (X-extent . ,stem-stub::width) + (extra-spacing-height . ,stem-stub::extra-spacing-height) + (Y-extent . ,(ly:make-unpure-pure-container #f stem-stub::pure-height)) + (meta . ((class . Item) + (interfaces . ()))))) + (StemTremolo . ( (beam-thickness . 0.48) ; staff-space diff --git a/scm/output-lib.scm b/scm/output-lib.scm index 84f9984b33..51a45aab55 100644 --- a/scm/output-lib.scm +++ b/scm/output-lib.scm @@ -132,6 +132,33 @@ (beg (ly:grob-pure-property grob 'stem-begin-position 0 1000))) (abs (- (ly:stem::pure-calc-stem-end-position grob 0 2147483646) beg)))) +(define (stem-stub::do-calculations grob) + (and (ly:grob-property (ly:grob-parent grob X) 'cross-staff) + (not (ly:grob-property (ly:grob-parent grob X) 'transparent)))) + +(define-public (stem-stub::pure-height grob beg end) + (if (stem-stub::do-calculations grob) + '(0 . 0) + '(+inf.0 . -inf.0))) + +(define-public (stem-stub::width grob) + (if (stem-stub::do-calculations grob) + (grob::x-parent-width grob) + '(+inf.0 . -inf.0))) + +(define-public (stem-stub::extra-spacing-height grob) + (if (stem-stub::do-calculations grob) + (let* ((dad (ly:grob-parent grob X)) + (refp (ly:grob-common-refpoint grob dad Y)) + (stem_ph (ly:grob-pure-height dad refp 0 1000000)) + (my_ph (ly:grob-pure-height grob refp 0 1000000)) + ;; only account for distance if stem is on different staff than stub + (dist (if (grob::has-interface refp 'hara-kiri-group-spanner-interface) + 0 + (- (car my_ph) (car stem_ph))))) + (if (interval-empty? (interval-intersection stem_ph my_ph)) #f (coord-translate stem_ph dist))) + #f)) + (define-public (note-head::calc-duration-log grob) (min 2 (ly:duration-log -- 2.39.2