]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/spring-spacer.cc
release: 0.1.61
[lilypond.git] / lily / spring-spacer.cc
index 7684e5de5f52bd9751a8cbd62ff710b92295ba33..ac4b00b623d9118898dbb38ce321f5f38a254c1f 100644 (file)
@@ -3,7 +3,7 @@
 
   source file of the GNU LilyPond music typesetter
 
-  (c) 1996,1997 Han-Wen Nienhuys <hanwen@stack.nl>
+  (c) 1996,  1997--1998, 1998 Han-Wen Nienhuys <hanwen@stack.nl>
 */
 
 
 #include "score-column.hh"
 #include "paper-def.hh"
 #include "dimen.hh"
-#include "minterval.hh"
+#include "colhpos.hh"
+#include "main.hh"             // experimental_fietsers
 
 Vector
-Spring_spacer::default_solution()const
+Spring_spacer::default_solution() const
 {
-       return try_initial_solution() ; 
+  return try_initial_solution() ;
 }
 
 Score_column*
-Spring_spacer::scol_l(int i) 
+Spring_spacer::scol_l (int i)
 {
-    return (Score_column*)cols[i].pcol_l_;
+  return (Score_column*)cols_[i].pcol_l_;
 }
 
 const Real COLFUDGE=1e-3;
 template class P<Real>;                // ugh.
 
 bool
-Spring_spacer::contains(PCol const *w)
+Spring_spacer::contains_b (Paper_column const *w)
 {
-    for (int i=0; i< cols.size(); i++)
-       if (cols[i].pcol_l_ == w)
-           return true;
-    return false;
+  for (int i=0; i< cols_.size(); i++)
+    if (cols_[i].pcol_l_ == w)
+      return true;
+  return false;
 }
 
 
@@ -50,279 +51,374 @@ void
 Spring_spacer::OK() const
 {
 #ifndef NDEBUG
-    for (int i = 1; i < cols.size(); i++)
-       assert(cols[i].rank_i_ > cols[i-1].rank_i_);
-    for (int i = 1; i < loose_col_arr_.size(); i++)
-       assert(loose_col_arr_[i].rank_i_ > loose_col_arr_[i-1].rank_i_);
-#endif 
+  for (int i = 1; i < cols_.size(); i++)
+    assert (cols_[i].rank_i_ > cols_[i-1].rank_i_);
+  for (int i = 1; i < loose_col_arr_.size(); i++)
+    assert (loose_col_arr_[i].rank_i_ > loose_col_arr_[i-1].rank_i_);
+#endif
 }
 
 /**
-  Make sure no unconnected columns happen. 
+  Make sure no unconnected columns happen.
  */
 void
-Spring_spacer::handle_loose_cols() 
+Spring_spacer::handle_loose_cols()
 {
-    Union_find connected(cols.size());
-    Array<int> fixed;
-    for (PCursor<Idealspacing*> i(ideal_p_list_.top()); i.ok(); i++){
-       connected.connect(i->left_i_,i->right_i_);              
+  Union_find connected (cols_.size());
+  Array<int> fixed;
+  for (PCursor<Idealspacing*> i (ideal_p_list_.top()); i.ok (); i++)
+    {
+      connected.connect (i->left_i_,i->right_i_);
     }
-    for (int i = 0; i < cols.size(); i++)
-       if (cols[i].fixed())
-           fixed.push(i);
-    for (int i=1; i < fixed.size(); i++)
-       connected.connect(fixed[i-1], fixed[i]);
-
-    for (int i = cols.size(); i--; ) {
-       if (! connected.equiv(fixed[0], i)) {
-           warning("unconnected column: " + String(i));
-           loosen_column(i);
+  for (int i = 0; i < cols_.size(); i++)
+    if (cols_[i].fixed_b())
+      fixed.push (i);
+  for (int i=1; i < fixed.size(); i++)
+    connected.connect (fixed[i-1], fixed[i]);
+
+  for (int i = cols_.size(); i--;)
+    {
+      if (! connected.equiv (fixed[0], i))
+       {
+         warning (_("unconnected column: ") + String (i));
+         loosen_column (i);
        }
     }
-    OK();
+  OK();
 }
 
 
 /**
   Guess a stupid position for loose columns.  Put loose columns at
-  regular distances from enclosing calced columns 
+  regular distances from enclosing calced columns
   */
 void
-Spring_spacer::position_loose_cols(Vector &sol_vec)const
+Spring_spacer::position_loose_cols (Vector &sol_vec) const
 {
-    if (!loose_col_arr_.size())
-       return ; 
-    assert(sol_vec.dim());
-    Array<bool> fix_b_arr;
-    fix_b_arr.set_size(cols.size() + loose_col_arr_.size());
-    Real utter_right_f=-INFTY_f;
-    Real utter_left_f =INFTY_f;
-    for (int i=0; i < loose_col_arr_.size(); i++) {
-       fix_b_arr[loose_col_arr_[i].rank_i_] = false;
+  if (!loose_col_arr_.size())
+    return ;
+  assert (sol_vec.dim());
+  Array<bool> fix_b_arr;
+  fix_b_arr.set_size (cols_.size() + loose_col_arr_.size ());
+  Real utter_right_f=-infinity_f;
+  Real utter_left_f =infinity_f;
+  for (int i=0; i < loose_col_arr_.size(); i++)
+    {
+      fix_b_arr[loose_col_arr_[i].rank_i_] = false;
     }
-    for (int i=0; i < cols.size(); i++) {
-       int r= cols[i].rank_i_;
-       fix_b_arr[r] = true;
-       utter_right_f = utter_right_f >? sol_vec(i);
-       utter_left_f = utter_left_f <? sol_vec(i);
+  for (int i=0; i < cols_.size(); i++)
+    {
+      int r= cols_[i].rank_i_;
+      fix_b_arr[r] = true;
+      utter_right_f = utter_right_f >? sol_vec (i);
+      utter_left_f = utter_left_f <? sol_vec (i);
     }
-    Vector v(fix_b_arr.size());
-    int j =0;
-    int k =0;
-    for (int i=0; i < v.dim(); i++) {
-       if (fix_b_arr[i]) {
-           assert(cols[j].rank_i_ == i);
-           v(i) = sol_vec(j++);
-       } else {
-           Real left_pos_f = 
-               (j>0) ?sol_vec(j-1) : utter_left_f;
-           Real right_pos_f = 
-               (j < sol_vec.dim()) ? sol_vec(j) : utter_right_f;
-           int left_rank = (j>0) ? cols[j-1].rank_i_ : 0;
-           int right_rank = (j<sol_vec.dim()) ? cols[j].rank_i_ : sol_vec.dim();
-
-           int d_r = right_rank - left_rank;
-           Colinfo loose=loose_col_arr_[k++];
-           int r = loose.rank_i_ ;
-           assert(r > left_rank && r < right_rank);
-
-           v(i) =  (r - left_rank)*left_pos_f/ d_r + 
-               (right_rank - r) *right_pos_f /d_r;
+  Vector v (fix_b_arr.size());
+  int j =0;
+  int k =0;
+  for (int i=0; i < v.dim(); i++)
+    {
+      if (fix_b_arr[i])
+       {
+         assert (cols_[j].rank_i_ == i);
+         v (i) = sol_vec (j++);
+       }
+      else
+       {
+         Real left_pos_f =
+           (j>0) ?sol_vec (j-1) : utter_left_f;
+         Real right_pos_f =
+           (j < sol_vec.dim()) ? sol_vec (j) : utter_right_f;
+         int left_rank = (j>0) ? cols_[j-1].rank_i_ : 0;
+         int right_rank = (j<sol_vec.dim()) ? cols_[j].rank_i_ : sol_vec.dim ();
+
+         int d_r = right_rank - left_rank;
+         Colinfo loose=loose_col_arr_[k++];
+         int r = loose.rank_i_ ;
+         assert (r > left_rank && r < right_rank);
+
+         v (i) =  (r - left_rank)*left_pos_f/ d_r +
+           (right_rank - r) *right_pos_f /d_r;
        }
     }
-    sol_vec = v;
+  sol_vec = v;
 }
+
 bool
-Spring_spacer::check_constraints(Vector v) const 
+Spring_spacer::check_constraints (Vector v) const
 {
-    int dim=v.dim();
-    assert(dim == cols.size());
-    
-    for (int i=0; i < dim; i++) {
-
-       if (cols[i].fixed()&&
-           abs(cols[i].fixed_position() - v(i)) > COLFUDGE) 
-           return false;
-       
-       if (!i) 
-           continue;
-       
-       Real mindist=cols[i-1].minright()
-           +cols[i].minleft();
-
-       // ugh... compares
-       Real dif =v(i) - v(i-1)- mindist;
-       bool b = (dif > - COLFUDGE);
-       
-
-       if (!b)
-           return false;
+  int dim=v.dim();
+  assert (dim == cols_.size());
+  DOUT << "checking " << v;
+  for (int i=0; i < dim; i++)
+    {
+      if (cols_[i].fixed_b() &&
+         abs (cols_[i].fixed_position() - v (i)) > COLFUDGE)
+       {
+         DOUT << "Fixpos broken\n";
+         return false;
+       }
+      Array<Spacer_rod> const &rods (cols_[i].rods_[RIGHT]);
+      for (int j =0; j < rods.size (); j++)
+       {
+         int other =rods[j].other_idx_;
+         Real diff =v (other) - v (i) ;
+         if (COLFUDGE +diff <  rods[j].distance_f_)
+           {
+             DOUT << "i, other_i: " << i << "  " << other << "\n";
+             DOUT << "dist, minimal = " << diff <<" "
+                  << rods[j].distance_f_<<'\n';
+             return false;
+           }
+       }
 
     }
-    return true;
+  return true;
 }
 
-bool
-Spring_spacer::check_feasible() const
-{
-    Vector sol(try_initial_solution());
-    return check_constraints(sol);     
-}
-
-/// generate a solution which obeys the min distances and fixed positions
+/** try to generate a solution which obeys the min distances and fixed positions
+ */
 Vector
 Spring_spacer::try_initial_solution() const
 {
-    int dim=cols.size();
-    Vector initsol(dim);
-    for (int i=0; i < dim; i++) {
-       if (cols[i].fixed()) {
-           initsol(i)=cols[i].fixed_position();        
-
-           if (i > 0) {
-               Real r =initsol(i-1)  + cols[i-1].minright();
-               if (initsol(i) < r ) {
-                   warning("overriding fixed position");
-                   initsol(i) =r;
-               } 
-           }
-               
-       } else {
-           Real mindist=cols[i-1].minright()
-               +cols[i].minleft();
-           if (mindist < 0.0)
-               warning("Excentric column");
-           initsol(i)=initsol(i-1)+mindist;
-       }       
+  Vector v;
+  if (!try_initial_solution_and_tell (v))
+    {
+      warning ("I'm too fat; call Oprah");
     }
+  return v;
 
-    return initsol;
 }
 
-
-
-Vector
-Spring_spacer::find_initial_solution() const
+bool
+Spring_spacer::try_initial_solution_and_tell (Vector &v) const
 {
-    Vector v(try_initial_solution());     
-    assert(check_constraints(v));
-    return v;
+  int dim=cols_.size();
+  bool succeeded = true;
+  Vector initsol (dim);
+
+  assert (cols_[0].fixed_b ());
+  DOUT << "fixpos 0 " << cols_[0].fixed_position ();
+  for (int i=0; i < dim; i++)
+    {
+      Real min_x = i ?  initsol (i-1) : cols_[0].fixed_position ();
+      Array<Spacer_rod> const &sr_arr(cols_[i].rods_[LEFT]);
+      for (int j=0; j < sr_arr.size (); j++)
+       {
+         min_x = min_x >? (initsol (sr_arr[j].other_idx_) + sr_arr[j].distance_f_);
+       }
+      initsol (i) = min_x;
+      
+      if (cols_[i].fixed_b())
+       {
+         initsol (i)=cols_[i].fixed_position();
+         if (initsol (i) < min_x )
+           {
+             DOUT << "failing: init, min : " << initsol (i) << " " << min_x << "\n";
+             initsol (i) = min_x;
+             succeeded = false;
+           }
+       }
+    }
+  v = initsol;
+  
+  DOUT << "tried and told solution: " << v;
+  if (!succeeded)
+    DOUT << "(failed)\n";
+  return succeeded;
 }
 
+
+
 // generate the matrices
 void
-Spring_spacer::make_matrices(Matrix &quad, Vector &lin, Real &c) const
+Spring_spacer::make_matrices (Matrix &quad, Vector &lin, Real &c) const
 {
-    quad.fill(0);
-    lin.fill(0);
-    c = 0;
-    
-    for (PCursor<Idealspacing*> i(ideal_p_list_.top()); i.ok(); i++) {
-       int l = i->left_i_;
-       int r = i->right_i_;
-
-       quad(r,r) += i->hooke_f_;
-       quad(r,l) -= i->hooke_f_;
-       quad(l,r) -= i->hooke_f_;
-       quad(l,l) += i->hooke_f_;
-
-       lin(r) -= i->space_f_*i->hooke_f_;
-       lin(l) += i->space_f_*i->hooke_f_;
-
-       c += sqr(i->space_f_);
+  quad.fill (0);
+  lin.fill (0);
+  c = 0;
+
+  for (PCursor<Idealspacing*> i (ideal_p_list_.top()); i.ok (); i++)
+    {
+      int l = i->left_i_;
+      int r = i->right_i_;
+
+      quad (r,r) += i->hooke_f_;
+      quad (r,l) -= i->hooke_f_;
+      quad (l,r) -= i->hooke_f_;
+      quad (l,l) += i->hooke_f_;
+
+      lin (r) -= i->space_f_*i->hooke_f_;
+      lin (l) += i->space_f_*i->hooke_f_;
+
+      c += sqr (i->space_f_);
     }
+  // experimental
+  if (quad.dim() > 10)
+    quad.set_band();
+  
+
 }
 
+void
+Spring_spacer::set_fixed_cols (Mixed_qp &qp) const
+{
+  for (int j=0; j < cols_.size(); j++)
+    if (cols_[j].fixed_b())
+      qp.add_fixed_var (j,cols_[j].fixed_position());
+} 
+
 // put the constraints into the LP problem
 void
-Spring_spacer::make_constraints(Mixed_qp& lp) const
-{    
-    int dim=cols.size();
-    for (int j=0; j < dim; j++) {
-       Colinfo c=cols[j];
-       if (c.fixed()) {
-           lp.add_fixed_var(j,c.fixed_position());         
-       }
-       if (j > 0){
-           Vector c1(dim);
-           
-           c1(j)=1.0 ;
-           c1(j-1)=-1.0 ;
-           lp.add_inequality_cons(c1, cols[j-1].minright() +
-                                  cols[j].minleft());
+Spring_spacer::make_constraints (Mixed_qp& lp) const
+{
+  int dim=cols_.size();
+  
+  for (int j=0; j < dim -1; j++)
+    {
+      Array<Spacer_rod> const&rod_arr (cols_[j].rods_[RIGHT]);
+      for (int i = 0; i < rod_arr.size (); i++)
+       {
+         Vector c1(dim);
+         c1(rod_arr[i].other_idx_)=1.0 ;
+         c1(j)=-1.0 ;
+
+         lp.add_inequality_cons (c1, rod_arr[i].distance_f_);
        }
     }
 }
 
-Array<Real>
-Spring_spacer::solve() const
+
+Real
+Spring_spacer::calculate_energy_f (Vector solution) const
 {
-    assert(check_feasible());
-
-    Mixed_qp lp(cols.size());
-    make_matrices(lp.quad,lp.lin, lp.const_term);
-    make_constraints(lp);    
-    Vector start=find_initial_solution();    
-    Vector sol(lp.solve(start));
-    if (!check_constraints(sol)) {
-       WARN << "solution doesn't satisfy constraints.\n" ;
+  Real e = 0.0;
+  for (PCursor<Idealspacing*> i (ideal_p_list_.top()); i.ok(); i++)
+    {
+      e += i->energy_f(solution(i->right_i_) - solution(i->left_i_));
     }
-    Real energy_f =lp.eval(sol);
-    position_loose_cols(sol);
 
-    Array<Real> posns(sol);
+  return e;
+}
+void
+Spring_spacer::lower_bound_solution (Col_hpositions*positions) const
+{
+  Mixed_qp lp (cols_.size());
+  make_matrices (lp.quad_,lp.lin_, lp.const_term_);
+  set_fixed_cols (lp);
+
+  Vector start (cols_.size());
+  start.fill (0.0);
+  Vector solution_vec (lp.solve (start));
+
+  DOUT << "Lower bound sol: " << solution_vec;
+  positions->energy_f_ = calculate_energy_f (solution_vec);
+  positions->config = solution_vec;
+  positions->satisfies_constraints_b_ = check_constraints (solution_vec);
+}
+
+void
+Spring_spacer::solve (Col_hpositions*positions) const
+{
 
-    posns.push(energy_f);
-    return posns;
+  DOUT << "Spring_spacer::solve ()...";
+  Vector solution_try;
+
+  bool constraint_satisfaction = try_initial_solution_and_tell (solution_try); 
+  if  (constraint_satisfaction)
+    {
+      Mixed_qp lp (cols_.size());
+      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_)
+       {
+         WARN << _("solution doesn't satisfy constraints.\n") ;
+       }
+      position_loose_cols (solution_vec);
+      positions->energy_f_ = calculate_energy_f (solution_vec);
+      positions->config = solution_vec;
+      positions->error_col_l_arr_ = error_pcol_l_arr();
+    }
+  else
+    {
+      positions->set_stupid_solution (solution_try);
+    }
+  DOUT << "Finished Spring_spacer::solve ()...";
 }
 
 /**
-    add one column to the problem.
-*/    
+  add one column to the problem.
+*/
 void
-Spring_spacer::add_column(PCol  *col, bool fixed, Real fixpos)
+Spring_spacer::add_column (Paper_column  *col, bool fixed, Real fixpos)
 {
-    Colinfo c(col,(fixed)? &fixpos :  0);
-    if (cols.size())
-       c.rank_i_ = cols.top().rank_i_+1;
-    else
-       c.rank_i_ = 0;
-    cols.push(c);
+  Colinfo c (col,(fixed)? &fixpos :  0);
+  int this_rank =  cols_.size();
+  c.rank_i_ = this_rank;
+  
+  for (int i=0; i < col->minimal_dists_arr_drul_[LEFT].size (); i++)
+    {
+      Column_rod &cr = col->minimal_dists_arr_drul_[LEFT][i];
+      int left_idx = cr.other_l_->rank_i () - cols_[0].pcol_l_->rank_i ();
+      if (left_idx < 0)
+       continue;
+
+      if (cols_[left_idx].pcol_l_ != cr.other_l_)
+       continue;
+
+      Spacer_rod l_rod;
+      l_rod.distance_f_ = cr.distance_f_;
+      l_rod.other_idx_ = left_idx;
+      c.rods_[LEFT].push (l_rod);
+
+      Spacer_rod r_rod;
+      r_rod.distance_f_ = cr.distance_f_;
+      r_rod.other_idx_ = this_rank;
+      cols_[left_idx].rods_[RIGHT].push (r_rod);
+    }
+  
+  cols_.push (c);
 }
 
-Array<PCol*>
-Spring_spacer::error_pcol_l_arr()const
+Line_of_cols
+Spring_spacer::error_pcol_l_arr() const
 {
-    Array<PCol*> retval;
-    for (int i=0; i< cols.size(); i++)
-       if (cols[i].ugh_b_)
-           retval.push(cols[i].pcol_l_);
-    for (int i=0;  i < loose_col_arr_.size(); i++) {
-       retval.push(loose_col_arr_[i].pcol_l_);
+  Array<Paper_column*> retval;
+  for (int i=0; i< cols_.size(); i++)
+    if (cols_[i].ugh_b_)
+      retval.push (cols_[i].pcol_l_);
+  for (int i=0;  i < loose_col_arr_.size(); i++)
+    {
+      retval.push (loose_col_arr_[i].pcol_l_);
     }
-    return retval;
+  return retval;
 }
 
 void
-Spring_spacer::loosen_column(int i)
+Spring_spacer::loosen_column (int i)
 {
-    Colinfo c=cols.get(i);
-    for (PCursor<Idealspacing*> j(ideal_p_list_.top()); j.ok(); j++){
-       if (j->left_i_ == i|| j->right_i_ == i)
-           j.del();
-       else
-           j++;
+  Colinfo c=cols_.get (i);
+  for (PCursor<Idealspacing*> j (ideal_p_list_.top()); j.ok (); j++)
+    {
+      if (j->left_i_ == i|| j->right_i_ == i)
+       j.del();
+      else
+       j++;
     }
-    c.ugh_b_ = true;
-    
-    int j=0;
-    for (; j < loose_col_arr_.size(); j++) {
-       if (loose_col_arr_[j].rank_i_ > c.rank_i_)
-           break;
+  c.ugh_b_ = true;
+
+  int j=0;
+  for (; j < loose_col_arr_.size(); j++)
+    {
+      if (loose_col_arr_[j].rank_i_ > c.rank_i_)
+       break;
     }
-    loose_col_arr_.insert(c,j);
+  loose_col_arr_.insert (c,j);
 }
 
 
@@ -330,253 +426,275 @@ void
 Spring_spacer::print() const
 {
 #ifndef NPRINT
-    for (int i=0; i < cols.size(); i++) {
-       mtor << "col " << i<<' ';
-       cols[i].print();
+  for (int i=0; i < cols_.size(); i++)
+    {
+      DOUT << "col " << i<<' ';
+      cols_[i].print();
     }
-    for (PCursor<Idealspacing*> i(ideal_p_list_.top()); i.ok(); i++){
-       i->print();
+  for (PCursor<Idealspacing*> i (ideal_p_list_.top()); i.ok (); i++)
+    {
+      i->print();
     }
 #endif
-    
 }
 
 
 void
-Spring_spacer::connect(int i, int j, Real d, Real h)
+Spring_spacer::connect (int i, int j, Real d, Real h)
 {
-    Idealspacing * s = new Idealspacing;
-    s->left_i_ = i;
-    s->right_i_ = j;
-    s->space_f_ = d;
-    s->hooke_f_ = h;
-    
-    ideal_p_list_.bottom().add(s);
+  assert(d >= 0 && d <= 100 CM);
+  assert(h >=0);
+
+  Idealspacing * s = new Idealspacing;
+
+  s->left_i_ = i ;
+  s->right_i_ = j;
+  s->space_f_ = d;
+  s->hooke_f_ = h;
+
+  ideal_p_list_.bottom().add (s);
 }
 
-/**
-  walk through all durations in all Score_columns
- */
-struct Durations_iter
-{
-    Spring_spacer * sp_l_;
-    int col_i_;
-    int d_i_;
-    
-    Durations_iter(Spring_spacer*);
-
-    Moment duration()const;
-    Moment when()const;
-    
-    bool ok()const;
-    void next();
-};
-
-Durations_iter::Durations_iter(Spring_spacer * s)
+
+
+
+void
+Spring_spacer::prepare()
 {
-    col_i_ =0;
-    d_i_ =0;           // ugh
-    
-    sp_l_ = s;
-    if (! sp_l_->scol_l(col_i_)->durations.size() )
-       next();
+  DOUT << "Preparing..";
+  calc_idealspacing();
+  handle_loose_cols();
+  print();
+  DOUT << "finished preparing.\n";
 }
 
-Moment
-Durations_iter::duration() const 
+Line_spacer*
+Spring_spacer::constructor()
 {
-    return sp_l_->scol_l(col_i_)->durations[d_i_];
+  return new Spring_spacer;
 }
 
-bool
-Durations_iter::ok()const{
-    return col_i_ < sp_l_->cols.size();
-}
 
-Moment
-Durations_iter::when()const{
-    return sp_l_->scol_l(col_i_)->when();
-}
 
+/**
+  get the shortest_playing running note at a time. */
 void
-Durations_iter::next()
+Spring_spacer::get_ruling_durations(Array<Moment> &shortest_playing_arr,
+                                   Array<Moment> &context_shortest_arr)
 {
-    d_i_ ++;
-    while ( col_i_ < sp_l_->cols.size() 
-           && d_i_ >= sp_l_->scol_l(col_i_)->durations.size()){
-       col_i_ ++;
-       d_i_ =0;
+  for (int i=0; i < cols_.size(); i++)
+    {
+      scol_l (i)->preprocess();
+      scol_l (i)->print ();
     }
+  int start_context_i=0;
+  Moment context_shortest;
+  context_shortest.set_infinite (1);
+  context_shortest_arr.set_size(cols_.size());
+
+  for (int i=0; i < cols_.size(); i++)
+    {
+      Moment now = scol_l (i)->when();
+      Moment shortest_playing;
+      shortest_playing.set_infinite (1);
+
+      if (scol_l (i)->breakable_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())
+       {
+         context_shortest = context_shortest <? scol_l(i)->durations[0];
+       }
+      
+      // ji was j, but triggered ICE
+      for (int ji=i+1; ji --;)
+       {
+         if (scol_l(ji)->durations.size() &&
+             now - scol_l(ji)->when() >= shortest_playing)
+           break;
+
+         for (int k =  scol_l (ji)->durations.size();
+              k-- && scol_l(ji)->durations[k] + scol_l(ji)->when() > now;
+              )
+           {
+             shortest_playing = shortest_playing <? scol_l(ji)->durations[k];
+           }
+       }
+      shortest_playing_arr.push(shortest_playing);
+    }
+
+#ifndef NPRINT
+  DOUT << "shortest_playing/:[ ";
+  for (int i=0; i < shortest_playing_arr.size(); i++)
+    {
+      DOUT << shortest_playing_arr[i] << " ";
+      DOUT << context_shortest_arr[i] << ", ";
+    }
+  DOUT << "]\n";
+#endif
 }
 
-       
+/*
+  TODO: take out the refs to width
+ */
 /**
   generate springs between columns.
 
-  UNDER DESTRUCTION
-  
   TODO: This needs rethinking.  Spacing should take optical
-  effects into account, and should be local (measure wide)
+  effects into account
 
-  The algorithm is taken from : 
+  The algorithm is taken from :
 
   John S. Gourlay. ``Spacing a Line of Music,'' Technical Report
   OSU-CISRC-10/87-TR35, Department of Computer and Information
   Science, The Ohio State University, 1987.
-  
+
   */
 void
 Spring_spacer::calc_idealspacing()
 {
-    for (int i=0; i < cols.size(); i++) 
-       scol_l(i)->preprocess();
-    
-    /* get the shortest running note at a time. */
-    Array<Moment> shortest_arr_;
+  Array<Moment> shortest_playing_arr;
+  Array<Moment> context_shortest_arr;
+  get_ruling_durations(shortest_playing_arr, context_shortest_arr);
+
+  Real interline_f = paper_l ()->interline_f ();
+  Real nw_f = paper_l ()->note_width ();
+
+  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);
+  }
+
+  /* 
+     First do all non-musical columns
+  */
+  for (int i=0; i < cols_.size(); i++)
     {
-       Durations_iter d_iter(this);
-       for (int i=0; i < cols.size(); i++) {
-           Moment now = scol_l(i)->when();
-           while (  d_iter.ok() && now >= d_iter.when() ) {
-               if ( now < d_iter.when() + d_iter.duration())
-                   break;
-               d_iter.next();
-           }
-           if ( d_iter.ok() && now >= d_iter.when()) {
-               Durations_iter d2 = d_iter;
-               Moment shortest = (Real)INT_MAX; //ugh INFTY;
-               while (d2.ok() && d2.when() <= now) {
-                   shortest = shortest <? d2.duration();
-                   d2.next();
-               }
-               shortest_arr_.push( shortest );
-           } else
-               shortest_arr_.push(0);
+      if (!scol_l (i)->musical_b() && i+1 < cols_.size())
+       {
+         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 () ;
+
+         Real k=  paper_l()->arithmetic_constant (context_shortest_arr[i]);
+         /*
+           ugh should use shortest_playing distance
+         */
+         if (delta_t)
+           durational_distance =  paper_l()->duration_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;
        }
-       
     }
-#ifndef NPRINT
-    mtor << "shortest:[ ";
-    for (int i=0; i < shortest_arr_.size(); i++)
-       mtor << shortest_arr_[i] << " ";
-    mtor << "]\n";
-#endif
-  
-    Array<Real> ideal_arr_;
-    Array<Real> hooke_arr_;    
-    for (int i=0; i < cols.size(); i++){
-       ideal_arr_.push(  -1.0);
-       hooke_arr_.push(1.0);
-    }
-    
-    for (int i=0; i < cols.size(); i++) {
-       if ( !scol_l(i)->musical_b()) {
-           ideal_arr_[i] = cols[i].minright() + 2 PT;
-           hooke_arr_[i] = 2.0;
-           if (i+1 < cols.size()) {
-               Moment delta_t =  scol_l(i+1)->when() - scol_l(i)->when() ;
-               Real dist = delta_t ? paper_l()->duration_to_dist(delta_t) : 0;
-               if (delta_t && dist > ideal_arr_[i])
-                   ideal_arr_[i] = dist;
+
+  /* 
+     Then musicals
+  */
+  for (int i=0; i < cols_.size(); i++)
+    {
+      if (scol_l (i)->musical_b())
+       {
+         Moment shortest_playing_len = shortest_playing_arr[i];
+         Moment context_shortest = context_shortest_arr[i];
+         if (! shortest_playing_len)
+           {
+             warning (_("Can't find a ruling note at ")
+                      +scol_l (i)->when().str ());
+             shortest_playing_len = 1;
            }
-       }
-    }
-    for (int i=0; i < cols.size(); i++) {
-       if (scol_l(i)->musical_b()) {
-           Moment shortest_len = shortest_arr_[i];
-           if ( ! shortest_len ) {
-               warning( "Can't find a ruling note at " 
-                        +String( scol_l(i)->when()));
-               shortest_len = 1;
+         if (! context_shortest)
+           {
+             warning(_("No minimum in measure at ")
+                     + scol_l (i)->when().str ());
+             context_shortest = 1;
+           }
+         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);
+         dist *= (double)(delta_t / shortest_playing_len);
+
+         /*
+           According to [Ross] and [Wanske], and from what i've seen:
+            
+           * 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 
+           possible at the begin of a bar; but this is not implemented 
+           right now.
+            
+           * 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 
+           too.
+           [jcn]
+         */
+
+         /* 
+            first musical column of bar
+         */
+         if (i && scol_l (i - 1)->breakable_b_)
+           {
+             // fixed: probably should set minimum (rod/spring)?
+             cols_[i-1].width_[RIGHT] += interline_f;
+             // should adjust dist too?
+             ideal_arr_[i-1] = ideal_arr_[i-1] >? interline_f;
            }
-           Moment delta_t = scol_l(i+1)->when() - scol_l(i)->when();
-           Real dist = paper_l()->duration_to_dist(shortest_len);
-           dist *= delta_t / shortest_len;
-           if (!scol_l(i+1)->musical_b() ) {
-
-               if (ideal_arr_[i+1] + cols[i+1].minleft() < dist) {
-                   ideal_arr_[i+1] = dist/2 + cols[i+1].minleft();
-                   hooke_arr_[i+1] =1.0;
-               } 
-               ideal_arr_[i] = dist/2;
-           } else
-               ideal_arr_[i] = dist;
-       }
-    }
-
-    for (int i=0; i < ideal_arr_.size()-1; i++) {
-       assert (ideal_arr_[i] >=0 && hooke_arr_[i] >=0);
-       connect(i, i+1, ideal_arr_[i], hooke_arr_[i]);
-    }
-}
 
+         /* 
+            last musical column of bar
+         */
+         if (i + 1 < cols_.size () && scol_l(i+1)->breakable_b_)
+           {
+             // hmm, how bout?
+             dist = dist >? interline_f;
 
+             /*
+               uhuh, this code looks fine, already?
+               someone was junking this last "hinterfleisch" whitespace?!
 
-void
-Spring_spacer::prepare()
-{
-    calc_idealspacing();
-    handle_loose_cols();
-    print();
-}
+               but this seems to be fixed now :-)
+             */
+             // set minimum rod 
+             cols_[i].width_[RIGHT] += interline_f;
+           }
 
-Line_spacer*
-Spring_spacer::constructor() 
-{
-    return new Spring_spacer;
-}
-   
-#if 0
-void obsolete()
-{
-    for (int i=0; i < cols.size(); i++) {
-       if (!scol_l(i)->used_b())
-           continue;
-       
-       
-       int j = i+1;
-
-       if (scol_l(i)->musical_b()) {
-           assert ( j < cols.size());
-           
-           for (int n=0; n < scol_l(i)->durations.size(); n++) {
-               Moment d = scol_l(i)->durations[n];
-               Real dist = paper_l()->duration_to_dist(d);
-               Real strength =  scol_l(i)->durations[0]/scol_l(i)->durations[n];
-               assert(strength <= 1.0);
-               
-               while (j < cols.size()) {
-                   if (scol_l(j)->used_b() 
-                       && scol_l(j)->when() >= d + scol_l(i)->when() )
-                       break;
-                   j++;
-               }
-               if ( j < cols.size() ){
-                   Moment delta_desired = scol_l(j)->when() - (d+scol_l(i)->when());
-                   dist += paper_l()->duration_to_dist(delta_desired);
-                   if (scol_l(j)->musical_b()) {
-                       dist += cols[j].minleft() + 2 PT;
-                   }
-                   connect(i, j, dist, strength);
-               }
+         // ugh, do we need this?
+         if (i < cols_.size () - 1 && !scol_l (i + 1)->musical_b ())
+           {
+             Real minimum = -cols_[i + 1].width_[LEFT] + cols_[i].width_[RIGHT]
+               + interline_f / 2;
+             dist = dist >? minimum;
            }
-       } else if (j < cols.size()) {
-           while  (!scol_l(j)->used_b())
-               j++;
-           
-           /* attach i to the next column in use. This exists, since
-             the last col is breakable, and therefore in use
-             */
-           
-           Moment d = scol_l(j)->when() - scol_l(i)->when();
-           Real minimal_f = cols[i].minright()  +cols[j].minleft() + 2 PT;
-           Real durdist_f = (d) ? paper_l()->duration_to_dist(d) : 0; // todo
-           
-           connect(i, j, minimal_f <? durdist_f, (d) ? 1.0:1.0);
+
+          // ugh: never let columns touch... try to set over here...
+         // ugh: use j iso i triggers ice in gcc-2.7.2.3 
+          cols_[i].width_[LEFT] -= nw_f / 4;
+         ideal_arr_[i] = dist;
        }
-       // !j.ok() might hold if we're at the last col.
+    }
+
+  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]);
     }
 }
-#endif