]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/spring-spacer.cc
patch::: 1.1.38.jcn1: Cons
[lilypond.git] / lily / spring-spacer.cc
index 99939fcd6b55900401845a3e83ca78550723c234..4b7c39b5b59748c9d198824ba96534a11123bfa3 100644 (file)
@@ -3,12 +3,13 @@
 
   source file of the GNU LilyPond music typesetter
 
-  (c) 1996,  1997--1998, 1998 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+  (c) 1996--1999 Han-Wen Nienhuys <hanwen@cs.uu.nl>
 */
 
 
 #include <math.h>
 #include <limits.h>
+#include "killing-cons.tcc"
 #include "spring-spacer.hh"
 #include "p-col.hh"
 #include "debug.hh"
 #include "score-column.hh"
 #include "paper-def.hh"
 #include "colhpos.hh"
+#include "main.hh"
 
 Vector
 Spring_spacer::default_solution() const
 {
-  return try_initial_solution() ;
+  return try_initial_solution();
 }
 
 Score_column*
 Spring_spacer::scol_l (int i)
 {
-  return (Score_column*)cols_[i].pcol_l_;
+  return dynamic_cast<Score_column*>(cols_[i].pcol_l_);
 }
 
 const Real COLFUDGE=1e-3;
@@ -65,9 +67,10 @@ Spring_spacer::handle_loose_cols()
 {
   Union_find connected (cols_.size());
   Array<int> fixed;
-  for (PCursor<Idealspacing*> i (ideal_p_list_.top()); i.ok (); i++)
+  
+  for (Cons<Idealspacing> *i  = ideal_p_list_; i; i = i->next_cons_p_)
     {
-      connected.connect (i->left_i_,i->right_i_);
+      connected.connect (i->car_p_->cols_drul_[LEFT],i->car_p_->cols_drul_[RIGHT]);
     }
   for (int i = 0; i < cols_.size(); i++)
     if (cols_[i].fixed_b())
@@ -237,10 +240,11 @@ Spring_spacer::make_matrices (Matrix &quad, Vector &lin, Real &c) const
   lin.fill (0);
   c = 0;
 
-  for (PCursor<Idealspacing*> i (ideal_p_list_.top()); i.ok (); i++)
+  for (Cons<Idealspacing> *p =ideal_p_list_; p; p = p->next_cons_p_)
     {
-      int l = i->left_i_;
-      int r = i->right_i_;
+      Idealspacing *i = p->car_p_;
+      int l = i->cols_drul_[LEFT];
+      int r = i->cols_drul_[RIGHT];
 
       quad (r,r) += i->hooke_f_;
       quad (r,l) -= i->hooke_f_;
@@ -292,9 +296,10 @@ Real
 Spring_spacer::calculate_energy_f (Vector solution) const
 {
   Real e = 0.0;
-  for (PCursor<Idealspacing*> i (ideal_p_list_.top()); i.ok(); i++)
+  for (Cons<Idealspacing>*p =ideal_p_list_; p; p = p->next_cons_p_)
     {
-      e += i->energy_f(solution(i->right_i_) - solution(i->left_i_));
+      Idealspacing * i = p->car_p_;
+      e += i->energy_f(solution(i->cols_drul_[RIGHT]) - solution(i->cols_drul_[LEFT]));
     }
 
   return e;
@@ -318,16 +323,17 @@ Spring_spacer::lower_bound_solution (Column_x_positions*positions) const
 
 Spring_spacer::Spring_spacer ()
 {
+  ideal_p_list_ =0;
   energy_normalisation_f_ = 1.0;
 }
 
 void
 Spring_spacer::solve (Column_x_positions*positions) const
 {
-
   DOUT << "Spring_spacer::solve ()...";
-  Vector solution_try;
 
+  Vector solution_try;
+    
   bool constraint_satisfaction = try_initial_solution_and_tell (solution_try); 
   if  (constraint_satisfaction)
     {
@@ -335,9 +341,9 @@ Spring_spacer::solve (Column_x_positions*positions) const
       make_matrices (lp.quad_,lp.lin_, lp.const_term_);
       make_constraints (lp);
       set_fixed_cols (lp);
-
+       
       Vector solution_vec (lp.solve (solution_try));
-
+       
       positions->satisfies_constraints_b_ = check_constraints (solution_vec);
       if (!positions->satisfies_constraints_b_)
        {
@@ -352,6 +358,7 @@ Spring_spacer::solve (Column_x_positions*positions) const
     {
       positions->set_stupid_solution (solution_try);
     }
+
   DOUT << "Finished Spring_spacer::solve ()...";
 }
 
@@ -392,7 +399,7 @@ Spring_spacer::add_column (Paper_column  *col, bool fixed, Real fixpos)
 Line_of_cols
 Spring_spacer::error_pcol_l_arr() const
 {
-  Array<Paper_column*> retval;
+  Link_array<Paper_column> retval;
   for (int i=0; i< cols_.size(); i++)
     if (cols_[i].ugh_b_)
       retval.push (cols_[i].pcol_l_);
@@ -402,17 +409,27 @@ Spring_spacer::error_pcol_l_arr() const
     }
   return retval;
 }
-
+/*
+  Ugh. Should junk this.
+ */
 void
-Spring_spacer::loosen_column (int i)
+Spring_spacer::loosen_column (int idx)
 {
-  Column_info c=cols_.get (i);
-  for (PCursor<Idealspacing*> j (ideal_p_list_.top()); j.ok (); j++)
+  Column_info c=cols_.get (idx);
+
+  Cons<Idealspacing> **pp = &ideal_p_list_;
+
+  while (*pp)
     {
-      if (j->left_i_ == i|| j->right_i_ == i)
-       j.del();
+      Idealspacing *j = (*pp)->car_p_;
+      if (j->cols_drul_[LEFT] == idx|| j->cols_drul_[RIGHT] == idx)
+       {
+         delete remove_cons_p (pp);
+       }
       else
-       j++;
+       {
+         pp = &(*pp)->next_cons_p_;
+       }
     }
   c.ugh_b_ = true;
 
@@ -435,9 +452,10 @@ Spring_spacer::print() const
       DOUT << "col " << i << " ";
       cols_[i].print();
     }
-  for (PCursor<Idealspacing*> i (ideal_p_list_.top()); i.ok (); i++)
+
+  for (Cons<Idealspacing> *p =ideal_p_list_; p; p = p->next_cons_p_)
     {
-      i->print();
+      p->car_p_->print();
     }
 #endif
 }
@@ -451,12 +469,12 @@ Spring_spacer::connect (int i, int j, Real d, Real h)
 
   Idealspacing * s = new Idealspacing;
 
-  s->left_i_ = i ;
-  s->right_i_ = j;
+  s->cols_drul_[LEFT] = i ;
+  s->cols_drul_[RIGHT] = j;
   s->space_f_ = d;
   s->hooke_f_ = h;
 
-  ideal_p_list_.bottom().add (s);
+  ideal_p_list_ = new Killing_cons<Idealspacing> (s, ideal_p_list_);
 }
 
 
@@ -498,20 +516,21 @@ Spring_spacer::get_ruling_durations(Array<Moment> &shortest_playing_arr,
 
   for (int i=0; i < cols_.size(); i++)
     {
+      Score_column * sc = scol_l(i);
       Moment now = scol_l (i)->when();
       Moment shortest_playing;
       shortest_playing.set_infinite (1);
 
-      if (scol_l (i)->breakable_b_)
+      if (!sc->musical_b ())
        {
          for (int ji=i; ji >= start_context_i; ji--)
            context_shortest_arr[ji] = context_shortest;
          start_context_i = i;
          context_shortest.set_infinite (1);
        }
-      if (scol_l (i)->durations.size())
+      if (sc->durations.size())
        {
-         context_shortest = context_shortest <? scol_l(i)->durations[0];
+         context_shortest = context_shortest <? sc->durations[0];
        }
       
       // ji was j, but triggered ICE
@@ -544,11 +563,12 @@ Spring_spacer::get_ruling_durations(Array<Moment> &shortest_playing_arr,
 
 /*
   TODO: take out the refs to width
+
  */
 /**
   generate springs between columns.
 
-  TODO: This needs rethinking.
+  TODO: This needs rethinking....... 
 
   *  Spacing should take optical
   effects into account
@@ -569,14 +589,13 @@ Spring_spacer::calc_idealspacing()
   Array<Moment> context_shortest_arr;
   get_ruling_durations(shortest_playing_arr, context_shortest_arr);
 
-  Real interline_f = paper_l ()->interline_f ();
+  Real interline_f = paper_l ()->get_realvar (interline_scm_sym);
 
-
-  Array<Real> ideal_arr_;
-  Array<Real> hooke_arr_;
+  Array<Real> ideal_arr;
+  Array<Real> hooke_arr;
   for (int i=0; i < cols_.size() - 1; i++){
-    ideal_arr_.push (-1.0);
-    hooke_arr_.push (1.0);
+    ideal_arr.push (-1.0);
+    hooke_arr.push (1.0);
   }
 
   /* 
@@ -588,24 +607,21 @@ Spring_spacer::calc_idealspacing()
        {
          Real symbol_distance =cols_[i].width_[RIGHT] + 2 PT;
          Real durational_distance = 0;
-
-         
          Moment delta_t =  scol_l (i+1)->when() - scol_l (i)->when () ;
 
-
          /*
            ugh should use shortest_playing distance
          */
          if (delta_t)
            {
              Real k=  paper_l()->arithmetic_constant (context_shortest_arr[i]);
-             durational_distance =  paper_l()->duration_to_dist (delta_t,k);
+             durational_distance =  paper_l()->length_mom_to_dist (delta_t,k);
            }
          symbol_distance += -cols_[i+1].width_[LEFT];
  
 
-         ideal_arr_[i] = symbol_distance >? durational_distance;
-         hooke_arr_[i] = 1; //2.0;
+         ideal_arr[i] = symbol_distance >? durational_distance;
+         hooke_arr[i] = 1; //2.0;
        }
     }
 
@@ -632,7 +648,7 @@ Spring_spacer::calc_idealspacing()
            }
          Moment delta_t = scol_l (i+1)->when() - scol_l (i)->when ();
          Real k=  paper_l()->arithmetic_constant(context_shortest);
-         Real dist = paper_l()->duration_to_dist (shortest_playing_len, k);
+         Real dist = paper_l()->length_mom_to_dist (shortest_playing_len, k);
          dist *= (double)(delta_t / shortest_playing_len);
 
          /*
@@ -640,6 +656,7 @@ Spring_spacer::calc_idealspacing()
             
            * whitespace at the begin of the bar should be fixed at 
            (about) one interline.
+
            [Ross]:
            when spacing gets real tight, a smaller fixed value may be 
            used, so that there are two discrete amounts of whitespace 
@@ -649,43 +666,60 @@ Spring_spacer::calc_idealspacing()
            * whitespace at the end of the bar is the normal amount of 
            "hinterfleish" that would have been used, had there been
            yet another note in the bar.  
+
            [Ross]:
            some editors argue that the bar line should not take any 
            space, not to hinder the flow of music spaced around a bar 
            line.  
+
            [Ross] and [Wanske] do not suggest this, however.  Further, 
-           it introduces some spacing problems and think that it is ugly 
+           it introduces some spacing problems and think that it is ugly 
            too.
+           
            [jcn]
          */
 
          /* 
             first musical column of bar
          */
-         if (i && scol_l (i - 1)->breakable_b_)
+         if (i && !scol_l (i - 1)->musical_b ())
            {
-             // fixed: probably should set minimum (rod/spring)?
-             cols_[i-1].width_[RIGHT] += interline_f;
+             // one interline minimum at start of bar
+
+             // cols_[i].width_[RIGHT] += interline_f;
+             cols_[i].width_[RIGHT] = cols_[i].width_[RIGHT] >? interline_f;
+
              // should adjust dist too?
-             ideal_arr_[i-1] = ideal_arr_[i-1] >? (2 * interline_f);
+             ideal_arr[i-1] = ideal_arr[i-1] >? (2 * interline_f);
            }
 
          /* 
             last musical column of bar
          */
-         if (i + 1 < cols_.size () && scol_l(i+1)->breakable_b_)
+         if (i + 1 < cols_.size () && !scol_l(i+1)->musical_b ())
            {
-             // hmm, how bout?
-             dist = dist >? interline_f;
+             // two interline minimum ok for last column?
+             dist = dist >? 2 * interline_f;
 
+             // set minimum rod 
              /*
-               uhuh, this code looks fine, already?
-               someone was junking this last "hinterfleisch" whitespace?!
+               urg: simply *adding* an interline leaves big gaps at
+               end of measure in star-spangled-banner (after lyrics
+               at eom).
 
-               but this seems to be fixed now :-)
-             */
-             // set minimum rod 
-             cols_[i].width_[RIGHT] += interline_f;
+                  cols_[i].width_[RIGHT] += interline_f; // before
+
+               having a minimum of one interline solves this problem
+               in most (but not all??) cases.
+
+               for music without lyrics (esp. when set very tightly),
+               adding an interline looks good: probably because this
+               hides a bug that allows the last note's "hinterfleish"
+               to be removed (e.g., see wtk1-fugue2: that's ugly now).
+               -- jcn
+              */
+
+             cols_[i].width_[RIGHT] = cols_[i].width_[RIGHT] >? 2 * interline_f;
            }
 
          // ugh, do we need this?
@@ -695,13 +729,25 @@ Spring_spacer::calc_idealspacing()
                + interline_f / 2;
              dist = dist >? minimum;
            }
-         ideal_arr_[i] = dist;
+         ideal_arr[i] = dist;
        }
     }
 
-  for (int i=0; i < ideal_arr_.size(); i++)
+  /*
+    shorter distances should stretch less.
+
+    (and how bout
+
+      hooke[i] = 2 * max_ideal_space - ideal[i]
+
+    ?)
+  */
+  for (int i=0; i < ideal_arr.size(); i++)
+    hooke_arr[i] = 1/ideal_arr[i];
+
+  for (int i=0; i < ideal_arr.size(); i++)
     {
-      assert (ideal_arr_[i] >=0 && hooke_arr_[i] >=0);
-      connect (i, i+1, ideal_arr_[i], hooke_arr_[i]);
+      assert (ideal_arr[i] >=0 && hooke_arr[i] >=0);
+      connect (i, i+1, ideal_arr[i], hooke_arr[i]);
     }
 }