]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/slur-scoring.cc
Doc-es: various updates.
[lilypond.git] / lily / slur-scoring.cc
index 5413c047c2cc219f71773a211aa426d0385d4198..a3dad6fb5e9785888b05b119ac5320b24c0b36b0 100644 (file)
@@ -1,7 +1,7 @@
 /*
   This file is part of LilyPond, the GNU music typesetter.
 
-  Copyright (C) 1996--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
+  Copyright (C) 1996--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
   Jan Nieuwenhuizen <janneke@gnu.org>
 
   LilyPond is free software: you can redistribute it and/or modify
 
 #include <queue>
 
+#include "axis-group-interface.hh"
 #include "accidental-interface.hh"
 #include "beam.hh"
+#include "clef.hh"
 #include "directional-element-interface.hh"
+#include "dots.hh"
 #include "libc-extension.hh"
 #include "main.hh"
+#include "misc.hh"
 #include "note-column.hh"
+#include "note-head.hh"
 #include "output-def.hh"
 #include "paper-column.hh"
 #include "pitch.hh"
@@ -102,7 +107,7 @@ Slur_score_state::slur_direction () const
 Encompass_info
 Slur_score_state::get_encompass_info (Grob *col) const
 {
-  Grob *stem = unsmob_grob (col->get_object ("stem"));
+  Grob *stem = unsmob<Grob> (col->get_object ("stem"));
   Encompass_info ei;
 
   if (!stem)
@@ -152,16 +157,17 @@ Slur_score_state::get_bound_info () const
 {
   Drul_array<Bound_info> extremes;
 
-  Direction d = LEFT;
   Direction dir = dir_;
 
-  do
+  for (LEFT_and_RIGHT (d))
     {
       extremes[d].bound_ = slur_->get_bound (d);
-      if (Note_column::has_interface (extremes[d].bound_))
+      if (has_interface<Note_column> (extremes[d].bound_))
         {
           extremes[d].note_column_ = extremes[d].bound_;
           extremes[d].stem_ = Note_column::get_stem (extremes[d].note_column_);
+          extremes[d].flag_ = Note_column::get_flag (extremes[d].note_column_);
+
           if (extremes[d].stem_)
             {
               extremes[d].stem_dir_ = get_grob_direction (extremes[d].stem_);
@@ -170,6 +176,8 @@ Slur_score_state::get_bound_info () const
                 {
                   Axis ax = Axis (a);
                   Interval s = extremes[d].stem_->extent (common_[ax], ax);
+                  if (extremes[d].flag_)
+                    s.unite (extremes[d].flag_->extent (common_[ax], ax));
                   if (s.is_empty ())
                     {
                       /*
@@ -193,13 +201,15 @@ Slur_score_state::get_bound_info () const
                                          ::staff_space (extremes[d].stem_);
             }
 
-          if (extremes[d].slur_head_)
-            extremes[d].slur_head_x_extent_
-              = extremes[d].slur_head_->extent (common_[X_AXIS], X_AXIS);
-
         }
+      else if (has_interface<Note_head> (extremes[d].bound_))
+        {
+          extremes[d].slur_head_ = extremes[d].bound_;
+        }
+      if (extremes[d].slur_head_)
+        extremes[d].slur_head_x_extent_
+          = extremes[d].slur_head_->extent (common_[X_AXIS], X_AXIS);
     }
-  while (flip (&d) != LEFT);
 
   return extremes;
 }
@@ -219,8 +229,8 @@ Slur_score_state::fill (Grob *me)
 
   Slur::replace_breakable_encompass_objects (me);
   staff_space_ = Staff_symbol_referencer::staff_space (me);
-  Real lt = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
-  thickness_ = robust_scm2double (me->get_property ("thickness"), 1.0) * lt;
+  line_thickness_ = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
+  thickness_ = robust_scm2double (me->get_property ("thickness"), 1.0) * line_thickness_;
 
   dir_ = slur_direction ();
   parameters_.fill (me);
@@ -236,8 +246,7 @@ Slur_score_state::fill (Grob *me)
       common_[a] = common_refpoint_of_array (columns, me, a);
       common_[a] = common_refpoint_of_array (extra_objects, common_[a], a);
 
-      Direction d = LEFT;
-      do
+      for (LEFT_and_RIGHT (d))
         {
           /*
             If bound is not in note-columns, we don't want to know about
@@ -246,12 +255,11 @@ Slur_score_state::fill (Grob *me)
           if (a != Y_AXIS)
             common_[a] = common_[a]->common_refpoint (sp->get_bound (d), a);
         }
-      while (flip (&d) != LEFT);
     }
 
   extremes_ = get_bound_info ();
-  is_broken_ = (!extremes_[LEFT].note_column_
-                || !extremes_[RIGHT].note_column_);
+  is_broken_ = (!(extremes_[LEFT].note_column_ || extremes_[LEFT].slur_head_)
+                || !(extremes_[RIGHT].note_column_ || extremes_[RIGHT].slur_head_));
 
   has_same_beam_
     = (extremes_[LEFT].stem_ && extremes_[RIGHT].stem_
@@ -262,23 +270,58 @@ Slur_score_state::fill (Grob *me)
   Drul_array<Real> end_ys
     = get_y_attachment_range ();
 
+  extra_encompass_infos_ = get_extra_encompass_infos ();
+
+  Interval additional_ys (0.0, 0.0);
+
+  for (vsize i = 0; i < extra_encompass_infos_.size (); i++)
+    {
+      if (extra_encompass_infos_[i].extents_[X_AXIS].is_empty ())
+        continue;
+
+      Real y_place = linear_interpolate (extra_encompass_infos_[i].extents_[X_AXIS].center (),
+                                         base_attachments_[RIGHT][X_AXIS],
+                                         base_attachments_[LEFT][X_AXIS],
+                                         end_ys[RIGHT],
+                                         end_ys[LEFT]);
+      Real encompass_place = extra_encompass_infos_[i].extents_[Y_AXIS][dir_];
+      if (scm_is_eq (extra_encompass_infos_[i].type_,
+                     ly_symbol2scm ("inside"))
+          && minmax (dir_, encompass_place, y_place) == encompass_place
+          && (!extra_encompass_infos_[i].grob_->internal_has_interface (ly_symbol2scm ("key-signature-interface"))
+              && !has_interface<Clef> (extra_encompass_infos_[i].grob_)
+              && !extra_encompass_infos_[i].grob_->internal_has_interface (ly_symbol2scm ("time-signature-interface"))))
+        {
+          for (LEFT_and_RIGHT (d))
+            additional_ys[d] = minmax (dir_,
+                                       additional_ys[d],
+                                       (dir_
+                                        * (parameters_.encompass_object_range_overshoot_
+                                           + (y_place - encompass_place)
+                                           * (normalize (extra_encompass_infos_[i].extents_[X_AXIS].center (),
+                                                         base_attachments_[RIGHT][X_AXIS],
+                                                         base_attachments_[LEFT][X_AXIS])
+                                              + (dir_ == LEFT ? 0 : -1)))));
+        }
+    }
+
+  for (LEFT_and_RIGHT (d))
+    end_ys[d] += additional_ys[d];
+
   configurations_ = enumerate_attachments (end_ys);
   for (vsize i = 0; i < columns_.size (); i++)
     encompass_infos_.push_back (get_encompass_info (columns_[i]));
 
-  extra_encompass_infos_ = get_extra_encompass_infos ();
   valid_ = true;
 
   musical_dy_ = 0.0;
-  Direction d = LEFT;
-  do
+  for (LEFT_and_RIGHT (d))
     {
       if (!is_broken_
           && extremes_[d].slur_head_)
         musical_dy_ += d
                        * extremes_[d].slur_head_->relative_coordinate (common_[Y_AXIS], Y_AXIS);
     }
-  while (flip (&d) != LEFT);
 
   edge_has_beams_
     = (extremes_[LEFT].stem_ && Stem::get_beam (extremes_[LEFT].stem_))
@@ -292,7 +335,7 @@ MAKE_SCHEME_CALLBACK (Slur, calc_control_points, 1)
 SCM
 Slur::calc_control_points (SCM smob)
 {
-  Spanner *me = unsmob_spanner (smob);
+  Spanner *me = unsmob<Spanner> (smob);
 
   Slur_score_state state;
   state.fill (me);
@@ -388,10 +431,12 @@ Slur_score_state::get_best_curve () const
   return best;
 }
 
-Grob *
-Slur_score_state::breakable_bound_item (Direction d) const
+Interval
+Slur_score_state::breakable_bound_extent (Direction d) const
 {
   Grob *col = slur_->get_bound (d)->get_column ();
+  Interval ret;
+  ret.set_empty ();
 
   extract_grob_set (slur_, "encompass-objects", extra_encompasses);
 
@@ -399,10 +444,10 @@ Slur_score_state::breakable_bound_item (Direction d) const
     {
       Item *item = dynamic_cast<Item *> (extra_encompasses[i]);
       if (item && col == item->get_column ())
-        return item;
+        ret.unite (robust_relative_extent (item, common_[X_AXIS], X_AXIS));
     }
 
-  return 0;
+  return ret;
 }
 
 /*
@@ -414,21 +459,29 @@ Drul_array<Real>
 Slur_score_state::get_y_attachment_range () const
 {
   Drul_array<Real> end_ys;
-  Direction d = LEFT;
-  do
+  for (LEFT_and_RIGHT (d))
     {
       if (extremes_[d].note_column_)
         {
-          end_ys[d] = dir_
-                      * max (max (dir_ * (base_attachments_[d][Y_AXIS]
-                                          + parameters_.region_size_ * dir_),
-                                  dir_ * (dir_ + extremes_[d].note_column_->extent (common_[Y_AXIS], Y_AXIS)[dir_])),
-                             dir_ * base_attachments_[-d][Y_AXIS]);
+          Interval nc_extent = extremes_[d].note_column_
+                               ->extent (common_[Y_AXIS], Y_AXIS);
+          if (nc_extent.is_empty ())
+            slur_->warning ("slur trying to encompass an empty note column.");
+          else
+            end_ys[d] = dir_
+                        * max (max (dir_ * (base_attachments_[d][Y_AXIS]
+                                            + parameters_.region_size_ * dir_),
+                                    dir_ * (dir_ + nc_extent[dir_])),
+                               dir_ * base_attachments_[-d][Y_AXIS]);
+        }
+      else if (extremes_[d].slur_head_)
+        {
+          // allow only minimal movement
+          end_ys[d] = base_attachments_[d][Y_AXIS] + 0.3 * dir_;
         }
       else
         end_ys[d] = base_attachments_[d][Y_AXIS] + parameters_.region_size_ * dir_;
     }
-  while (flip (&d) != LEFT);
 
   return end_ys;
 }
@@ -437,13 +490,11 @@ bool
 spanner_less (Spanner *s1, Spanner *s2)
 {
   Slice b1, b2;
-  Direction d = LEFT;
-  do
+  for (LEFT_and_RIGHT (d))
     {
       b1[d] = s1->get_bound (d)->get_column ()->get_rank ();
       b2[d] = s2->get_bound (d)->get_column ()->get_rank ();
     }
-  while (flip (&d) != LEFT);
 
   return b2[LEFT] <= b1[LEFT] && b2[RIGHT] >= b1[RIGHT]
          && (b2[LEFT] != b1[LEFT] || b2[RIGHT] != b1[RIGHT]);
@@ -453,8 +504,7 @@ Drul_array<Offset>
 Slur_score_state::get_base_attachments () const
 {
   Drul_array<Offset> base_attachment;
-  Direction d = LEFT;
-  do
+  for (LEFT_and_RIGHT (d))
     {
       Grob *stem = extremes_[d].stem_;
       Grob *head = extremes_[d].slur_head_;
@@ -487,25 +537,32 @@ Slur_score_state::get_base_attachments () const
                : extremes_[d].bound_->extent (common_[X_AXIS], X_AXIS))
               .linear_combination (CENTER);
         }
+      else if (head)
+        {
+          y = head->extent (common_[Y_AXIS], Y_AXIS)
+            .linear_combination (0.5*dir_);
+
+          // Don't "move_away_from_staffline" because that makes it
+          // harder to recognize the specific attachment point
+          x = head->extent (common_[X_AXIS], X_AXIS)[-d];
+        }
+
       base_attachment[d] = Offset (x, y);
     }
-  while (flip (&d) != LEFT);
 
-  do
+  for (LEFT_and_RIGHT (d))
     {
-      if (!extremes_[d].note_column_)
+      if (!extremes_[d].note_column_ && !extremes_[d].slur_head_)
         {
           Real x = 0;
           Real y = 0;
 
-          if (Grob *g = breakable_bound_item (d))
-            {
-              x = robust_relative_extent (g, common_[X_AXIS], X_AXIS)[RIGHT];
-            }
-          else if (d == RIGHT)
-            x = robust_relative_extent (extremes_[d].bound_, common_[X_AXIS], X_AXIS)[d];
-          else
-            x = slur_->get_broken_left_end_align ();
+          Interval ext = breakable_bound_extent (d);
+          if (ext.is_empty ())
+            ext = Axis_group_interface::
+                  generic_bound_extent (extremes_[d].bound_,
+                                        common_[X_AXIS], X_AXIS);
+          x = ext[-d];
 
           Grob *col = (d == LEFT) ? columns_[0] : columns_.back ();
 
@@ -527,9 +584,8 @@ Slur_score_state::get_base_attachments () const
           base_attachment[d] = Offset (x, y);
         }
     }
-  while (flip (&d) != LEFT);
 
-  do
+  for (LEFT_and_RIGHT (d))
     {
       for (int a = X_AXIS; a < NO_AXES; a++)
         {
@@ -542,7 +598,6 @@ Slur_score_state::get_base_attachments () const
             }
         }
     }
-  while (flip (&d) != LEFT);
 
   return base_attachment;
 }
@@ -564,8 +619,7 @@ Slur_score_state::move_away_from_staffline (Real y,
       * 2.0 / staff_space_;
 
   if (fabs (pos - my_round (pos)) < 0.2
-      && Staff_symbol_referencer::on_line (on_staff, (int) rint (pos))
-      && Staff_symbol_referencer::line_count (on_staff) - 1 >= rint (pos))
+      && Staff_symbol_referencer::on_staff_line (on_staff, (int) rint (pos)))
     y += 1.5 * staff_space_ * dir_ / 10;
 
   return y;
@@ -592,7 +646,7 @@ Slur_score_state::generate_avoid_offsets () const
   extract_grob_set (slur_, "encompass-objects", extra_encompasses);
   for (vsize i = 0; i < extra_encompasses.size (); i++)
     {
-      if (Slur::has_interface (extra_encompasses[i]))
+      if (has_interface<Slur> (extra_encompasses[i]))
         {
           Grob *small_slur = extra_encompasses[i];
           Bezier b = Slur::get_curve (small_slur);
@@ -604,7 +658,8 @@ Slur_score_state::generate_avoid_offsets () const
           z[Y_AXIS] += dir_ * parameters_.free_slur_distance_;
           avoid.push_back (z);
         }
-      else if (extra_encompasses[i]->get_property ("avoid-slur") == ly_symbol2scm ("inside"))
+      else if (scm_is_eq (extra_encompasses[i]->get_property ("avoid-slur"),
+                          ly_symbol2scm ("inside")))
         {
           Grob *g = extra_encompasses [i];
           Interval xe = g->extent (common_[X_AXIS], X_AXIS);
@@ -644,9 +699,9 @@ Slur_score_state::enumerate_attachments (Drul_array<Real> end_ys) const
       os[RIGHT] = base_attachments_[RIGHT];
       for (int j = 0; dir_ * os[RIGHT][Y_AXIS] <= dir_ * end_ys[RIGHT]; j++)
         {
-          Direction d = LEFT;
+
           Drul_array<bool> attach_to_stem (false, false);
-          do
+          for (LEFT_and_RIGHT (d))
             {
               os[d][X_AXIS] = base_attachments_[d][X_AXIS];
               if (extremes_[d].stem_
@@ -668,14 +723,13 @@ Slur_score_state::enumerate_attachments (Drul_array<Real> end_ys) const
                     os[d][X_AXIS] = extremes_[d].stem_extent_[X_AXIS].center ();
                 }
             }
-          while (flip (&d) != LEFT);
 
           Offset dz;
           dz = os[RIGHT] - os[LEFT];
           if (dz[X_AXIS] < minimum_length
               || fabs (dz[Y_AXIS] / dz[X_AXIS]) > parameters_.max_slope_)
             {
-              do
+              for (LEFT_and_RIGHT (d))
                 {
                   if (extremes_[d].slur_head_
                       && !extremes_[d].slur_head_x_extent_.is_empty ())
@@ -684,11 +738,10 @@ Slur_score_state::enumerate_attachments (Drul_array<Real> end_ys) const
                       attach_to_stem[d] = false;
                     }
                 }
-              while (flip (&d) != LEFT);
             }
 
-          dz = os[RIGHT] - os[LEFT];
-          do
+          dz = (os[RIGHT] - os[LEFT]).direction ();
+          for (LEFT_and_RIGHT (d))
             {
               if (extremes_[d].slur_head_
                   && !attach_to_stem[d])
@@ -699,10 +752,9 @@ Slur_score_state::enumerate_attachments (Drul_array<Real> end_ys) const
                      TODO: parameter */
                   os[d][X_AXIS]
                   -= dir_ * extremes_[d].slur_head_x_extent_.length ()
-                     * sin (dz.arg ()) / 3;
+                    * dz[Y_AXIS] / 3;
                 }
             }
-          while (flip (&d) != LEFT);
 
           scores.push_back (Slur_configuration::new_config (os, scores.size ()));
 
@@ -723,7 +775,7 @@ Slur_score_state::get_extra_encompass_infos () const
   vector<Extra_collision_info> collision_infos;
   for (vsize i = encompasses.size (); i--;)
     {
-      if (Slur::has_interface (encompasses[i]))
+      if (has_interface<Slur> (encompasses[i]))
         {
           Spanner *small_slur = dynamic_cast<Spanner *> (encompasses[i]);
           Bezier b = Slur::get_curve (small_slur);
@@ -764,10 +816,12 @@ Slur_score_state::get_extra_encompass_infos () const
           Grob *g = encompasses [i];
           Interval xe = g->extent (common_[X_AXIS], X_AXIS);
           Interval ye = g->extent (common_[Y_AXIS], Y_AXIS);
+          if (has_interface<Dots> (g))
+            ye.widen (0.2);
 
           Real xp = 0.0;
           Real penalty = parameters_.extra_object_collision_penalty_;
-          if (Accidental_interface::has_interface (g))
+          if (has_interface<Accidental_interface> (g))
             {
               penalty = parameters_.accidental_collision_;