From 3d8f4559228bd8a4a30bb024163b64d425b76f18 Mon Sep 17 00:00:00 2001
From: =?utf8?q?Benk=C5=91=20P=C3=A1l?= <benko.pal@gmail.com>
Date: Mon, 13 Feb 2012 18:49:17 +0100
Subject: [PATCH] Issue 2300: do not tinker with the position of a pitched rest

---
 input/regression/rest-on-nonstandard-staff.ly | 44 ++++++++----
 lily/include/staff-symbol.hh                  |  2 +-
 lily/rest.cc                                  | 68 +++++++++++--------
 lily/staff-symbol-referencer.cc               |  3 +-
 lily/staff-symbol.cc                          | 45 ++++++++----
 5 files changed, 105 insertions(+), 57 deletions(-)

diff --git a/input/regression/rest-on-nonstandard-staff.ly b/input/regression/rest-on-nonstandard-staff.ly
index b68330a687..4870f578cf 100644
--- a/input/regression/rest-on-nonstandard-staff.ly
+++ b/input/regression/rest-on-nonstandard-staff.ly
@@ -12,27 +12,47 @@
   indent = 0.0
 }
 
+mus = {
+  r2
+  b\rest
+  c'\rest d'\rest e'\rest f'\rest g'\rest a'\rest b'\rest
+  c''\rest d''\rest e''\rest f''\rest g''\rest a''\rest b''\rest
+  r1
+  b\rest
+  c'\rest d'\rest e'\rest f'\rest g'\rest a'\rest b'\rest
+  c''\rest d''\rest e''\rest f''\rest g''\rest a''\rest b''\rest
+  r\breve
+  b\rest
+  c'\rest d'\rest e'\rest f'\rest g'\rest a'\rest b'\rest
+  c''\rest d''\rest e''\rest f''\rest g''\rest a''\rest b''\rest
+  r\longa
+  b\rest
+  c'\rest d'\rest e'\rest f'\rest g'\rest a'\rest b'\rest
+  c''\rest d''\rest e''\rest f''\rest g''\rest a''\rest b''\rest
+  <<
+    { r2 r2 r1 r\breve r\longa }
+    \\
+    { r2 r2 r1 r\breve r\longa }
+  >>
+}
+
 \new StaffGroup <<
   \new Staff {
-    r2
-    g'2\rest
-    r1
-    g'1\rest
+    \mus
   }
 
   \new Staff {
     \override Staff.StaffSymbol #'line-positions = #'(-4 -2 0 2)
-    r2
-    g'2\rest
-    r1
-    g'1\rest
+    \mus
   }
 
   \new Staff {
     \override Staff.StaffSymbol #'line-count = #4
-    r2
-    g'2\rest
-    r1
-    g'1\rest
+    \mus
+  }
+
+  \new Staff {
+    \override Staff.StaffSymbol #'line-positions = #'(-4 -2 1 5)
+    \mus
   }
 >>
diff --git a/lily/include/staff-symbol.hh b/lily/include/staff-symbol.hh
index a8a68c34f0..688dccb0a6 100644
--- a/lily/include/staff-symbol.hh
+++ b/lily/include/staff-symbol.hh
@@ -36,7 +36,7 @@ public:
   static vector<Real> line_positions (Grob *);
   static vector<Real> ledger_positions (Grob *me, int pos);
   static int line_count (Grob *);
-  static bool on_line (Grob *me, int pos);
+  static bool on_line (Grob *me, int pos, bool allow_ledger = true);
   static Interval line_span (Grob *);
   DECLARE_SCHEME_CALLBACK (print, (SCM));
   DECLARE_SCHEME_CALLBACK (height, (SCM));
diff --git a/lily/rest.cc b/lily/rest.cc
index 552d20f670..a25e6a9319 100644
--- a/lily/rest.cc
+++ b/lily/rest.cc
@@ -46,6 +46,13 @@ Rest::y_offset_callback (SCM smob)
     {
       amount =
         robust_scm2double (me->get_property ("staff-position"), 0) * 0.5 * ss;
+
+      /*
+        semibreve rests were always positioned one off
+      */
+      if (duration_log == 0)
+        amount += ss;
+
       /*
         trust the client on good positioning;
         would be tempting to adjust position of rests longer than a quarter
@@ -55,18 +62,24 @@ Rest::y_offset_callback (SCM smob)
     }
   else
     {
-      amount = 2 * ss * get_grob_direction (me);
+      int pos = 4 * get_grob_direction (me);
 
-      if (line_count % 2 == 0)
-        amount += ss / 2;
-    }
+      /*
+        make a semibreve rest hang from the next line,
+        except for a single line staff;
+        assume the next line being integer steps away
+      */
+      if (duration_log == 0 && line_count > 1)
+        ++pos;
 
-  /*
-    make a semibreve rest hang from the next line,
-    except for a single line staff
-  */
-  if (duration_log == 0 && line_count > 1)
-    amount += ss;
+      /*
+        make sure rest is aligned to a staff line
+      */
+      while (!Staff_symbol_referencer::on_line (me, pos))
+        ++pos;
+
+      amount = ss * 0.5 * pos;
+    }
 
   return scm_from_double (amount);
 }
@@ -91,22 +104,22 @@ Rest::calc_cross_staff (SCM smob)
   make this function easily usable in C++
 */
 string
-Rest::glyph_name (Grob *me, int balltype, string style, bool try_ledgers)
+Rest::glyph_name (Grob *me, int durlog, string style, bool try_ledgers)
 {
   bool is_ledgered = false;
-  if (try_ledgers && (balltype == -1 || balltype == 0 || balltype == 1))
+  if (try_ledgers && (durlog == -1 || durlog == 0 || durlog == 1))
     {
-      Real rad = Staff_symbol_referencer::staff_radius (me) * 2.0;
-      Real pos = Staff_symbol_referencer::get_position (me);
+      int const pos = int (Staff_symbol_referencer::get_position (me));
 
       /*
-        Figure out when the rest is far enough outside the staff. This
-        could bemore generic, but hey, we understand this even after
-        dinner.
+	half rests need ledger if not lying on a staff line,
+	whole rests need ledger if not hanging from a staff line,
+	breve rests need ledger if neither lying on nor hanging from a staff line
       */
-      is_ledgered |= (balltype == -1) && (pos <= -rad - 3 || pos >= +rad + 1);
-      is_ledgered |= (balltype == 0) && (pos >= +rad + 2 || pos < -rad);
-      is_ledgered |= (balltype == 1) && (pos <= -rad - 2 || pos > +rad);
+      if (-1 <= durlog && durlog <= 1)
+        is_ledgered = !Staff_symbol_referencer::on_staff_line (me, pos)
+	  && !(durlog == -1
+	       && Staff_symbol_referencer::on_staff_line (me, pos + 2));
     }
 
   string actual_style (style.c_str ());
@@ -126,11 +139,11 @@ Rest::glyph_name (Grob *me, int balltype, string style, bool try_ledgers)
         There are no 32th/64th/128th mensural/neomensural rests.  In
         these cases, revert back to default style.
       */
-      if (balltype > 4)
+      if (durlog > 4)
         actual_style = "";
     }
 
-  if ((style == "classical") && (balltype != 2))
+  if ((style == "classical") && (durlog != 2))
     {
       /*
         classical style: revert back to default style for any rest other
@@ -148,7 +161,7 @@ Rest::glyph_name (Grob *me, int balltype, string style, bool try_ledgers)
       actual_style = "";
     }
 
-  return ("rests." + to_string (balltype) + (is_ledgered ? "o" : "")
+  return ("rests." + to_string (durlog) + (is_ledgered ? "o" : "")
           + actual_style);
 }
 
@@ -156,16 +169,16 @@ MAKE_SCHEME_CALLBACK (Rest, print, 1);
 SCM
 Rest::brew_internal_stencil (Grob *me, bool ledgered)
 {
-  SCM balltype_scm = me->get_property ("duration-log");
-  if (!scm_is_number (balltype_scm))
+  SCM durlog_scm = me->get_property ("duration-log");
+  if (!scm_is_number (durlog_scm))
     return Stencil ().smobbed_copy ();
 
-  int balltype = scm_to_int (balltype_scm);
+  int durlog = scm_to_int (durlog_scm);
 
   string style = robust_symbol2string (me->get_property ("style"), "default");
 
   Font_metric *fm = Font_interface::get_default_font (me);
-  string font_char = glyph_name (me, balltype, style, ledgered);
+  string font_char = glyph_name (me, durlog, style, ledgered);
   Stencil out = fm->find_by_name (font_char);
   if (out.is_empty ())
     me->warning (_f ("rest `%s' not found", font_char.c_str ()));
@@ -250,4 +263,3 @@ ADD_INTERFACE (Rest,
                "minimum-distance "
                "style "
               );
-
diff --git a/lily/staff-symbol-referencer.cc b/lily/staff-symbol-referencer.cc
index 74c2c448c6..b18bb04fa3 100644
--- a/lily/staff-symbol-referencer.cc
+++ b/lily/staff-symbol-referencer.cc
@@ -41,7 +41,8 @@ Staff_symbol_referencer::on_line (Grob *me, int pos)
 bool
 Staff_symbol_referencer::on_staff_line (Grob *me, int pos)
 {
-  return on_line (me, pos) && abs (pos) <= 2 * staff_radius (me);
+  Grob *st = get_staff_symbol (me);
+  return st ? Staff_symbol::on_line (st, pos, false) : false;
 }
 
 Grob *
diff --git a/lily/staff-symbol.cc b/lily/staff-symbol.cc
index e2ea43a570..57279033b2 100644
--- a/lily/staff-symbol.cc
+++ b/lily/staff-symbol.cc
@@ -80,7 +80,6 @@ Staff_symbol::print (SCM smob)
   Stencil m;
 
   vector<Real> line_positions = Staff_symbol::line_positions (me);
-  int line_count = line_positions.size ();
 
   Stencil line
     = Lookup::horizontal_line (span_points
@@ -88,10 +87,13 @@ Staff_symbol::print (SCM smob)
                                t);
 
   Real space = staff_space (me);
-  for (int i = 0; i < line_count; i++)
+  for (vector<Real>::const_iterator i = line_positions.begin (),
+         e = line_positions.end ();
+       i != e;
+       ++i)
     {
       Stencil b (line);
-      b.translate_axis (line_positions[i] * 0.5 * space, Y_AXIS);
+      b.translate_axis (*i * 0.5 * space, Y_AXIS);
       m.add_stencil (b);
     }
   return m.smobbed_copy ();
@@ -137,17 +139,18 @@ Staff_symbol::ledger_positions (Grob *me, int pos)
   if (line_positions.empty ())
     return values;
 
-  int line_count = line_positions.size ();
-
   // find the staff line nearest to note position
   Real nearest_line = line_positions[0];
   Real line_dist = abs (line_positions[0] - pos);
-  for (int i = 1; i < line_count; i++)
+  for (vector<Real>::const_iterator i = line_positions.begin (),
+         e = line_positions.end ();
+       i != e;
+       ++i)
     {
-      if (abs (line_positions[i] - pos) < line_dist)
+      if (abs (*i - pos) < line_dist)
         {
-          nearest_line = line_positions[i];
-          line_dist = abs (line_positions[i] - pos);
+          nearest_line = *i;
+          line_dist = abs (*i - pos);
         }
     }
 
@@ -303,7 +306,7 @@ Staff_symbol::height (SCM smob)
 }
 
 bool
-Staff_symbol::on_line (Grob *me, int pos)
+Staff_symbol::on_line (Grob *me, int pos, bool allow_ledger)
 {
   SCM line_positions = me->get_property ("line-positions");
   if (scm_is_pair (line_positions))
@@ -321,15 +324,27 @@ Staff_symbol::on_line (Grob *me, int pos)
             min_line = current_line;
 
         }
-      if (pos < min_line)
-        return (( (int) (rint (pos - min_line)) % 2) == 0);
-      if (pos > max_line)
-        return (( (int) (rint (pos - max_line)) % 2) == 0);
+
+      if (allow_ledger)
+        {
+          if (pos < min_line)
+            return (( (int) (rint (pos - min_line)) % 2) == 0);
+          if (pos > max_line)
+            return (( (int) (rint (pos - max_line)) % 2) == 0);
+        }
 
       return false;
     }
   else
-    return ((abs (pos + line_count (me)) % 2) == 1);
+    {
+      int const line_cnt = line_count (me);
+      bool result = abs (pos + line_cnt) % 2 == 1;
+      if (result && !allow_ledger)
+        {
+          result = -line_cnt < pos && pos < line_cnt;
+        }
+      return result;
+    }
 }
 
 Interval
-- 
2.39.5