]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/spacing-spanner.cc
2003 -> 2004
[lilypond.git] / lily / spacing-spanner.cc
index 091dd1ce68e827da521debeb03f993a6e25bc50b..4d1cdd89017955c49812ddc4ff90c8bb8832773d 100644 (file)
@@ -3,7 +3,7 @@
   
   source file of the GNU LilyPond music typesetter
   
-  (c) 1999--2003 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+  (c) 1999--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
   
  */
 
 #include "break-align-interface.hh"
 #include "spacing-interface.hh"
 
+
+/*
+  TODO: this file/class is too complex. Should figure out how to chop
+  this up even more.
+    
+ */
+
 class Spacing_spanner
 {
 public:
@@ -41,7 +48,7 @@ public:
   static Rational find_shortest (Grob *, Link_array<Grob> const &);  
   static void breakable_column_spacing (Grob*, Item* l, Item *r, Moment);
   static void find_loose_columns () {}
-  static void prune_loose_colunms (Grob*,Link_array<Grob> *cols, Rational);
+  static void prune_loose_columns (Grob*,Link_array<Grob> *cols, Rational);
   static void find_loose_columns (Link_array<Grob> cols);
   static void set_explicit_neighbor_columns (Link_array<Grob> cols);
   static void set_implicit_neighbor_columns (Link_array<Grob> cols);
@@ -154,10 +161,10 @@ loose_column (Grob *l, Grob *c, Grob *r)
   between.
 */
 void
-Spacing_spanner::prune_loose_colunms (Grob*me,Link_array<Grob> *cols, Rational shortest)
+Spacing_spanner::prune_loose_columns (Grob*me,Link_array<Grob> *cols, Rational shortest)
 {
   Link_array<Grob> newcols;
-  Real increment = gh_scm2double (me->get_grob_property ("spacing-increment"));
+  Real increment = robust_scm2double (me->get_grob_property ("spacing-increment"), 1.2);
   for (int i=0; i < cols->size ();  i++)
     {
       if (Item::breakable_b (cols->elem(i)) || Paper_column::musical_b (cols->elem (i)))
@@ -361,7 +368,7 @@ Spacing_spanner::set_springs (SCM smob)
 {
   Grob *me = unsmob_grob (smob);
 
-  Link_array<Grob> all (me->pscore_->system_->columns ()) ;
+  Link_array<Grob> all (me->pscore_->system_->columns ());
 
   set_explicit_neighbor_columns (all);
 
@@ -376,10 +383,10 @@ Spacing_spanner::set_springs (SCM smob)
       global_shortest = find_shortest (me, all);
       if (verbose_global_b)
        {
-         progress_indication (_f("Global shortest duration is %s\n", global_shortest.string ())); 
+         progress_indication (_f("Global shortest duration is %s\n", global_shortest.to_string ())); 
        }
     }
-  prune_loose_colunms (me, &all, global_shortest);
+  prune_loose_columns (me, &all, global_shortest);
   set_implicit_neighbor_columns (all);
 
   
@@ -438,7 +445,7 @@ Spacing_spanner::find_shortest (Grob *me, Link_array<Grob> const &cols)
          assert (this_shortest.to_bool());
          shortest_in_measure = shortest_in_measure <? this_shortest.main_part_;
        }
-      else if (!shortest_in_measure.infty_b()
+      else if (!shortest_in_measure.is_infinity ()
               && Item::breakable_b (cols[i]))
        {
          int j = 0;
@@ -501,7 +508,7 @@ void
 Spacing_spanner::do_measure (Rational shortest, Grob*me, Link_array<Grob> *cols) 
 {
 
-  Real headwid =       gh_scm2double (me->get_grob_property ("spacing-increment"));
+  Real headwid = robust_scm2double (me->get_grob_property ("spacing-increment"), 1);
   for (int i= 0; i < cols->size () - 1; i++)
     {
       Item * l = dynamic_cast<Item*> (cols->elem (i));
@@ -553,9 +560,10 @@ Spacing_spanner::musical_column_spacing (Grob *me, Item * lc, Item *rc, Real inc
   bool expand_only = false;
   Real base_note_space = note_spacing (me, lc, rc, shortest, &expand_only);
 
-  Real max_note_space = -infinity_f;
-  Real max_fixed_note_space = -infinity_f;
-
+  Real compound_note_space = 0.0;
+  Real compound_fixed_note_space = 0.0;
+  int wish_count = 0;
+  
   SCM seq  = lc->get_grob_property ("right-neighbors");
 
   /*
@@ -581,8 +589,12 @@ Spacing_spanner::musical_column_spacing (Grob *me, Item * lc, Item *rc, Real inc
          Real fixed =0.0;
          
          Note_spacing::get_spacing (wish, rc, base_note_space, increment, &space, &fixed);
-         max_note_space = max_note_space >? space;
-         max_fixed_note_space = max_fixed_note_space >? fixed;
+
+         
+         compound_note_space = compound_note_space + space;
+         compound_fixed_note_space = compound_fixed_note_space + fixed;
+         wish_count ++;
+         
        }
     }
 
@@ -592,16 +604,19 @@ Spacing_spanner::musical_column_spacing (Grob *me, Item * lc, Item *rc, Real inc
       /*
        Ugh. 0.8 is arbitrary.
        */
-      max_note_space *= 0.8; 
+      compound_note_space *= 0.8; 
     }
   
-  if (max_note_space < 0)
+  if (compound_note_space < 0 || wish_count == 0)
     {
-      max_note_space = base_note_space;
-      max_fixed_note_space =  increment;
+      compound_note_space = base_note_space;
+      compound_fixed_note_space =  increment;
+    }
+  else
+    {
+      compound_note_space /= wish_count;
+      compound_fixed_note_space /= wish_count;
     }
-
-  bool ragged = to_boolean (me->get_paper ()->get_scmvar ("raggedright"));
 
   /*
     Whatever we do, the fixed space is smaller than the real
@@ -610,27 +625,33 @@ Spacing_spanner::musical_column_spacing (Grob *me, Item * lc, Item *rc, Real inc
     TODO: this criterion is discontinuous in the derivative.
     Maybe it should be continuous?
   */
-  max_fixed_note_space = max_fixed_note_space <?  max_note_space;
-
+  compound_fixed_note_space = compound_fixed_note_space <? compound_note_space;
 
-#if 0
-  /*
-    This doesn't make sense. For ragged right we want to have the same
-    spacing. Otherwise  the option should be called differently.
-
-    ragged-righted-and-weird-spacing. Whatever.
-
-  */
-  Real strength = (ragged) ? 1.0 : 1 / (max_note_space - max_fixed_note_space);
-  Real distance = (ragged) ? max_fixed_note_space : max_note_space;
-#else
+  bool packed = to_boolean (me->get_paper ()->get_scmvar ("packed"));
+  Real strength, distance;
 
   /*
-        TODO: make sure that the space doesn't exceed the right margin.
+    TODO: make sure that the space doesn't exceed the right margin.
    */
-  Real strength = 1 / (max_note_space - max_fixed_note_space);
-  Real distance = max_note_space;
-#endif
+  if (packed)
+    {
+      /*
+       In packed mode, pack notes as tight as possible.  This makes
+       sense mostly in combination with raggedright mode: the notes
+       are then printed at minimum distance.  This is mostly useful
+       for ancient notation, but may also be useful for some flavours
+       of contemporary music.  If not in raggedright mode, lily will
+       pack as much bars of music as possible into a line, but the
+       line will then be stretched to fill the whole linewidth.
+      */
+      strength = 1.0;
+      distance = compound_fixed_note_space;
+    }
+  else
+    {
+      strength = 1 / (compound_note_space - compound_fixed_note_space);
+      distance = compound_note_space;
+    }
 
   //  Spaceable_grob::add_spring (lc, rc, distance, strength, expand_only);
 
@@ -647,7 +668,6 @@ Spacing_spanner::standard_breakable_column_spacing (Grob * me, Item*l, Item*r,
                                   Real * fixed, Real * space,
                                   Moment shortest)
 {
   *fixed = 0.0;
   Direction d = LEFT;
   Drul_array<Item*> cols(l,r);
@@ -661,10 +681,12 @@ Spacing_spanner::standard_breakable_column_spacing (Grob * me, Item*l, Item*r,
            what happens if we do this for non musical columns only.
           */
          Interval lext = cols[d]->extent (cols [d], X_AXIS);
-         *fixed += -d * lext[-d];
+         if (!lext.is_empty ())
+           *fixed += -d * lext[-d];
        }
     }
   while (flip (&d) != LEFT);
+  
 
   if (l->breakable_b (l) && r->breakable_b(r))
     {
@@ -673,98 +695,99 @@ Spacing_spanner::standard_breakable_column_spacing (Grob * me, Item*l, Item*r,
       if (dt)
        mlen = *dt;
       
-      Real incr = gh_scm2double (me->get_grob_property ("spacing-increment"));
+      Real incr = robust_scm2double (me->get_grob_property ("spacing-increment"), 1);
 
       *space =  *fixed + incr * double (mlen.main_part_ / shortest.main_part_) * 0.8;
     }
   else
     {
       Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
-      bool dummy;
 
-      *space = *fixed + get_duration_space (me, dt, shortest.main_part_, &dummy);
+      if (dt == Moment (0,0))
+       {
+         /*
+           In this case, Staff_spacing should handle the job,
+           using dt when it is 0 is silly.
+          */
+         *space = *fixed + 0.5; 
+       }
+      else
+       {
+         bool dummy;
+         *space = *fixed + get_duration_space (me, dt, shortest.main_part_, &dummy);
+       }
     }
 }
 
 
 /*
   Read hints from L and generate springs.
- */
+*/
 void
 Spacing_spanner::breakable_column_spacing (Grob*me, Item* l, Item *r,Moment shortest)
 {
-  Real max_fixed = -infinity_f;
-  Real max_space = -infinity_f;
+  Real compound_fixed = 0.0;
+  Real compound_space = 0.0;
+  int wish_count = 0;
 
-  standard_breakable_column_spacing (me, l, r, &max_fixed, &max_space ,
-                                    shortest);
-  
-  for (SCM s = l->get_grob_property ("spacing-wishes");
-       gh_pair_p (s); s = gh_cdr (s))
-    {
-      Item * spacing_grob = dynamic_cast<Item*> (unsmob_grob (gh_car (s)));
-
-      if (!spacing_grob || !Staff_spacing::has_interface (spacing_grob))
-       continue;
+  Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
 
-      Real space;
-      Real fixed_space;
-
-      /*
-       column for the left one settings should be ok due automatic
-       pointer munging.
+  if (dt == Moment (0,0))
+    {
+      for (SCM s = l->get_grob_property ("spacing-wishes");
+          gh_pair_p (s); s = gh_cdr (s))
+       {
+         Item * spacing_grob = dynamic_cast<Item*> (unsmob_grob (gh_car (s)));
 
-      */
-      assert (spacing_grob-> get_column () == l);
+         if (!spacing_grob || !Staff_spacing::has_interface (spacing_grob))
+           continue;
 
-      Staff_spacing::get_spacing_params (spacing_grob,
-                                        &space, &fixed_space);
+         Real space;
+         Real fixed_space;
 
-      if (Paper_column::when_mom (r).grace_part_)
-       {
          /*
-           Correct for grace notes.
+           column for the left one settings should be ok due automatic
+           pointer munging.
 
-           Ugh. The 0.8 is arbitrary.
-          */
-         space *= 0.8;
-       }
-      if (space > max_space)
-       {
-         max_space = space;
-         max_fixed = fixed_space;
-       }
-    }
+         */
+         assert (spacing_grob-> get_column () == l);
 
-  
-  
-    
-  if (isinf (max_space))
-    {
-    /*
-      One situation where this can happen is when there is a column
-      that only serves as a spanning point for a short staff-symbol.
+         Staff_spacing::get_spacing_params (spacing_grob,
+                                            &space, &fixed_space);
 
-     ===============X===
+         if (Paper_column::when_mom (r).grace_part_)
+           {
+             /*
+               Correct for grace notes.
 
-         |=======Y
+               Ugh. The 0.8 is arbitrary.
+             */
+             space *= 0.8;
+           }
 
 
-      (here no StaffSpacing from Y to X is found.)
-    */      
-      programming_error ("No StaffSpacing wishes found");
-      max_space = 2.0;
-      max_fixed = 1.0;
+         compound_space += space;
+         compound_fixed += fixed_space;
+         wish_count ++ ;
+       }
     }
 
-  
-  if (l->break_status_dir() == RIGHT
-      && Paper_column::when_mom (l) == Paper_column::when_mom (r))
+  if (compound_space <= 0.0 || !wish_count)
+    {
+      standard_breakable_column_spacing (me, l, r, &compound_fixed, &compound_space ,
+                                        shortest);
+      wish_count = 1;
+    }
+  else
     {
-      /* Start of line: this space is not stretchable */
-      max_fixed = max_space;
+      compound_space /= wish_count;
+      compound_fixed /= wish_count;
     }
 
+  assert (!isinf (compound_space));
+  compound_space = compound_space >? compound_fixed;
+
+  
   /*
     Hmm.  we do 1/0 in the next thing. Perhaps we should check if this
     works on all architectures.
@@ -777,8 +800,8 @@ Spacing_spanner::breakable_column_spacing (Grob*me, Item* l, Item *r,Moment shor
     Do it more cleanly, or rename the property. 
     
    */
-  Real strength = 1 / (max_space - max_fixed);
-  Real distance =  max_space;
+  Real strength = 1 / (compound_space - compound_fixed);
+  Real distance = compound_space;
   Spaceable_grob::add_spring (l, r, distance, strength, false);
 }
 
@@ -789,8 +812,8 @@ Spacing_spanner::breakable_column_spacing (Grob*me, Item* l, Item *r,Moment shor
 Real
 Spacing_spanner::get_duration_space (Grob*me, Moment d, Rational shortest, bool * expand_only) 
 {
-  Real k = gh_scm2double (me->get_grob_property ("shortest-duration-space"));
-  Real incr = gh_scm2double (me->get_grob_property ("spacing-increment"));
+  Real k = robust_scm2double (me->get_grob_property ("shortest-duration-space"), 1);
+  Real incr = robust_scm2double (me->get_grob_property ("spacing-increment"), 1);
   
   if (d < shortest)
     {
@@ -812,9 +835,6 @@ Spacing_spanner::get_duration_space (Grob*me, Moment d, Rational shortest, bool
        */
       Rational ratio = d.main_part_ / shortest;
 
-#if 0
-      *expand_only = true;
-#endif
       return ((k-1) + double (ratio)) * incr;
     }
   else
@@ -845,7 +865,7 @@ Spacing_spanner::note_spacing (Grob*me, Grob *lc, Grob *rc,
   
   if (! shortest_playing_len.to_bool ())
     {
-      programming_error ("can't find a ruling note at " + Paper_column::when_mom (lc).string ());
+      programming_error ("can't find a ruling note at " + Paper_column::when_mom (lc).to_string ());
       shortest_playing_len = 1;
     }
 
@@ -853,6 +873,39 @@ Spacing_spanner::note_spacing (Grob*me, Grob *lc, Grob *rc,
   Moment rwhen =  Paper_column::when_mom (rc);
 
   Moment delta_t = rwhen - lwhen;
+  if (!Paper_column::musical_b (rc ))
+    {
+      /*
+       when toying with mmrests, it is possible to have musical
+       column on the left and non-musical on the right, spanning
+       several measures.
+
+       In 2.0.1, this still fucks up in an interesting way:
+
+       
+\score {
+{      \property Score.skipBars = ##t
+       \context Staff = clarinet
+           { 
+               \notes {
+               \time 3/4 \mark "72"
+<< s1*0^"all"          R4*3*11 >>
+               \mark "73"
+               R4*3*11 \mark "74"
+       d2 r4
+
+
+               }}}
+    \paper { raggedright = ##t }
+}
+
+       
+       */
+      
+      Moment *dt = unsmob_moment (rc->get_grob_property ("measure-length"));
+      if (dt)
+       delta_t = delta_t <? *dt; 
+    }
   Real dist = 0.0;
 
   /*
@@ -875,10 +928,8 @@ Spacing_spanner::note_spacing (Grob*me, Grob *lc, Grob *rc,
       */
       dist = get_duration_space (me, shortest, shortest.main_part_, expand_only);
 
-      Real grace_fact = 1.0;
-      SCM gf = me->get_grob_property ("grace-space-factor");
-      if (gh_number_p (gf))
-       grace_fact = gh_scm2double (gf);
+      Real grace_fact
+       = robust_scm2double (me->get_grob_property ("grace-space-factor"), 1);
 
       dist *= grace_fact;
     }