]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/beam.cc
clap
[lilypond.git] / lily / beam.cc
index 47e156a3a92b754dc2d706a3653873981ab4b020..2e223aaecc0a235052567044b9351b83b93c93fc 100644 (file)
   * Rewrite stem_beams.
 
   * Use Number_pair i.s.o Interval to represent (yl, yr).
+
   
   */
 
 
-
-
 #include <math.h> // tanh.
 
 #include "molecule.hh" 
 const int INTER_QUANT_PENALTY = 1000; 
 const int SECONDARY_BEAM_DEMERIT  = 15;
 const int STEM_LENGTH_DEMERIT_FACTOR = 5;
-const int STEM_LENGTH_LIMIT_PENALTY = 500;
+// possibly ridiculous, but too short stems just won't do
+const int STEM_LENGTH_LIMIT_PENALTY = 5000;
 const int DAMPING_DIRECTIION_PENALTY = 800;
 const int MUSICAL_DIRECTION_FACTOR = 400;
 const int IDEAL_SLOPE_FACTOR = 10;
+const int REGION_SIZE = 2;
 
 
 static Real
@@ -346,13 +347,9 @@ Beam::set_stem_shorten (Grob *m)
 }
 
 /*  Call list of y-dy-callbacks, that handle setting of
-    grob-properties y, dy.
-    
-    User may set grob-properties: y-position-hs and height-hs
- (to be fixed) that override the calculated y and dy.
-    
-    Because y and dy cannot be calculated and quanted separately, we
-    always calculate both, then check for user override. */
+    grob-properties
+
+*/
 MAKE_SCHEME_CALLBACK (Beam, after_line_breaking, 1);
 SCM
 Beam::after_line_breaking (SCM smob)
@@ -447,31 +444,29 @@ Beam::quanting (SCM smob)
   for (int i= 0; i < stems.size(); i++)
     {
       Grob*s = stems[i];
-      stem_infos.push( Stem::calc_stem_info (s));
+      stem_infos.push (Stem::calc_stem_info (s));
+      dirs_found[stem_infos.top ().dir_] = true;
 
-      Real b = calc_stem_y (me, s, Interval (1,0));
+      Real b = calc_stem_y (me, s, Interval (1,0), false);
       lbase_lengths.push (b);
 
-      b = calc_stem_y (me, s, Interval (0,1));
-      rbase_lengths.push (b);
-
-      dirs_found [stem_infos.top().dir_] = true;
+      Real a = calc_stem_y (me, s, Interval (0,1), false);
+      rbase_lengths.push (a);
     }
 
   Direction ldir = Direction (stem_infos[0].dir_);
   Direction rdir = Direction (stem_infos.top ().dir_);
   bool knee_b = dirs_found[LEFT] && dirs_found[RIGHT];
 
-  
-  int REGION_SIZE = 2;
 
+  int region_size = REGION_SIZE;
   /*
     Knees are harder, lets try some more possibilities for knees. 
    */
   if (knee_b)
-    REGION_SIZE += 2 ;
+    region_size += 2;
   
-  for (int i = -REGION_SIZE ; i < REGION_SIZE; i++)
+  for (int i = -region_size ; i < region_size; i++)
     for (int j = 0; j < num_quants; j++)
       {
        quantsl.push (i + quants[j] + int (yl));
@@ -573,9 +568,7 @@ Beam::score_stem_lengths (Link_array<Grob>stems,
 {
   Real demerit_score = 0.0 ;
   Real pen = STEM_LENGTH_LIMIT_PENALTY;
-  if (knee)
-    pen = sqrt(pen);
-
+  
   for (int i=0; i < stems.size (); i++)
     {
       Grob* s = stems[i];
@@ -588,7 +581,9 @@ Beam::score_stem_lengths (Link_array<Grob>stems,
       Stem_info info = stem_infos[i];
       Direction d = info.dir_;
 
-      demerit_score += pen * ( 0 >? (info.dir_ *(info.shortest_y_ - current_y)));
+      demerit_score += pen
+       * ( 0 >? (info.dir_ * (info.shortest_y_ - current_y)));
+      
       demerit_score += STEM_LENGTH_DEMERIT_FACTOR
        * shrink_extra_weight (d * current_y  - info.dir_ * info.ideal_y_);
     }
@@ -740,6 +735,29 @@ Beam::least_squares (SCM smob)
 
   Interval ideal (Stem::calc_stem_info (first_visible_stem (me)).ideal_y_,
                  Stem::calc_stem_info (last_visible_stem (me)).ideal_y_);
+
+
+
+  Array<Real> x_posns ;
+  Link_array<Item> stems=
+    Pointer_group_interface__extract_grobs (me, (Item*)0, "stems");
+  Grob *common = stems[0];
+  for (int i=1; i < stems.size (); i++)
+    common = stems[i]->common_refpoint (common, X_AXIS);
+
+  Real x0 = first_visible_stem (me)->relative_coordinate (common, X_AXIS);
+  for (int i=0; i < stems.size (); i++)
+    {
+      Item* s = stems[i];
+
+      Real x = s->relative_coordinate (common, X_AXIS) - x0;
+      x_posns.push (x);
+    }
+  Real dx = last_visible_stem (me)->relative_coordinate (common, X_AXIS) - x0;
+
+  Real y =0;  
+  Real dydx = 0;
+  Real dy = 0;
   
   if (!ideal.delta ())
     {
@@ -748,11 +766,10 @@ Beam::least_squares (SCM smob)
 
 
       /*
-       TODO  : use scoring for this.
+       TODO -- use scoring for this.
 
        complicated, because we take stem-info.ideal for determining
        beam slopes.
-       
        */
       /* Make simple beam on middle line have small tilt */
       if (!ideal[LEFT] && chord.delta () && count == 2)
@@ -770,39 +787,125 @@ Beam::least_squares (SCM smob)
        {
          pos = ideal;
        }
+
+      y = pos[LEFT];
+      dy = pos[RIGHT]- y;
+      dydx = dy/dx;
     }
   else
     {
       Array<Offset> ideals;
-
-      // ugh -> use commonx
-      Real x0 = first_visible_stem (me)->relative_coordinate (0, X_AXIS);
-      Link_array<Item> stems=
-       Pointer_group_interface__extract_grobs (me, (Item*)0, "stems");
-
       for (int i=0; i < stems.size (); i++)
        {
          Item* s = stems[i];
          if (Stem::invisible_b (s))
            continue;
-         ideals.push (Offset (s->relative_coordinate (0, X_AXIS) - x0,
+         ideals.push (Offset (x_posns[i],
                               Stem::calc_stem_info (s).ideal_y_));
        }
-      Real y; 
-      Real dydx;
       minimise_least_squares (&dydx, &y, ideals);
 
-      Real dx = last_visible_stem (me)->relative_coordinate (0, X_AXIS) - x0;
-      Real dy = dydx * dx;
+      dy = dydx * dx;
       me->set_grob_property ("least-squares-dy", gh_double2scm (dy));
-
       pos = Interval (y, (y+dy));
     }
 
   me->set_grob_property ("positions", ly_interval2scm (pos));
   return SCM_UNSPECIFIED;
 }
 
+
+/*
+  We can't combine with previous function, since check concave and
+  slope damping comes first.
+ */
+MAKE_SCHEME_CALLBACK (Beam, shift_region_to_valid, 1);
+SCM
+Beam::shift_region_to_valid (SCM grob)
+{
+  Grob *me = unsmob_grob (grob);
+  /*
+    Code dup.
+   */
+  Array<Real> x_posns ;
+  Link_array<Item> stems=
+    Pointer_group_interface__extract_grobs (me, (Item*)0, "stems");
+  Grob *common = stems[0];
+  for (int i=1; i < stems.size (); i++)
+    common = stems[i]->common_refpoint (common, X_AXIS);
+
+  Grob *fvs = first_visible_stem (me);
+
+  if (!fvs)
+    return SCM_UNSPECIFIED;
+    
+  Real x0 =fvs->relative_coordinate (common, X_AXIS);
+  for (int i=0; i < stems.size (); i++)
+    {
+      Item* s = stems[i];
+
+      Real x = s->relative_coordinate (common, X_AXIS) - x0;
+      x_posns.push (x);
+    }
+
+  Grob *lvs = last_visible_stem (me);
+  if (!lvs)
+    return SCM_UNSPECIFIED;
+  
+  Real dx = lvs->relative_coordinate (common, X_AXIS) - x0;
+
+  Interval pos = ly_scm2interval ( me->get_grob_property ("positions"));
+  Real dy = pos.delta();
+  Real y = pos[LEFT];
+  Real dydx =dy/dx;
+
+  
+  /*
+    Shift the positions so that we have a chance of finding good
+    quants (i.e. no short stem failures.)
+   */
+  Interval feasible_left_point;
+  feasible_left_point.set_full ();
+  for (int i=0; i < stems.size (); i++)
+    {
+      Item* s = stems[i];
+      if (Stem::invisible_b (s))
+       continue;
+
+
+      Direction d = Stem::get_direction (s);
+
+
+      Real left_y = Stem::calc_stem_info (s).shortest_y_
+       - dydx * x_posns [i];
+
+      Interval flp ;
+      flp.set_full ();
+      flp[-d] = left_y;
+
+      feasible_left_point.intersect (flp);
+    }
+      
+  if (feasible_left_point.empty_b())
+    {
+      warning (_("Not sure that we can find a nice beam slope (no viable initial configuration found)."));
+    }
+  else if (!feasible_left_point.elem_b(y))
+    {
+      if (isinf (feasible_left_point[DOWN]))
+       y = feasible_left_point[UP] - REGION_SIZE;
+      else if (isinf (feasible_left_point[UP]))
+       y = feasible_left_point[DOWN]+ REGION_SIZE;
+      else
+       y = feasible_left_point.center ();
+    }
+  pos = Interval (y, (y+dy));
+  me->set_grob_property ("positions", ly_interval2scm (pos));
+  return SCM_UNSPECIFIED;
+}
+
+
 MAKE_SCHEME_CALLBACK (Beam, check_concave, 1);
 SCM
 Beam::check_concave (SCM smob)
@@ -962,30 +1065,39 @@ Beam::slope_damping (SCM smob)
 /*
   Calculate the Y position of the stem-end, given the Y-left, Y-right
   in POS, and for stem S.
+
+  If CORRECT, correct for multiplicity of beam in case of knees.
+
+
+  TODO: junk CORRECT from this.
  */
 Real
-Beam::calc_stem_y (Grob *me, Grob* s, Interval pos)
+Beam::calc_stem_y (Grob *me, Grob* s, Interval pos, bool correct)
 {
   int beam_multiplicity = get_multiplicity (me);
   int stem_multiplicity = (Stem::duration_log (s) - 2) >? 0;
+  
 
   Real thick = gh_scm2double (me->get_grob_property ("thickness"));
   Real interbeam = get_interbeam (me);
 
   // ugh -> use commonx
-  Real x0 = first_visible_stem (me)->relative_coordinate (0, X_AXIS);
-  Real dx = last_visible_stem (me)->relative_coordinate (0, X_AXIS) - x0;
+  Grob * fvs = first_visible_stem (me);
+  Grob *lvs = last_visible_stem (me);
+    
+  Real x0 = fvs ? fvs->relative_coordinate (0, X_AXIS) : 0.0;
+  Real dx = fvs ? lvs->relative_coordinate (0, X_AXIS) - x0 : 0.0;
+  Real r = s->relative_coordinate (0, X_AXIS) - x0;
   Real dy = pos.delta ();
   Real stem_y = (dy && dx
-                ? (s->relative_coordinate (0, X_AXIS) - x0) / dx
+                ? r / dx
                 * dy
                 : 0) + pos[LEFT];
 
-
-  Direction first_dir = Directional_element_interface::get (first_visible_stem (me));
   Direction my_dir = Directional_element_interface::get (s);
+  Direction first_dir = fvs? Directional_element_interface::get (fvs) : my_dir;
 
-  if (my_dir != first_dir)
+  if (correct && my_dir != first_dir)
     {
       /*
        WTF is happening here ?
@@ -1009,6 +1121,8 @@ Beam::calc_stem_y (Grob *me, Grob* s, Interval pos)
        --hwn.
        
        */
+      
+      // FIXME, hairy stuff
       stem_y += my_dir * (thick / 2 + (beam_multiplicity - 1) * interbeam);
 
       // huh, why not for first visible?
@@ -1027,7 +1141,6 @@ Beam::calc_stem_y (Grob *me, Grob* s, Interval pos)
       else
        programming_error ("No last visible stem");
     }
-
   return stem_y;
 }
 
@@ -1067,7 +1180,7 @@ Beam::set_stem_lengths (Grob *me)
       if (Stem::invisible_b (s))
        continue;
 
-      Real stem_y = calc_stem_y (me, s, pos);
+      Real stem_y = calc_stem_y (me, s, pos, true);
 
 #if 0
       // doesn't play well with dvips
@@ -1293,8 +1406,6 @@ Beam::brew_molecule (SCM smob)
   Real dydx = dy && dx ? dy/dx : 0;
 
 
-  Direction firstdir = Directional_element_interface::get ( Beam::first_visible_stem (me) );
-  
   for (int i=0; i < stems.size (); i++)
     {
       Item *item = stems[i];
@@ -1307,7 +1418,7 @@ Beam::brew_molecule (SCM smob)
       Real x = item->relative_coordinate (0, X_AXIS) - x0;
       sb.translate (Offset (x, x * dydx + pos[LEFT]));
 
-      Direction sd = Stem::get_direction (item);      
+
       mol.add_molecule (sb);
     }