]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/slur-configuration.cc
Doc-es: various updates.
[lilypond.git] / lily / slur-configuration.cc
index 99577018129afd9dc8187864675e252e50fb6fcb..9eb4ef83bd03c74581d9da08b5664c1a062c9c54 100644 (file)
@@ -1,7 +1,7 @@
 /*
   This file is part of LilyPond, the GNU music typesetter.
 
-  Copyright (C) 2004--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
+  Copyright (C) 2004--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
 
   LilyPond is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -28,6 +28,7 @@
 #include "spanner.hh"
 #include "staff-symbol-referencer.hh"
 #include "stem.hh"
+#include "tie.hh"
 #include "warn.hh"
 
 Bezier
@@ -42,31 +43,41 @@ avoid_staff_line (Slur_score_state const &state,
       && (state.extremes_[LEFT].staff_ == state.extremes_[RIGHT].staff_)
       && state.extremes_[LEFT].staff_ && state.extremes_[RIGHT].staff_)
     {
-      Real y = bez.curve_point (ts[0])[Y_AXIS];
+      Real t = ts[0]; //the first (usually only) point where slur is horizontal
+      Real y = bez.curve_point (t)[Y_AXIS];
+      // A Bezier curve at t moves 3t-3t² as far as the middle control points
+      Real factor = 3.0 * t * (1.0 - t);
 
       Grob *staff = state.extremes_[LEFT].staff_;
 
       Real p = 2 * (y - staff->relative_coordinate (state.common_[Y_AXIS], Y_AXIS))
                / state.staff_space_;
 
-      Real distance = fabs (my_round (p) - p);  //  in halfspaces
-      if (distance < 4 * state.thickness_
-          && (int) fabs (my_round (p))
-          <= 2 * Staff_symbol_referencer::staff_radius (staff) + 0.1
-          && (int (fabs (my_round (p))) % 2
-              != Staff_symbol_referencer::line_count (staff) % 2))
+      int round_p = (int) my_round (p);
+      if (!Staff_symbol_referencer::on_staff_line (staff, round_p))
+        round_p += (p > round_p) ? 1 : -1;
+      if (!Staff_symbol_referencer::on_staff_line (staff, round_p))
+        return bez;
+
+      Real const distance = (p - round_p) * state.staff_space_ / 2.0;
+      // Allow half the thickness of the slur at the point t, plus one basic
+      // blot-diameter (half for the slur outline, half for the staff line)
+      Real const min_distance = 0.5 * state.thickness_ * factor
+        + state.line_thickness_
+        + ((state.dir_ * distance > 0.0)
+           ? state.parameters_.gap_to_staffline_inside_
+           : state.parameters_.gap_to_staffline_outside_);
+      if (fabs (distance) < min_distance)
         {
-          Direction resolution_dir
-            = (distance ? state.dir_ : Direction (sign (p - my_round (p))));
+          Direction resolution_dir = (distance > 0.0) ? UP : DOWN;
 
-          // TODO: parameter
-          Real newp = my_round (p) + resolution_dir
-                      * 5 * state.thickness_;
-
-          Real dy = (newp - p) * state.staff_space_ / 2.0;
+          Real dy = resolution_dir * (min_distance - fabs (distance));
 
+          // Shape the curve, moving the horizontal point by factor * dy
           bez.control_[1][Y_AXIS] += dy;
           bez.control_[2][Y_AXIS] += dy;
+          // Move the entire curve by the remaining amount
+          bez.translate (Offset (0.0, dy - factor * dy));
         }
     }
   return bez;
@@ -79,7 +90,7 @@ fit_factor (Offset dz_unit, Offset dz_perp, Real close_to_edge_length,
   Real fit_factor = 0.0;
   Offset x0 = curve.control_[0];
   curve.translate (-x0);
-  curve.rotate (-dz_unit.arg ());
+  curve.rotate (-dz_unit.angle_degrees ());
   curve.scale (1, d);
 
   Interval curve_xext;
@@ -93,10 +104,8 @@ fit_factor (Offset dz_unit, Offset dz_perp, Real close_to_edge_length,
                 d * dot_product (z, dz_perp));
 
       bool close_to_edge = false;
-      Direction d = LEFT;
-      do
+      for (LEFT_and_RIGHT (d))
         close_to_edge = close_to_edge || -d * (p[X_AXIS] - curve_xext[d]) < close_to_edge_length;
-      while (flip (&d) != LEFT);
 
       if (close_to_edge)
         continue;
@@ -192,11 +201,11 @@ Slur_configuration::Slur_configuration ()
 };
 
 void
-Slur_configuration::add_score (Real s, string desc)
+Slur_configuration::add_score (Real s, const string &desc)
 {
   if (s < 0)
     {
-      programming_error ("Negative demerits found for slur. Ignoring");
+      programming_error ("Negative demerits found for slur.  Ignoring");
       s = 0.0;
     }
 
@@ -277,26 +286,15 @@ Slur_configuration::score_encompass (Slur_score_state const &state)
 
           demerit += stem_dem;
         }
-      else if (!edge)
-        {
-          Interval ext;
-          ext.add_point (state.encompass_infos_[j].stem_);
-          ext.add_point (state.encompass_infos_[j].head_);
-
-          // ?
-          demerit += -state.parameters_.closeness_factor_
-                     * min (state.dir_
-                            * (y - (ext[state.dir_] + state.dir_ * state.parameters_.free_head_distance_)), 0.0)
-                     / state.encompass_infos_.size ();
-        }
     }
   add_score (demerit, "encompass");
 
-  if (convex_head_distances.size ())
+  if (vsize n = convex_head_distances.size ())
     {
       Real avg_distance = 0.0;
       Real min_dist = infinity_f;
-      for (vsize j = 0; j < convex_head_distances.size (); j++)
+
+      for (vsize j = 0; j < n; j++)
         {
           min_dist = min (min_dist, convex_head_distances[j]);
           avg_distance += convex_head_distances[j];
@@ -306,12 +304,11 @@ Slur_configuration::score_encompass (Slur_score_state const &state)
         For slurs over 3 or 4 heads, the average distance is not a
         good normalizer.
       */
-      Real n = convex_head_distances.size ();
       if (n <= 2)
         {
           Real fact = 1.0;
           avg_distance += height_ * fact;
-          n += fact;
+          ++n;
         }
 
       /*
@@ -334,6 +331,39 @@ Slur_configuration::score_encompass (Slur_score_state const &state)
 void
 Slur_configuration::score_extra_encompass (Slur_score_state const &state)
 {
+  // we find forbidden attachments
+  vector<Offset> forbidden_attachments;
+  for (vsize i = 0; i < state.extra_encompass_infos_.size (); i++)
+    if (has_interface<Tie> (state.extra_encompass_infos_[i].grob_))
+      {
+        Grob *t = state.extra_encompass_infos_[i].grob_;
+        Grob *common_x = Grob::get_vertical_axis_group (t);
+        Real rp = t->relative_coordinate (common_x, X_AXIS);
+        SCM cp = t->get_property ("control-points");
+
+        Bezier b;
+        int j = 0;
+        for (SCM s = cp; scm_is_pair (s); s = scm_cdr (s))
+          {
+            b.control_[j] = ly_scm2offset (scm_car (s));
+            j++;
+          }
+        forbidden_attachments.push_back (Offset (b.control_[0]) + Offset (rp, 0));
+        forbidden_attachments.push_back (Offset (b.control_[3]) + Offset (rp, 0));
+      }
+
+  bool too_close = false;
+  for (vsize k = 0; k < forbidden_attachments.size (); k++)
+    for (LEFT_and_RIGHT (side))
+      if ((forbidden_attachments[k] - attachment_[side]).length () < state.parameters_.slur_tie_extrema_min_distance_)
+        {
+          too_close = true;
+          break;
+        }
+
+  if (too_close)
+    add_score (state.parameters_.slur_tie_extrema_min_distance_penalty_, "extra");
+
   for (vsize j = 0; j < state.extra_encompass_infos_.size (); j++)
     {
       Drul_array<Offset> attachment = attachment_;
@@ -345,11 +375,11 @@ Slur_configuration::score_extra_encompass (Slur_score_state const &state)
         to prevent numerical inaccuracies in
         Bezier::get_other_coordinate ().
       */
-      Direction d = LEFT;
+
       bool found = false;
       Real y = 0.0;
 
-      do
+      for (LEFT_and_RIGHT (d))
         {
           /*
             We need to check for the bound explicitly, since the
@@ -370,7 +400,6 @@ Slur_configuration::score_extra_encompass (Slur_score_state const &state)
             }
 
         }
-      while (flip (&d) != LEFT);
 
       if (!found)
         {
@@ -383,14 +412,14 @@ Slur_configuration::score_extra_encompass (Slur_score_state const &state)
         }
 
       Real dist = 0.0;
-      if (info.type_ == ly_symbol2scm ("around"))
+      if (scm_is_eq (info.type_, ly_symbol2scm ("around")))
         dist = info.extents_[Y_AXIS].distance (y);
 
       /*
         Have to score too: the curve enumeration is limited in its
         shape, and may produce curves which collide anyway.
        */
-      else if (info.type_ == ly_symbol2scm ("inside"))
+      else if (scm_is_eq (info.type_, ly_symbol2scm ("inside")))
         dist = state.dir_ * (y - info.extents_[Y_AXIS][state.dir_]);
       else
         programming_error ("unknown avoidance type");
@@ -408,11 +437,11 @@ Slur_configuration::score_extra_encompass (Slur_score_state const &state)
 void
 Slur_configuration::score_edges (Slur_score_state const &state)
 {
-  Direction d = LEFT;
+
   Offset dz = attachment_[RIGHT]
               - attachment_[LEFT];
   Real slope = dz[Y_AXIS] / dz[X_AXIS];
-  do
+  for (LEFT_and_RIGHT (d))
     {
       Real y = attachment_[d][Y_AXIS];
       Real dy = fabs (y - state.base_attachments_[d][Y_AXIS]);
@@ -431,7 +460,6 @@ Slur_configuration::score_edges (Slur_score_state const &state)
       string dir_str = d == LEFT ? "L" : "R";
       add_score (demerit, dir_str + " edge");
     }
-  while (flip (&d) != LEFT);
 }
 
 void