]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/beam-quanting.cc
Issue 5167/6: Changes: show \markup xxx = ... \etc assignments
[lilypond.git] / lily / beam-quanting.cc
index 77dfc9ae0a51d8f42e58e6f80ee283c41b9a896b..f3505772f1a70940c4deb9014d400b9158e485a2 100644 (file)
@@ -1,7 +1,7 @@
 /*
   This file is part of LilyPond, the GNU music typesetter.
 
-  Copyright (C) 1997--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
+  Copyright (C) 1997--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
   Jan Nieuwenhuizen <janneke@gnu.org>
 
   LilyPond is free software: you can redistribute it and/or modify
@@ -45,6 +45,7 @@ using namespace std;
 #include "stencil.hh"
 #include "stem.hh"
 #include "warn.hh"
+#include "string-convert.hh"
 
 Real
 get_detail (SCM alist, SCM sym, Real def)
@@ -66,7 +67,10 @@ Beam_quant_parameters::fill (Grob *him)
   REGION_SIZE = get_detail (details, ly_symbol2scm ("region-size"), 2);
 
   // forbidden quants
-  SECONDARY_BEAM_DEMERIT = get_detail (details, ly_symbol2scm ("secondary-beam-demerit"), 10.0);
+  SECONDARY_BEAM_DEMERIT = get_detail (details, ly_symbol2scm ("secondary-beam-demerit"), 10.0)
+    // For stems that are non-standard, the forbidden beam quanting
+    // doesn't really work, so decrease their importance.
+    * exp(- 8*fabs (1.0 - robust_scm2double(him->get_property ("length-fraction"), 1.0)));
   STEM_LENGTH_DEMERIT_FACTOR = get_detail (details, ly_symbol2scm ("stem-length-demerit-factor"), 5);
   HORIZONTAL_INTER_QUANT_PENALTY = get_detail (details, ly_symbol2scm ("horizontal-inter-quant"), 500);
 
@@ -79,7 +83,14 @@ Beam_quant_parameters::fill (Grob *him)
 
   // Collisions
   COLLISION_PENALTY = get_detail (details, ly_symbol2scm ("collision-penalty"), 500);
-  COLLISION_PADDING = get_detail (details, ly_symbol2scm ("collision-padding"), 0.5);
+
+  /* For grace notes, beams get scaled down to 80%, but glyphs go down
+     to 63% (magstep -4 for accidentals). To make the padding
+     commensurate with glyph size for grace notes, we take the square
+     of the length fraction, yielding a 64% decrease.
+   */
+  COLLISION_PADDING = get_detail (details, ly_symbol2scm ("collision-padding"), 0.5)
+    * sqr (robust_scm2double(him->get_property ("length-fraction"), 1.0));
   STEM_COLLISION_FACTOR = get_detail (details, ly_symbol2scm ("stem-collision-factor"), 0.1);
 }
 
@@ -193,10 +204,8 @@ void Beam_scoring_problem::init_instance_variables (Grob *me, Drul_array<Real> y
     the stems.  Otherwise, we want to do initial slope calculations.
   */
   do_initial_slope_calculations_ = false;
-  Direction d = LEFT;
-  do
+  for (LEFT_and_RIGHT (d))
     do_initial_slope_calculations_ |= isinf (unquanted_y_[d]) || isnan (unquanted_y_[d]);
-  while (flip (&d) != LEFT);
 
   /*
     Calculations are relative to a unit-scaled staff, i.e. the quants are
@@ -245,10 +254,8 @@ void Beam_scoring_problem::init_instance_variables (Grob *me, Drul_array<Real> y
       for (int a = 2; a--;)
         common[a] = common_refpoint_of_array (stems, beams[i], Axis (a));
 
-      Direction d = LEFT;
-      do
+      for (LEFT_and_RIGHT (d))
         common[X_AXIS] = beams[i]->get_bound (d)->common_refpoint (common[X_AXIS], X_AXIS);
-      while (flip (&d) != LEFT);
 
       // positions of the endpoints of this beam segment, including any overhangs
       const Interval x_pos = robust_scm2interval (beams[i]->get_property ("X-positions"),
@@ -298,7 +305,7 @@ void Beam_scoring_problem::init_instance_variables (Grob *me, Drul_array<Real> y
         edge_dirs_ = Drul_array<Direction> (stem_infos_[0].dir_,
                                             stem_infos_.back ().dir_);
 
-      is_xstaff_ = Align_interface::has_interface (common[Y_AXIS]);
+      is_xstaff_ = has_interface<Align_interface> (common[Y_AXIS]);
       is_knee_ |= dirs_found[DOWN] && dirs_found[UP];
 
       staff_radius_ = Staff_symbol_referencer::staff_radius (beams[i]);
@@ -309,8 +316,7 @@ void Beam_scoring_problem::init_instance_variables (Grob *me, Drul_array<Real> y
       // TODO - why are we dividing by staff_space_?
       beam_translation_ = Beam::get_beam_translation (beams[i]) / staff_space_;
 
-      d = LEFT;
-      do
+      for (LEFT_and_RIGHT (d))
         {
           quant_range_[d].set_full ();
           if (!edge_stems[d])
@@ -325,7 +331,6 @@ void Beam_scoring_problem::init_instance_variables (Grob *me, Drul_array<Real> y
                        + (edge_beam_counts_[d] - 1) * beam_translation_ + beam_thickness_ * .5);
           quant_range_[d][-ed] = heads[ed] + stem_offset;
         }
-      while (flip (&d) != LEFT);
 
       segments_ = Beam::get_beam_segments (beams[i]);
       vector_sort (segments_, beam_segment_less);
@@ -338,7 +343,7 @@ void Beam_scoring_problem::init_instance_variables (Grob *me, Drul_array<Real> y
           if (!collisions[j]->is_live ())
             continue;
 
-          if (Beam::has_interface (collisions[j]) && Beam::is_cross_staff (collisions[j]))
+          if (has_interface<Beam> (collisions[j]) && Beam::is_cross_staff (collisions[j]))
             continue;
 
           Box b;
@@ -355,13 +360,11 @@ void Beam_scoring_problem::init_instance_variables (Grob *me, Drul_array<Real> y
           Real width = b[X_AXIS].length ();
           Real width_factor = sqrt (width / staff_space_);
 
-          Direction d = LEFT;
-          do
+          for (LEFT_and_RIGHT (d))
             add_collision (b[X_AXIS][d], b[Y_AXIS], width_factor);
-          while (flip (&d) != LEFT);
 
-          Grob *stem = unsmob_grob (collisions[j]->get_object ("stem"));
-          if (stem && Stem::has_interface (stem) && Stem::is_normal_stem (stem))
+          Grob *stem = unsmob<Grob> (collisions[j]->get_object ("stem"));
+          if (has_interface<Stem> (stem) && Stem::is_normal_stem (stem))
             {
               colliding_stems.insert (stem);
             }
@@ -370,7 +373,7 @@ void Beam_scoring_problem::init_instance_variables (Grob *me, Drul_array<Real> y
       for (set<Grob *>::const_iterator it (colliding_stems.begin ()); it != colliding_stems.end (); it++)
         {
           Grob *s = *it;
-          Real x = (s->extent (common[X_AXIS], X_AXIS) - x_pos[LEFT] + x_span_).center ();
+          Real x = (robust_relative_extent (s, common[X_AXIS], X_AXIS) - x_pos[LEFT] + x_span_).center ();
 
           Direction stem_dir = get_grob_direction (*it);
           Interval y;
@@ -379,7 +382,7 @@ void Beam_scoring_problem::init_instance_variables (Grob *me, Drul_array<Real> y
                          - my_y;
 
           Real factor = parameters_.STEM_COLLISION_FACTOR;
-          if (!unsmob_grob (s->get_object ("beam")))
+          if (!unsmob<Grob> (s->get_object ("beam")))
             factor = 1.0;
           add_collision (x, y, factor);
         }
@@ -659,7 +662,7 @@ Beam_scoring_problem::calc_concaveness ()
   if (scm_is_number (conc))
     return scm_to_double (conc);
 
-  if (is_knee_)
+  if (is_knee_ || is_xstaff_)
     return 0.0;
 
   Direction beam_dir = CENTER;
@@ -794,23 +797,19 @@ Beam_scoring_problem::shift_region_to_valid ()
       if (collisions_[i].y_.length () < min_y_size)
         continue;
 
-      Direction d = LEFT;
-      do
+      for (LEFT_and_RIGHT (d))
         {
           Real dy = slope * collisions_[i].x_;
 
-          Direction yd = DOWN;
           Interval disallowed;
-          do
+          for (DOWN_and_UP (yd))
             {
               Real left_y = collisions_[i].y_[yd] - dy;
               disallowed[yd] = left_y;
             }
-          while (flip (&yd) != DOWN);
 
           forbidden_intervals.push_back (disallowed);
         }
-      while (flip (&d) != LEFT);
     }
 
   vector_sort (forbidden_intervals, Interval::left_less);
@@ -825,13 +824,11 @@ Beam_scoring_problem::shift_region_to_valid ()
 
   // if the beam placement falls out of the feasible region, we push it
   // to infinity so that it can never be a feasible candidate below
-  Direction d = DOWN;
-  do
+  for (DOWN_and_UP (d))
     {
       if (!feasible_left_point.contains (feasible_beam_placements[d]))
         feasible_beam_placements[d] = d * infinity_f;
     }
-  while (flip (&d) != DOWN);
 
   if ((feasible_beam_placements[UP] == infinity_f && feasible_beam_placements[DOWN] == -infinity_f) && !feasible_left_point.is_empty ())
     {
@@ -892,8 +889,7 @@ Beam_scoring_problem::generate_quants (vector<Beam_configuration *> *scores) con
                                             Interval (unshifted_quants[i],
                                                       unshifted_quants[j]));
 
-        Direction d = LEFT;
-        do
+        for (LEFT_and_RIGHT (d))
           {
             if (!quant_range_[d].contains (c->y[d]))
               {
@@ -902,7 +898,6 @@ Beam_scoring_problem::generate_quants (vector<Beam_configuration *> *scores) con
                 break;
               }
           }
-        while (flip (&d) != LEFT);
         if (c)
           scores->push_back (c);
       }
@@ -1098,10 +1093,8 @@ Beam_scoring_problem::score_stem_lengths (Beam_configuration *config) const
     }
 
   /* Divide by number of stems, to make the measure scale-free. */
-  Direction d = DOWN;
-  do
+  for (DOWN_and_UP (d))
     score[d] /= max (count[d], 1);
-  while (flip (&d) != DOWN);
 
   /*
     sometimes, two perfectly symmetric kneed beams will have the same score
@@ -1208,27 +1201,29 @@ Beam_scoring_problem::score_forbidden_quants (Beam_configuration *config) const
 {
   Real dy = config->y.delta ();
 
-  Real extra_demerit = parameters_.SECONDARY_BEAM_DEMERIT
-                       / max (edge_beam_counts_[LEFT], edge_beam_counts_[RIGHT]);
-
-  Direction d = LEFT;
+  Real extra_demerit =
+    parameters_.SECONDARY_BEAM_DEMERIT
+    / max (edge_beam_counts_[LEFT], edge_beam_counts_[RIGHT]);
+  
   Real dem = 0.0;
   Real eps = parameters_.BEAM_EPS;
 
-  do
+  for (LEFT_and_RIGHT (d))
     {
       for (int j = 1; j <= edge_beam_counts_[d]; j++)
         {
           Direction stem_dir = edge_dirs_[d];
 
           /*
-            The 2.2 factor is to provide a little leniency for
+            The fudge_factor is to provide a little leniency for
             borderline cases. If we do 2.0, then the upper outer line
             will be in the gap of the (2, sit) quant, leading to a
-            false demerit.
+            false demerit. By increasing the fudge factor to 2.2, we
+            fix this case.
           */
-          Real gap1 = config->y[d] - stem_dir * ((j - 1) * beam_translation_ + beam_thickness_ / 2 - line_thickness_ / 2.2);
-          Real gap2 = config->y[d] - stem_dir * (j * beam_translation_ - beam_thickness_ / 2 + line_thickness_ / 2.2);
+          Real fudge_factor = 2.2;
+          Real gap1 = config->y[d] - stem_dir * ((j - 1) * beam_translation_ + beam_thickness_ / 2 - line_thickness_ / fudge_factor);
+          Real gap2 = config->y[d] - stem_dir * (j * beam_translation_ - beam_thickness_ / 2 + line_thickness_ / fudge_factor);
 
           Interval gap;
           gap.add_point (gap1);
@@ -1258,8 +1253,9 @@ Beam_scoring_problem::score_forbidden_quants (Beam_configuration *config) const
               }
         }
     }
-  while ((flip (&d)) != LEFT);
 
+  config->add (dem, "Fl");
+  dem = 0.0;
   if (max (edge_beam_counts_[LEFT], edge_beam_counts_[RIGHT]) >= 2)
     {
       Real straddle = 0.0;
@@ -1267,8 +1263,7 @@ Beam_scoring_problem::score_forbidden_quants (Beam_configuration *config) const
       Real inter = 0.5;
       Real hang = 1.0 - (beam_thickness_ - line_thickness_) / 2;
 
-      Direction d = LEFT;
-      do
+      for (LEFT_and_RIGHT (d))
         {
           if (edge_beam_counts_[d] >= 2
               && fabs (config->y[d] - edge_dirs_[d] * beam_translation_) < staff_radius_ + inter)
@@ -1296,10 +1291,9 @@ Beam_scoring_problem::score_forbidden_quants (Beam_configuration *config) const
                 dem += extra_demerit;
             }
         }
-      while (flip (&d) != LEFT);
     }
 
-  config->add (dem, "F");
+  config->add (dem, "Fs");
 }
 
 void
@@ -1317,16 +1311,20 @@ Beam_scoring_problem::score_collisions (Beam_configuration *config) const
       Real dist = infinity_f;
       if (!intersection (beam_y, collision_y).is_empty ())
         dist = 0.0;
-      else
+      else 
         dist = min (beam_y.distance (collision_y[DOWN]),
                     beam_y.distance (collision_y[UP]));
 
+      
       Real scale_free
         = max (parameters_.COLLISION_PADDING - dist, 0.0)
           / parameters_.COLLISION_PADDING;
-      demerits
-      += collisions_[i].base_penalty_ *
+      Real collision_demerit = collisions_[i].base_penalty_ *
          pow (scale_free, 3) * parameters_.COLLISION_PENALTY;
+
+      if (collision_demerit > 0) {
+        demerits += collision_demerit;
+      }
     }
 
   config->add (demerits, "C");