]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/spring-spacer.cc
patch::: 1.1.38.jcn1: Cons
[lilypond.git] / lily / spring-spacer.cc
index 6dc6e441be18b252cf7b92f3881175ba99186832..4b7c39b5b59748c9d198824ba96534a11123bfa3 100644 (file)
@@ -3,45 +3,46 @@
 
   source file of the GNU LilyPond music typesetter
 
-  (c) 1996,1997 Han-Wen Nienhuys <hanwen@stack.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 "dimensions.hh"
 #include "qlp.hh"
 #include "unionfind.hh"
 #include "idealspacing.hh"
 #include "pointer.tcc"
 #include "score-column.hh"
 #include "paper-def.hh"
-#include "dimen.hh"
 #include "colhpos.hh"
-#include "main.hh"             // experimental_fietsers
+#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;
 template class P<Real>;                // ugh.
 
 bool
-Spring_spacer::contains (Paper_column const *w)
+Spring_spacer::contains_b (Paper_column const *w)
 {
-  for (int i=0; i< cols.size(); i++)
-    if (cols[i].pcol_l_ == w)
+  for (int i=0; i< cols_.size(); i++)
+    if (cols_[i].pcol_l_ == w)
       return true;
   return false;
 }
@@ -51,8 +52,8 @@ 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 < 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
@@ -64,23 +65,24 @@ Spring_spacer::OK() const
 void
 Spring_spacer::handle_loose_cols()
 {
-  Union_find connected (cols.size());
+  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())
+  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--;)
+  for (int i = cols_.size(); i--;)
     {
       if (! connected.equiv (fixed[0], i))
        {
-         warning (_("unconnected column: ") + String (i));
+         warning (_f ("unconnected column: %d", i));
          loosen_column (i);
        }
     }
@@ -99,16 +101,16 @@ Spring_spacer::position_loose_cols (Vector &sol_vec) const
     return ;
   assert (sol_vec.dim());
   Array<bool> fix_b_arr;
-  fix_b_arr.set_size (cols.size() + loose_col_arr_.size ());
+  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++)
+  for (int i=0; i < cols_.size(); i++)
     {
-      int r= cols[i].rank_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);
@@ -120,7 +122,7 @@ Spring_spacer::position_loose_cols (Vector &sol_vec) const
     {
       if (fix_b_arr[i])
        {
-         assert (cols[j].rank_i_ == i);
+         assert (cols_[j].rank_i_ == i);
          v (i) = sol_vec (j++);
        }
       else
@@ -129,11 +131,11 @@ Spring_spacer::position_loose_cols (Vector &sol_vec) const
            (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 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++];
+         Column_info loose=loose_col_arr_[k++];
          int r = loose.rank_i_ ;
          assert (r > left_rank && r < right_rank);
 
@@ -148,86 +150,88 @@ bool
 Spring_spacer::check_constraints (Vector v) const
 {
   int dim=v.dim();
-  assert (dim == cols.size());
-
+  assert (dim == cols_.size());
+  DOUT << "checking " << v;
   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].width_[RIGHT]
-       -cols[i].width_[LEFT];
-
-      // ugh... compares
-      Real dif =v (i) - v (i-1)- mindist;
-      bool b = (dif > - COLFUDGE);
-
-
-      if (!b)
-       return false;
+      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;
 }
 
-bool
-Spring_spacer::check_feasible() const
+/** try to generate a solution which obeys the min distances and fixed positions
+ */
+Vector
+Spring_spacer::try_initial_solution() const
 {
-  Vector sol (try_initial_solution());
-  return check_constraints (sol);
+  Vector v;
+  if (!try_initial_solution_and_tell (v))
+    {
+      warning (_ ("I'm too fat; call Oprah"));
+    }
+  return v;
+
 }
 
-/// generate a solution which obeys the min distances and fixed positions
-Vector
-Spring_spacer::try_initial_solution() const
+bool
+Spring_spacer::try_initial_solution_and_tell (Vector &v) const
 {
-  int dim=cols.size();
+  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++)
     {
-      if (cols[i].fixed())
+      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++)
        {
-         initsol (i)=cols[i].fixed_position();
-
-         if (i > 0)
-           {
-             Real r =initsol (i-1)  + cols[i-1].width_[RIGHT];
-             if (initsol (i) < r)
-               {
-                 warning (_("overriding fixed position"));
-                 initsol (i) =r;
-               }
-           }
-
+         min_x = min_x >? (initsol (sr_arr[j].other_idx_) + sr_arr[j].distance_f_);
        }
-      else
+      initsol (i) = min_x;
+      
+      if (cols_[i].fixed_b())
        {
-         Real mindist=cols[i-1].width_[RIGHT]
-           - cols[i].width_[LEFT];
-         if (mindist < 0.0)
-           warning (_("Excentric column"));
-         initsol (i)=initsol (i-1)+mindist;
+         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;
+           }
        }
     }
-
-  return initsol;
+  v = initsol;
+  
+  DOUT << "tried and told solution: " << v;
+  if (!succeeded)
+    DOUT << "(failed)\n";
+  return succeeded;
 }
 
 
 
-Vector
-Spring_spacer::find_initial_solution() const
-{
-  Vector v (try_initial_solution());
-  assert (check_constraints (v));
-  return v;
-}
-
 // generate the matrices
 void
 Spring_spacer::make_matrices (Matrix &quad, Vector &lin, Real &c) const
@@ -236,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_;
@@ -251,34 +256,37 @@ Spring_spacer::make_matrices (Matrix &quad, Vector &lin, Real &c) const
 
       c += sqr (i->space_f_);
     }
+
+  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())
-      qp.add_fixed_var (j,cols[j].fixed_position());
-
-
-}
+  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++)
+  int dim=cols_.size();
+  
+  for (int j=0; j < dim -1; j++)
     {
-      Colinfo c=cols[j];
-      if (j > 0)
+      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 ;
 
-         c1(j)=1.0 ;
-         c1(j-1)=-1.0 ;
-         lp.add_inequality_cons (c1,
-                                 cols[j-1].width_[RIGHT] - cols[j].width_[LEFT]);
+         lp.add_inequality_cons (c1, rod_arr[i].distance_f_);
        }
     }
 }
@@ -288,52 +296,70 @@ 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;
 }
 void
-Spring_spacer::lower_bound_solution (Col_hpositions*positions) const
+Spring_spacer::lower_bound_solution (Column_x_positions*positions) const
 {
-  Mixed_qp lp (cols.size());
-  make_matrices (lp.quad,lp.lin, lp.const_term);
+  Mixed_qp lp (cols_.size());
+  make_matrices (lp.quad_,lp.lin_, lp.const_term_);
   set_fixed_cols (lp);
 
-  Vector start (cols.size());
+  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
+Spring_spacer::Spring_spacer ()
 {
-  assert (check_feasible());
-
-  Mixed_qp lp (cols.size());
-  make_matrices (lp.quad,lp.lin, lp.const_term);
-  make_constraints (lp);
-  set_fixed_cols (lp);
-  Vector start=find_initial_solution();
-  Vector solution_vec (lp.solve (start));
+  ideal_p_list_ =0;
+  energy_normalisation_f_ = 1.0;
+}
 
+void
+Spring_spacer::solve (Column_x_positions*positions) const
+{
+  DOUT << "Spring_spacer::solve ()...";
 
-  positions->satisfies_constraints_b_ = check_constraints (solution_vec);
-  if (!positions->satisfies_constraints_b_)
+  Vector solution_try;
+    
+  bool constraint_satisfaction = try_initial_solution_and_tell (solution_try); 
+  if  (constraint_satisfaction)
     {
-      WARN << _("solution doesn't satisfy constraints.\n") ;
+      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);
     }
-  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();
 
+  DOUT << "Finished Spring_spacer::solve ()...";
 }
 
 /**
@@ -342,38 +368,68 @@ Spring_spacer::solve (Col_hpositions*positions) const
 void
 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);
+  Column_info 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);
 }
 
 Line_of_cols
 Spring_spacer::error_pcol_l_arr() const
 {
-  Array<Paper_column*> retval;
-  for (int i=0; i< cols.size(); i++)
-    if (cols[i].ugh_b_)
-      retval.push (cols[i].pcol_l_);
+  Link_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;
 }
-
+/*
+  Ugh. Should junk this.
+ */
 void
-Spring_spacer::loosen_column (int i)
+Spring_spacer::loosen_column (int idx)
 {
-  Colinfo 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;
 
@@ -391,14 +447,15 @@ void
 Spring_spacer::print() const
 {
 #ifndef NPRINT
-  for (int i=0; i < cols.size(); i++)
+  for (int i=0; i < cols_.size(); i++)
     {
-      DOUT << "col " << i<<' ';
-      cols[i].print();
+      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
 }
@@ -411,12 +468,13 @@ Spring_spacer::connect (int i, int j, Real d, Real h)
   assert(h >=0);
 
   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_);
 }
 
 
@@ -425,9 +483,11 @@ Spring_spacer::connect (int i, int j, Real d, Real h)
 void
 Spring_spacer::prepare()
 {
+  DOUT << "Preparing..";
   calc_idealspacing();
   handle_loose_cols();
   print();
+  DOUT << "finished preparing.\n";
 }
 
 Line_spacer*
@@ -444,29 +504,35 @@ void
 Spring_spacer::get_ruling_durations(Array<Moment> &shortest_playing_arr,
                                    Array<Moment> &context_shortest_arr)
 {
-  for (int i=0; i < cols.size(); i++)
-    scol_l (i)->preprocess();
-
+  for (int i=0; i < cols_.size(); i++)
+    {
+      scol_l (i)->preprocess();
+      scol_l (i)->print ();
+    }
   int start_context_i=0;
-  Moment context_shortest = infinity_mom;
-  context_shortest_arr.set_size(cols.size());
+  Moment context_shortest;
+  context_shortest.set_infinite (1);
+  context_shortest_arr.set_size(cols_.size());
 
-  for (int i=0; i < cols.size(); i++)
+  for (int i=0; i < cols_.size(); i++)
     {
+      Score_column * sc = scol_l(i);
       Moment now = scol_l (i)->when();
-      Moment shortest_playing = infinity_mom;
+      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 = infinity_mom;
+         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
       for (int ji=i+1; ji --;)
        {
@@ -495,14 +561,20 @@ Spring_spacer::get_ruling_durations(Array<Moment> &shortest_playing_arr,
 #endif
 }
 
+/*
+  TODO: take out the refs to width
+
+ */
 /**
   generate springs between columns.
 
-  UNDER DESTRUCTION
+  TODO: This needs rethinking....... 
 
-  TODO: This needs rethinking.  Spacing should take optical
-  effects into account, and should be local (measure wide)
+  *  Spacing should take optical
+  effects into account
 
+  *  Should be decentralised
+  
   The algorithm is taken from :
 
   John S. Gourlay. ``Spacing a Line of Music,'' Technical Report
@@ -517,40 +589,46 @@ 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_;
-  for (int i=0; i < cols.size(); i++){
-    ideal_arr_.push (-1.0);
-    hooke_arr_.push (1.0);
+  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);
   }
 
-  for (int i=0; i < cols.size(); i++)
+  /* 
+     First do all non-musical columns
+  */
+  for (int i=0; i < cols_.size(); i++)
     {
-      if (!scol_l (i)->musical_b())
+      if (!scol_l (i)->musical_b() && i+1 < cols_.size())
        {
-         Real symbol_distance =cols[i].width_[RIGHT] + 2 PT;
+         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 () ;
 
-         if (i+1 < cols.size())
+         /*
+           ugh should use shortest_playing distance
+         */
+         if (delta_t)
            {
-             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];
+             Real k=  paper_l()->arithmetic_constant (context_shortest_arr[i]);
+             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] = 2.0;
+         ideal_arr[i] = symbol_distance >? durational_distance;
+         hooke_arr[i] = 1; //2.0;
        }
     }
-  for (int i=0; i < cols.size(); i++)
+
+  /* 
+     Then musicals
+  */
+  for (int i=0; i < cols_.size(); i++)
     {
       if (scol_l (i)->musical_b())
        {
@@ -558,117 +636,118 @@ Spring_spacer::calc_idealspacing()
          Moment context_shortest = context_shortest_arr[i];
          if (! shortest_playing_len)
            {
-             warning (_("Can't find a ruling note at ")
-                      +String (scol_l (i)->when()));
+             warning (_f ("can't find a ruling note at %s", 
+               scol_l (i)->when().str ()));
              shortest_playing_len = 1;
            }
          if (! context_shortest)
            {
-             warning(_("No minimum in measure at ")
-                     + String (scol_l (i)->when()));
+             warning (_f ("no minimum in measure at %s", 
+                     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 *= delta_t / shortest_playing_len;
+         Real dist = paper_l()->length_mom_to_dist (shortest_playing_len, k);
+         dist *= (double)(delta_t / shortest_playing_len);
 
          /*
-            this is an experimental try to fix the spacing 
-            at the beginning and end of bars.
-            if -t option is not used, the old algorithm should still 
-            be in effect.
-
-            the "old" comment below about ugliness seems to indicate that
-            the code below it address the  same problem? but it sounds real
-            bad.
-
-            According to [Ross] and [Wanske], and from what i've seen:
-            * whitespace at the begin of the bar should be fixed at 
-            (about) two interlines.
-            [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.
-          */
-
-         if (experimental_features_global_b)
+           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 I think that it is ugly 
+           too.
+           
+           [jcn]
+         */
+
+         /* 
+            first musical column of bar
+         */
+         if (i && !scol_l (i - 1)->musical_b ())
            {
-             /* 
-                first musical column of bar?
-              */
-             Moment now_mom = scol_l (i)->when ();
-             if (i && !scol_l (i - 1)->musical_b ()
-                 && ((Moment) floor (now_mom) == now_mom))
-               {
-                 /* 
-                    wtk1-fugue2: very nice
-                    standchen: fuk, koor dump in check_feasible ()
-                  */
-                 // fixed: probably should set minimum (rod/spring)?
-                 cols[i-1].width_[RIGHT] += 1.5 * interline_f;
-                 // should adjust dist too?
-                 ideal_arr_[i-1] += 1.5 * interline_f;
-               }
-
-             /* 
-                last musical column of bar?
+             // 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);
+           }
+
+         /* 
+            last musical column of bar
+         */
+         if (i + 1 < cols_.size () && !scol_l(i+1)->musical_b ())
+           {
+             // two interline minimum ok for last column?
+             dist = dist >? 2 * interline_f;
+
+             // set minimum rod 
+             /*
+               urg: simply *adding* an interline leaves big gaps at
+               end of measure in star-spangled-banner (after lyrics
+               at eom).
+
+                  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
               */
-             Moment next_mom = scol_l (i + 1)->when ();
-             if ((i + 1 < cols.size ()) && !scol_l (i + 1)->musical_b ()
-                 && ((Moment) floor (next_mom) == next_mom))
-               {
-                 // hmm, how bout?
-                 dist = dist >? interline_f;
-
-                 // uhuh, this looks fine, already??
-                 // someone is junking this last "hinterfleisch" whitespace?!
-                 /* 
-                    wtk1-fugue2: very nice
-                    standchen: fuk, koor dump in check_feasible ()
-                  */
-                 cols[i].width_[RIGHT] = cols[i].width_[RIGHT] >? dist;
-               }
-
-             // ugh, do we need this?
-             if (!scol_l (i + 1)->musical_b ())
-               {
-                 Real minimum = -cols[i + 1].width_[LEFT] + cols[i].width_[RIGHT]
-                 + interline_f / 2;
-                 dist = dist >? minimum;
-               }
+
+             cols_[i].width_[RIGHT] = cols_[i].width_[RIGHT] >? 2 * interline_f;
            }
 
-         /* all sorts of ugliness to avoid running into bars/clefs, 
-            but not taking extra space if this is not needed 
-          */
-         else if (!scol_l (i + 1)->musical_b ())
+         // ugh, do we need this?
+         if (i < cols_.size () - 1 && !scol_l (i + 1)->musical_b ())
            {
-             Real minimum_dist = -cols[i + 1].width_[LEFT] + 2 PT
-             + cols[i].width_[RIGHT];
-             if (ideal_arr_[i + 1] + minimum_dist < dist)
-               dist -= ideal_arr_[i + 1];
-             else
-               dist = minimum_dist;
+             Real minimum = -cols_[i + 1].width_[LEFT] + cols_[i].width_[RIGHT]
+               + interline_f / 2;
+             dist = dist >? minimum;
            }
-         ideal_arr_[i] = dist;
+         ideal_arr[i] = dist;
        }
     }
 
-  for (int i=0; i < ideal_arr_.size()-1; 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]);
     }
 }