]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/note-spacing.cc
release: 1.5.38
[lilypond.git] / lily / note-spacing.cc
index 4b0d784b18e3930335865c9c5ae310d42c41f039..88beea31424e3faca43faa94cf4fd9b2ea50417c 100644 (file)
@@ -3,7 +3,7 @@
 
   source file of the GNU LilyPond music typesetter
 
-  (c) 2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+  (c) 2001--2002  Han-Wen Nienhuys <hanwen@cs.uu.nl>
 */
 
 
@@ -15,6 +15,8 @@
 #include "note-column.hh"
 #include "warn.hh"
 #include "stem.hh"
+#include "separation-item.hh"
+#include "staff-spacing.hh"
 
 bool
 Note_spacing::has_interface (Grob* g)
@@ -150,61 +152,148 @@ Real
 Note_spacing::stem_dir_correction (Grob*me) 
 {
   Drul_array<Direction> stem_dirs(CENTER,CENTER);
-  Drul_array<Interval> posns;
+  Drul_array<Interval> stem_posns;
+  Drul_array<Interval> head_posns;  
   Drul_array<SCM> props(me->get_grob_property ("left-items"),
                        me->get_grob_property ("right-items"));
 
+  Real correction = 0.0;
+  
   stem_dirs[LEFT] = stem_dirs[RIGHT] = CENTER;
   Interval intersect;
+  Interval bar_xextent;
+  Interval bar_yextent;  
+  
   bool correct = true;
   Direction d = LEFT;
+  bool acc_right = false;
+  
   do
     {
       for (SCM  s = props[d]; gh_pair_p (s); s = gh_cdr (s))
        {
          Item * it= dynamic_cast<Item*> (unsmob_grob (gh_car(s)));
 
+         if (d == RIGHT)
+           acc_right = acc_right || Note_column::accidentals (it);
+         
          Grob *stem = Note_column::stem_l (it);
 
-         if (!stem || Stem::invisible_b (stem))
+         if (!stem)
+           {
+             if (d == RIGHT && Separation_item::has_interface (it))
+               {
+                 Grob *last = Staff_spacing::extremal_break_aligned_grob (it, LEFT, &bar_xextent);
+
+                 if (last)
+                   bar_yextent = Staff_spacing::bar_y_positions (last);
+
+                 break;
+               }
+
+             goto exit_func; 
+           }
+         if(Stem::invisible_b (stem))
            {
              correct = false;
-             goto exit_loop ;
+             goto exit_func ;
            }
 
          Direction sd = Stem::get_direction (stem);
          if (stem_dirs[d] && stem_dirs[d] != sd)
            {
              correct = false;
-             goto exit_loop;
+             goto exit_func;
            }
          stem_dirs[d] = sd;
 
-         Real chord_start = Stem::head_positions (stem)[sd];
+         Interval hp  = Stem::head_positions (stem);
+         Real chord_start = hp[sd];      
          Real stem_end = Stem::stem_end_position (stem);
          
-         posns[d] = Interval(chord_start<?stem_end, chord_start>? stem_end);
+         stem_posns[d] = Interval(chord_start<?stem_end, chord_start>? stem_end);
+         head_posns[d].unite (hp);
        }
     }
   while (flip (&d) != LEFT);
   
-  intersect = posns[LEFT];  
-  intersect.intersect(posns[RIGHT]);
-  correct = correct && !intersect.empty_b ();
-  correct = correct && (stem_dirs[LEFT] *stem_dirs[RIGHT] == -1);
-  
- exit_loop:
-  if(!correct)
-    return 0.0;
 
   /*
-    Ugh. 7 is hardcoded.
-   */
-  Real correction = abs (intersect.length ());
-  correction = (correction/7) <? 1.0;
-  correction *= stem_dirs[LEFT] ;
-  correction *= gh_scm2double (me->get_grob_property ("stem-spacing-correction"));
+    don't correct if accidentals are sticking out of the right side.
+
+  */
+  if (acc_right)
+    return 0.0;
+
+  if (!bar_yextent.empty_b())
+    {
+      stem_dirs[RIGHT] = - stem_dirs[LEFT];
+      stem_posns[RIGHT] = bar_yextent;
+    }
+  
+  if (correct &&stem_dirs[LEFT] *stem_dirs[RIGHT] == -1)
+    {
+      
+      intersect = stem_posns[LEFT];  
+      intersect.intersect(stem_posns[RIGHT]);
+      correct = correct && !intersect.empty_b ();
+
+      if (!correct)
+       return 0.0;
+      /*
+       Ugh. 7 is hardcoded.
+      */
+      correction = abs (intersect.length ());
+      correction = (correction/7) <? 1.0;
+      correction *= stem_dirs[LEFT] ;
+      correction *= gh_scm2double (me->get_grob_property ("stem-spacing-correction"));
 
+      if (!bar_yextent.empty_b())
+       {
+         correction *= 0.5;
+       }
+    }
+  else if (correct)
+    {
+      /*
+       Correct for the following situation:
+
+        X      X
+       |      | 
+       |      |
+       |   X  |
+       |  |   |
+       ========
+
+           ^ move the center one to the left.
+       
+
+       this effect seems to be much more subtle than the
+       stem-direction stuff (why?), and also does not scale with the
+       difference in stem length.
+       
+       */
+
+      
+      Interval hp = head_posns[LEFT];
+      hp.intersect  (head_posns[RIGHT]);
+      if (!hp.empty_b())
+       return 0.0;
+
+      Direction lowest =
+       (head_posns[LEFT][DOWN] > head_posns[RIGHT][UP]) ? RIGHT : LEFT;
+
+      Real delta = head_posns[-lowest][DOWN] - head_posns[lowest][UP] ;
+      Real corr = gh_scm2double (me->get_grob_property ("stem-spacing-correction"));
+      corr =  (delta <= 1) ? 0.0 : 0.25;
+      
+      correction=  -lowest * corr ;
+    }
+
+  if (!bar_xextent.empty_b())
+    correction += - bar_xextent[LEFT];
+  
+ exit_func:
   return correction;
 }