From: Mike Solomon <mike@apollinemike.com>
Date: Mon, 19 Dec 2011 10:00:51 +0000 (+0100)
Subject: Prevents cross-staff Stems from colliding with articulations.
X-Git-Tag: release/2.15.23-1~9
X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=7ce94ab2bcd9d12b6f7e40020db4c51185fe99db;p=lilypond.git

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.
---

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 <valgrind/valgrind.h>
 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<Grob *> 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<Real> 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