]> git.donarmstrong.com Git - lilypond.git/commitdiff
* flower/include/interval.hh (struct Interval_t):
authorHan-Wen Nienhuys <hanwen@xs4all.nl>
Mon, 22 Aug 2005 14:03:11 +0000 (14:03 +0000)
committerHan-Wen Nienhuys <hanwen@xs4all.nl>
Mon, 22 Aug 2005 14:03:11 +0000 (14:03 +0000)
* lily/tie.cc (distance): new function
(height): new function.
(init): new function
(Tie_details): new struct.

* lily/skyline.cc (skyline_height): new function.

* lily/tie-column.cc (set_chord_outlines): new function.
(new_directions): read tie-configuration

* lily/skyline.cc: fix ASCII art.

13 files changed:
ChangeLog
Documentation/topdocs/NEWS.tely
flower/include/interval.hh
flower/include/interval.tcc
lily/include/skyline.hh
lily/include/tie-column.hh
lily/include/tie.hh
lily/skyline.cc
lily/tie-column.cc
lily/tie-helper.cc [new file with mode: 0644]
lily/tie.cc
python/convertrules.py
scm/define-grob-properties.scm

index 290a29c2d12361453167c63fbdf8754840581f6b..c2dc35e837d4fb27d80ac56e65bf10c03a1022d1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,9 +1,25 @@
+2005-08-22  Han-Wen Nienhuys  <hanwen@xs4all.nl>
+
+       * flower/include/interval.hh (struct Interval_t): 
+
+       * lily/tie.cc (distance): new function 
+       (height): new function.
+       (init): new function
+       (Tie_details): new struct.
+
+       * lily/skyline.cc (skyline_height): new function.
+
+       * lily/tie-column.cc (set_chord_outlines): new function.
+       (new_directions): read tie-configuration
+
+       * lily/skyline.cc: fix ASCII art.
+       
 2005-08-22  Mats Bengtsson  <mabe@drongo.s3.kth.se>
 
        * python/convertrules.py (string_or_scheme): Fix spelling error
 
 2005-08-22  Han-Wen Nienhuys  <hanwen@xs4all.nl>
-
+       
        * lily/tie-column.cc (set_directions): set directions only once.
        (add_configuration): new function.
 
index d335aba14e06d8c6abd7da609b36e7119166d92a..71de922b5b4f852a0c52a6de8c5cc04599eb66cf 100644 (file)
@@ -36,6 +36,23 @@ This document is also available in @uref{NEWS.pdf,PDF}.
 
 
 @itemize @bullet
+@item
+Formatting of ties in chords has been improved. Ties no longer collide
+with note heads and stems. In addition, it is possible to manually
+specify tie formatting
+
+@lilypond[relative=2, fragment,raggedright]
+  <a c d f> ~ <a c d f>
+  
+  \override TieColumn #'tie-configuration =
+  #'((0 . -1)  (2 . -1) (5.5 . 1) (7 . 1))
+  <b d f g> ~ <b d f g>
+@end lilypond
+
+This improvement has been sponsored by Bertalan Fodor, Jay Hamilton,
+Kieren MacMillan, Steve Doonan, by Trevor Baca, and 
+Vicente Solsona Dellá.
+
 @item
 Formatting of isolated, single ties has been improved. Now, ties avoid
 staff lines, flags and dots, without compromising their shape.
@@ -49,7 +66,8 @@ staff lines, flags and dots, without compromising their shape.
 @end lilypond
 
 This improvement has been sponsored by Bertalan Fodor, Jay Hamilton,
-Kieren MacMillan, Steve Doonan, by Trevor Baca, and Vincent SD.
+Kieren MacMillan, Steve Doonan, by Trevor Baca, and Vicente Solsona
+Dellá.
  
 
 @item
index 2d3bf4128114466bced1d52c9eb6c69350018410..08a48a9898e92658a79e223be05eaa70f2ab965e 100644 (file)
@@ -109,7 +109,7 @@ struct Interval_t : public Drul_array<T>
   }
   String to_string () const;
 
-  bool contains (T r);
+  bool contains (T r) const;
   void negate ()
   {
     T r = -elem (LEFT);
index 4e3323f74889bb6a2a15675294b5408f969c70cd..3cee682cbc4c06c8f9ee3a9b33cc91ca468ee4a2 100644 (file)
@@ -115,7 +115,7 @@ Interval_t<T>::to_string () const
 
 template<class T>
 bool
-Interval_t<T>::contains (T r)
+Interval_t<T>::contains (T r) const
 {
   return r >= elem (LEFT) && r <= elem (RIGHT);
 }
index 458a2f7cb09ae2b16152f53e931776b75231fcfe..85b58e27e97b1a54dde8d95c75076da74206ea1e 100644 (file)
@@ -33,5 +33,9 @@ Real
 skyline_meshing_distance (Array<Skyline_entry> const &buildings,
                          Array<Skyline_entry> const &clouds);
 
+Real
+skyline_height (Array<Skyline_entry> const &buildings,
+               Real airplane, Direction sky_dir);
+
 #endif /* SKYLINE_HH */
 
index 3ecc0120761c506aeebdd160709d2ea471960b40..37b5725c6486ab377aa3420869fbd6e35b5c4705 100644 (file)
@@ -20,7 +20,6 @@ public:
   DECLARE_SCHEME_CALLBACK (after_line_breaking, (SCM));
   DECLARE_SCHEME_CALLBACK (before_line_breaking, (SCM));
   static void set_directions (Grob *me);
-  static void werner_directions (Grob *me);
   static void new_directions (Grob *me);
 };
 
index efaa3f2949b21c3628cf31afa28ae78e65e26e0f..13ce284f4b68a63b4d932d4711fede6be1dcd15b 100644 (file)
 
 #include "lily-guile.hh"
 #include "lily-proto.hh"
+#include "skyline.hh"
 
 
+
+Interval
+get_skyline_attachment (Drul_array< Array < Skyline_entry > > const &skylines,
+                       Real y1);
+
+struct Tie_details
+{
+  Real height_limit_;
+  Real ratio_;
+  Real staff_space_;
+  
+  Tie_details ();
+  void init (Grob *);
+};
+  
 struct Tie_configuration
 {
-  int position_;
+  Real position_;
   Direction dir_;
   Interval attachment_x_;
   Real delta_y_;
   
   Tie_configuration ();
+  void center_tie_vertically (Tie_details const &);
+  Bezier get_bezier (Tie_details const &) const;
+  Real height (Tie_details const&) const;
   
   static int compare (Tie_configuration const &a,
                      Tie_configuration const &b);
+  static Real distance (Tie_configuration const &a,
+                      Tie_configuration const &b);
 };
+
 INSTANTIATE_COMPARE (Tie_configuration, Tie_configuration::compare);
 
 class Tie
@@ -35,15 +57,21 @@ public:
   static void set_direction (Grob *);
   static Grob *head (Grob *, Direction);
   static int get_column_rank (Grob *, Direction);
-  static Real get_position (Grob *);
+  static int get_position (Grob *);
   static Direction get_default_dir (Grob *);
-  static void get_configuration (Grob *, Grob **, Tie_configuration *);
-  static void set_control_points (Grob *, Grob **,Tie_configuration const&);
+  static void get_configuration (Grob *, Grob *, Tie_configuration *,
+                                Drul_array< Array<Skyline_entry> > const *,
+                                Tie_details const & 
+                                );
+  static void set_control_points (Grob *, Grob *,Tie_configuration const&,
+                                 Tie_details const&
+                                 );
   static void set_default_control_points (Grob *);
   DECLARE_SCHEME_CALLBACK (print, (SCM));
   DECLARE_SCHEME_CALLBACK (set_spacing_rods, (SCM));
   static int compare (Grob *const &s1,
                      Grob *const &s2);
+
   
 };
 
index 41aaa19039fa9a97eac3f76562e5e83bfca313a4..36046f19a61061f58accd6c639ebc43d71634824 100644 (file)
   A skyline is a shape of the form:
 
 
-  ----
-  |  |
-  ---------|  |
-  |          |
-  |          |
-  |          |______
-  --------|                 |___
-
-
+  *                  ----
+  *                  |  |
+  *         ---------|  |
+  *         |           |
+  *         |           |
+  *         |          |______
+  * --------|                |___
+  *
 
   This file deals with building such skyline structure, and computing
   the minimum distance between two opposing skylines.
 
-
   Invariants for a skyline:
 
   skyline[...].width_ forms a partition of the real interval, where
@@ -183,3 +181,22 @@ heighten_skyline (Array<Skyline_entry> *buildings, Real ground)
   for (int i = 0; i < buildings->size (); i++)
     buildings->elem_ref (i).height_ += ground;
 }
+
+Real
+skyline_height (Array<Skyline_entry> const &buildings,
+               Real airplane,
+               Direction sky_dir)
+{
+  Real h = - sky_dir * infinity_f;
+
+  /*
+    Ugh! linear, should be O(log n).
+   */
+  for (int i = 0; i < buildings.size (); i++)
+    if (buildings[i].width_.contains (airplane))
+      h = sky_dir * max (sky_dir * h,
+                        sky_dir * buildings[i].height_);
+  
+  return h;
+}
+
index 351feb2cc66c2ac64ffaca27e6e367ba2556a50f..cd1195f9b741329ea9e17de491146a51f193f288 100644 (file)
@@ -6,10 +6,13 @@
   (c) 2000--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
 */
 
-
 #include <math.h>
+
 #include <map>
+#include <set>
 
+#include "stem.hh"
+#include "skyline.hh"
 #include "staff-symbol-referencer.hh"
 #include "warn.hh"
 #include "tie-column.hh"
@@ -55,89 +58,6 @@ Tie::compare (Grob *const &s1,
   return sign (Tie::get_position (s1) - Tie::get_position (s2));
 }
 
-/*
-  Werner:
-
-  . The algorithm to choose the direction of the ties doesn't work
-  properly.  I suggest the following for applying ties sequentially
-  from top to bottom:
-
-  + The topmost tie is always `up'.
-
-  + If there is a vertical gap to the last note above larger than
-  or equal to a fifth (or sixth?), the tie is `up', otherwise it
-  is `down'.
-
-  + The bottommost tie is always `down'.
-*/
-void
-Tie_column::werner_directions (Grob *me)
-{
-  extract_grob_set (me, "ties", ro_ties);
-  Link_array<Grob> ties (ro_ties);
-  if (!ties.size ())
-    return;
-
-  ties.sort (&Tie::compare);
-
-  Direction d = get_grob_direction (me);
-  if (d)
-    {
-      for (int i = ties.size (); i--;)
-       {
-         Grob *t = ties[i];
-         if (!get_grob_direction (t))
-           set_grob_direction (t, d);
-       }
-      return;
-    }
-
-  if (ties.size () == 1)
-    {
-      Grob *t = ties[0];
-      if (t->is_live ()
-         && !get_grob_direction (t))
-       set_grob_direction (t, Tie::get_default_dir (t));
-      return;
-    }
-
-  Real last_down_pos = 10000;
-  if (!get_grob_direction (ties[0]))
-    set_grob_direction (ties[0], DOWN);
-
-  /*
-    Go downward.
-  */
-  Grob *last_tie = 0;
-  for (int i = ties.size (); i--;)
-    {
-      Grob *t = ties[i];
-
-      Direction d = get_grob_direction (t);
-      Real p = Tie::get_position (t);
-      if (!d)
-       {
-         if (last_tie
-             && Tie::get_column_rank (t, LEFT)
-             < Tie::get_column_rank (last_tie, LEFT))
-           d = DOWN;
-         else if (last_down_pos - p > 5)
-           d = UP;
-         else
-           d = DOWN;
-
-         set_grob_direction (t, d);
-       }
-
-      if (d == DOWN)
-       last_down_pos = p;
-
-      last_tie = t;
-    }
-
-  return;
-}
-
 MAKE_SCHEME_CALLBACK (Tie_column, after_line_breaking, 1);
 SCM
 Tie_column::after_line_breaking (SCM smob)
@@ -169,68 +89,86 @@ Tie_column::before_line_breaking (SCM smob)
   return SCM_UNSPECIFIED;
 }
 
-ADD_INTERFACE (Tie_column, "tie-column-interface",
-              "Object that sets directions of multiple ties in a tied chord",
-              "direction "
-              "positioning-done "
-              );
-
 
 
-
-bool
-config_allowed (map<Tie_configuration, bool> const &allowed,
-               Tie_configuration conf)
-{
-  return allowed.find (conf) == allowed.end ();
-}
-
 void
-add_configuration (map<Tie_configuration, bool> *allowed,
-                  Grob *tie_column,
-                  Tie_configuration new_conf)
+set_chord_outlines (Drul_array< Array<Skyline_entry> > *skyline_drul,
+                   Link_array<Grob> ties,
+                   Grob *common)
 {
-  bool on_line = Staff_symbol_referencer::on_staffline (tie_column, new_conf.position_);
-  
-  if (allowed->find (new_conf) != allowed->end ()
-      && !(*allowed)[new_conf])
-    {
-      programming_error ("Tie configuration not allowed");
-    }
-        
+  Direction d = LEFT;
 
-  if (on_line)
+  Real staff_space = Staff_symbol_referencer::staff_space (ties[0]);
+  do
     {
-      Tie_configuration forbidden;
+      Array<Box> boxes;
+      Interval x_union;
 
-      forbidden.dir_ = -new_conf.dir_ ;
-      forbidden.position_ = new_conf.position_;
-      (*allowed)[forbidden] = false;
+      Grob *stem = 0; 
+      for (int i = 0; i < ties.size (); i++)
+       {
+         Spanner *tie = dynamic_cast<Spanner*> (ties[i]);
+
+         Grob *head = Tie::head (tie, d);
+         if (!head)
+           continue;
+
+         if (!stem)
+           stem = unsmob_grob (head->get_object ("stem"));
+         
+         Real p = Tie::get_position (tie);
+         Interval y ((p-1) * 0.5 * staff_space,
+                     (p+1) * 0.5 * staff_space);
+
+         Interval x = head->extent (common, X_AXIS);
+         boxes.push (Box (x, y));
+         x_union.unite (x);
+       }
 
-      forbidden.position_ += new_conf.dir_;
-      (*allowed)[forbidden] = false;
-      forbidden.position_ += new_conf.dir_;
-      (*allowed)[forbidden] = false;
+      (*skyline_drul)[d] = empty_skyline (-d);
+      for (int i = 0; i < boxes.size (); i++)
+       insert_extent_into_skyline (&skyline_drul->elem_ref (d),
+                                   boxes[i], Y_AXIS, -d);
 
-      forbidden.dir_ = new_conf.dir_;
-      forbidden.position_ = new_conf.position_ + new_conf.dir_;
-      (*allowed)[forbidden] = false;
-    }
-  else
-    {
-      Tie_configuration forbidden;
-      forbidden.dir_ = - new_conf.dir_;
-      forbidden.position_ = new_conf.position_;
+      Direction updowndir = DOWN;
+      do
+       {
+         Box b = boxes.boundary (updowndir, 0);
+         Interval x = b[X_AXIS];
+         x[-d] =  b[X_AXIS].linear_combination (-d / 2);
+         if (stem
+             && !Stem::is_invisible (stem)
+             && updowndir == get_grob_direction (stem))
+           x.unite (robust_relative_extent (stem, common, X_AXIS));
+
+         (*skyline_drul)[d].boundary (updowndir, 0).height_ = x[-d]; 
+       }
+      while (flip (&updowndir) != DOWN);
 
-      
-      (*allowed)[forbidden] = false;
-      forbidden.position_ -= new_conf.dir_;
-      forbidden.dir_ = new_conf.dir_;
-      (*allowed)[forbidden] = false;
+      for (int i = 0; i < ties.size (); i++)
+       {
+         Spanner *tie = dynamic_cast<Spanner*> (ties[i]);
+         Grob *head = Tie::head (tie, d);
+         if (!head)
+           continue;
 
-      forbidden.position_ += 2* new_conf.dir_; 
-      (*allowed)[forbidden] = false;
+         Grob *dots = unsmob_grob (head->get_object ("dot"));
+         if (dots)
+           {
+             Interval x = dots->extent (common, X_AXIS);
+             Real p = Staff_symbol_referencer::get_position (dots);
+             
+             Interval y (-1,1);
+             y *= (staff_space /4);
+             y.translate ( p * staff_space * .5);
+
+             insert_extent_into_skyline (&skyline_drul->elem_ref (d),
+                                         Box (x,y), Y_AXIS, -d);
+           }
+       }
+      
     }
+  while (flip (&d) != LEFT);
 }
 
 
@@ -249,22 +187,37 @@ Tie_column::new_directions (Grob *me)
     }
   
   ties.sort (&Tie::compare);
+
   Array<Tie_configuration> tie_configs;
   for (int i = 0; i < ties.size (); i++)
     {
       Tie_configuration conf;
       conf.dir_ = get_grob_direction (ties[i]);
-      conf.position_ = (int) rint (Tie::get_position (ties[i]));
+      conf.position_ = Tie::get_position (ties[i]);
       tie_configs.push (conf);
     }
 
-    
+  SCM manual_configs = me->get_property ("tie-configuration");
+  bool manual_override = false;
+  int k = 0;
+  for (SCM s = manual_configs;
+       scm_is_pair (s) && k < tie_configs.size(); s = scm_cdr (s))
+    {
+      SCM entry = scm_car (s);
+      if (!scm_is_pair (entry))
+       continue;
+
+      manual_override = true;
+      tie_configs[k].position_ = robust_scm2double (scm_car (entry), tie_configs[k].position_);
+      tie_configs[k].dir_ = Direction (robust_scm2int (scm_cdr (entry), tie_configs[k].dir_));
+      k ++;
+    }
+
   if (!tie_configs[0].dir_)
     tie_configs[0].dir_ = DOWN;
   if (!tie_configs.top().dir_)
     tie_configs.top().dir_ = UP;
 
-
   /*
     Seconds
    */
@@ -287,66 +240,107 @@ Tie_column::new_directions (Grob *me)
       tie_configs[i].dir_ = (Direction) sign (tie_configs[i].position_);
     }
 
-  Grob *common[NO_AXES] = {
-    me, me
-  };
+  Grob *common = me;
   for (int i = 0; i < ties.size (); i++)
-    for (int a = X_AXIS; a < NO_AXES; a++)
-      {
-       Axis ax ((Axis) a);
-       
-       common[ax] = dynamic_cast<Spanner*> (ties[i])->get_bound (LEFT)->common_refpoint (common[a], ax); 
-       common[ax] = dynamic_cast<Spanner*> (ties[i])->get_bound (RIGHT)->common_refpoint (common[a], ax); 
-      }
-  
-  map<Tie_configuration, bool> allowed;
+    {
+      common = dynamic_cast<Spanner*> (ties[i])->get_bound (LEFT)->common_refpoint (common, X_AXIS); 
+      common = dynamic_cast<Spanner*> (ties[i])->get_bound (RIGHT)->common_refpoint (common, X_AXIS); 
+    }
 
-  Tie::get_configuration (ties[0], common, &tie_configs.elem_ref (0));
-  Tie::get_configuration (ties.top (), common,
-                         &tie_configs.elem_ref (tie_configs.size()-1));
+  Drul_array< Array<Skyline_entry> > skylines;
+  set_chord_outlines (&skylines, ties, common);
+  
+  Tie_details details;
+  details.init (ties[0]);
 
-  add_configuration (&allowed, me, tie_configs[0]);
-  add_configuration (&allowed, me, tie_configs.top());
+  /*
+    Let the ties flow out, according to our single-tie formatting.
+   */
+  if (!manual_override)
+    {
+      Tie::get_configuration (ties[0], common, &tie_configs.elem_ref (0),
+                             &skylines,
+                             details
+                             );
+      Tie::get_configuration (ties.top (), common,
+                             &tie_configs.elem_ref (tie_configs.size()-1),
+                             &skylines,
+                             details
+                             );
+    }
 
-  for (int i = 1; i < ties.size(); i++)
+  /*
+    Calculate final width and shape of the ties.
+   */
+  Real staff_space = Staff_symbol_referencer::staff_space (ties[0]);
+  Real gap = robust_scm2double (ties[0]->get_property ("x-gap"), 0.2);
+  for (int i = 0; i < ties.size(); i++)
     {
+      if (!manual_override
+         && (i == 0 || i == ties.size () -1))
+       continue;
+      
       Tie_configuration conf = tie_configs[i];
-      Tie::get_configuration (ties[i], common, &conf);
-      if (!config_allowed (allowed, conf))
-       {
-         conf = tie_configs[i];
+      conf = tie_configs[i];
+
+      Real line_dy = 0.0;
+      bool on_line = Staff_symbol_referencer::on_staffline (ties[0],
+                                                           int (rint (conf.position_)));
+      if (on_line)
+       line_dy = - sign (conf.height (details) - 0.6 * staff_space)
+         * 0.2 * staff_space * conf.dir_;
+
+      Real y = conf.position_ * staff_space * 0.5
+       + line_dy;
+      conf.attachment_x_
+       = get_skyline_attachment (skylines, y);
+      conf.attachment_x_.intersect (get_skyline_attachment (skylines,
+                                                           y + conf.dir_ * staff_space * .5));
+
+      conf.delta_y_ += line_dy;
+      conf.attachment_x_.widen (-gap);
+      if (!on_line
+         && Staff_symbol_referencer::staff_radius (ties[0]) * staff_space > y)
+       conf.center_tie_vertically (details);
+             
+      tie_configs[i] = conf;
+    }
 
-         Direction d = LEFT;
-         do
+  /*
+    Try to shift small ties into available spaces.
+   */
+  if (!manual_override)
+    {
+      set<int> positions_taken; 
+      for (int i = 0; i < tie_configs.size (); i++)
+       positions_taken.insert (int (rint (tie_configs[i].position_)));
+
+      for (int i = 0; i < tie_configs.size (); i++)
+       {
+         Tie_configuration * conf = &tie_configs.elem_ref (i);
+         if (Staff_symbol_referencer::on_staffline (ties[0], int (rint (conf->position_)))
+             && conf->height (details) < 0.4 * staff_space
+             && (positions_taken.find (int (rint (conf->position_ + conf->dir_)))
+                 == positions_taken.end ()))
            {
-             conf.attachment_x_[d] = d * 1e6; //  infty
-             for (int j = i - 1; j < i + 2; j++)
-               {
-                 if (j >= 0 && j < ties.size())
-                   {
-                     Spanner *t = dynamic_cast<Spanner*> (ties[j]);
-                     Interval ext
-                       = robust_relative_extent (t->get_bound (d),
-                                                 common[X_AXIS], X_AXIS);
-                     conf.attachment_x_[d]
-                       = d * min (d * conf.attachment_x_[d], d * ext[-d]);
-                   } 
-               }
+             positions_taken.insert (int (rint (conf->position_ + conf->dir_)));
+             conf->delta_y_ += 0.2 * staff_space * conf->dir_;
            }
-         while (flip (&d) != LEFT);
-         tie_configs[i] = conf;
        }
-      else
-       tie_configs[i] = conf;
-
-      add_configuration (&allowed, me, conf);
     }
-
+  
   for (int i = 0; i < ties.size(); i++)
     {
-      Tie::set_control_points (ties[i], common, tie_configs[i]);
+      Tie::set_control_points (ties[i], common, tie_configs[i],
+                              details
+                              );
       set_grob_direction (ties[i], tie_configs[i].dir_);
     }
 }
 
 
+ADD_INTERFACE (Tie_column, "tie-column-interface",
+              "Object that sets directions of multiple ties in a tied chord",
+              "positioning-done "
+              "tie-configuration "
+              );
diff --git a/lily/tie-helper.cc b/lily/tie-helper.cc
new file mode 100644 (file)
index 0000000..83f33f0
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+  tie-helper.cc -- implement Tie_configuration, Tie_details
+
+  source file of the GNU LilyPond music typesetter
+
+  (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+*/
+
+#include "tie.hh"
+#include "bezier.hh"
+#include "grob.hh"
+#include "staff-symbol-referencer.hh"
+
+
+int
+Tie_configuration::compare (Tie_configuration const &a,
+                           Tie_configuration const &b)
+{
+  if (a.position_ - b.position_)
+    return sign (a.position_ - b.position_);
+  return sign (a.dir_ - b.dir_);
+}
+                           
+
+Tie_configuration::Tie_configuration ()
+{
+  dir_ = CENTER;
+  position_ = 0;
+  delta_y_ = 0.0;
+}
+
+
+void
+Tie_configuration::center_tie_vertically (Tie_details const &details)
+{
+  Bezier b = get_bezier (details);
+  Offset middle = b.curve_point (0.5);
+  Offset edge = b.curve_point (0.0);
+
+  Real center = (edge[Y_AXIS] + middle[Y_AXIS])/2.0;
+
+  delta_y_ = - dir_ * center;
+}
+
+
+/*
+  Get bezier with left control at (0,0)
+ */
+Bezier
+Tie_configuration::get_bezier (Tie_details const &details) const
+{
+  return slur_shape (attachment_x_.length(),
+                    details.height_limit_,
+                    details.ratio_);
+}
+
+Real
+Tie_configuration::distance (Tie_configuration const &a,
+                            Tie_configuration const &b)
+{
+
+  Real d = 3 * (a.position_ - b.position_);
+  if (d < 0)
+    return d + (2 + (b.dir_ - a.dir_));
+  else
+    return d + (2 + (a.dir_ - b.dir_));
+}
+
+Real
+Tie_configuration::height (Tie_details const &details) const
+{
+  return slur_shape (attachment_x_.length(),
+                    details.height_limit_,
+                    details.ratio_).curve_point (0.5)[Y_AXIS]; 
+}
+
+
+void
+Tie_details::init (Grob *me)
+{
+  staff_space_ = Staff_symbol_referencer::staff_space (me);
+  SCM details = me->get_property ("details");
+  SCM limit
+    = scm_assq (ly_symbol2scm ("height-limit"), details);
+  height_limit_ = robust_scm2double (scm_cdr (limit), 0.75) * staff_space_;
+  ratio_ = robust_scm2double (scm_cdr (scm_assq (ly_symbol2scm ("ratio"), details)),
+                             .333);
+}
+
+Tie_details::Tie_details ()
+{
+  staff_space_ = 1.0; 
+  height_limit_ = 1.0;
+  ratio_ = .333;   
+}
+
index 40a8facc16e302c7f296bbc4d722f5bc70498b4d..4813ab197b97ef8658417287ba14e504722e7d0b 100644 (file)
@@ -65,11 +65,11 @@ Tie::get_column_rank (Grob *me, Direction d)
   return Paper_column::get_rank (col);
 }
 
-Real
+int
 Tie::get_position (Grob *me)
 {
   Direction d = head (me, LEFT) ? LEFT : RIGHT;
-  return Staff_symbol_referencer::get_position (head (me, d));
+  return (int) Staff_symbol_referencer::get_position (head (me, d));
 }
 
 /*
@@ -114,10 +114,87 @@ Tie::set_direction (Grob *me)
     }
 }
 
+Interval
+get_default_attachments (Spanner *me, Grob *common, Real gap,
+                        int *staff_position,
+                        bool *in_between
+                        )
+{
+  Real staff_space = Staff_symbol_referencer::staff_space (me);
+  Direction dir = get_grob_direction (me);
+  Interval attachments;
+  Direction d = LEFT;
+  do
+    {
+      attachments[d]
+       = robust_relative_extent (me->get_bound (d),
+                                 common,
+                                 X_AXIS)[-d]
+       - gap * d;
+    }
+  while (flip (&d) != LEFT);
+
+  if (attachments.length () < 0.6 * staff_space)
+    {
+      /*
+       Let short ties start over note heads, instead of between.
+      */
+      Drul_array<bool> allow (true, true);
+
+      Direction d = LEFT;
+      do {
+       if (Note_head::has_interface (me->get_bound (d)))
+         {
+           Grob *stem = unsmob_grob (me->get_bound (d)->get_object ("stem"));
+           if (get_grob_direction (stem) == dir
+               && -d == dir)
+             allow[d] = false;
+         }
+      } while (flip (&d) != LEFT);
+
+      if (allow[LEFT] && allow[RIGHT])
+       {
+         *staff_position += dir;
+         do
+           {
+             if (Note_head::has_interface (me->get_bound (d)))
+               {
+                 Interval extent
+                   = robust_relative_extent (me->get_bound (d),
+                                             common, X_AXIS);
+
+                 attachments[d] = extent.linear_combination (- 0.5 * d);
+                 *in_between = false;
+               }
+           }
+         while (flip (&d) != LEFT);
+       }
+    }
+
+  return attachments;
+}  
 
+Interval
+get_skyline_attachment (Drul_array< Array < Skyline_entry > > const &skylines,
+                       Real y)
+{
+  Interval attachments;
+  Direction d = LEFT;
+  do
+    {
+      attachments[d] = skyline_height (skylines[d], y, -d);
+    }
+  while (flip (&d) != LEFT);
+  
+  return attachments;
+}
+                       
 void
-Tie::get_configuration (Grob *me_grob, Grob **common,
-                       Tie_configuration *conf)
+Tie::get_configuration (Grob *me_grob, Grob *common,
+                       Tie_configuration *conf,
+                       Drul_array< Array < Skyline_entry > > const *skylines,
+                       Tie_details const &details
+                       )
 {
   Spanner *me = dynamic_cast<Spanner*> (me_grob);
   if (!head (me, LEFT) && !head (me, RIGHT))
@@ -130,7 +207,7 @@ Tie::get_configuration (Grob *me_grob, Grob **common,
   Direction dir = CENTER;
   
   int tie_position = (int) Tie::get_position (me);
-  int staff_position = conf->position_;
+  int staff_position = (int) conf->position_;
 
   if (conf->dir_)
     {
@@ -143,72 +220,28 @@ Tie::get_configuration (Grob *me_grob, Grob **common,
        dir = get_default_dir (me);
     }
 
-  Real staff_space = Staff_symbol_referencer::staff_space (me);
+  Real staff_space = details.staff_space_;
 
   bool in_between = true;
   Interval attachments = conf->attachment_x_;
+  Real gap = robust_scm2double (me->get_property ("x-gap"), 0.2);
   if (attachments.is_empty())
     {
-      Direction d = LEFT;
-      Real gap = robust_scm2double (me->get_property ("x-gap"), 0.2);
-      do
-       {
-         attachments[d]
-           = robust_relative_extent (me->get_bound (d),
-                                     common[X_AXIS],
-                                     X_AXIS)[-d]
-           - gap * d;
-       }
-      while (flip (&d) != LEFT);
-  
-      if (attachments.length () < 0.6 * staff_space)
+      if (!skylines)
+       attachments = get_default_attachments (me, common, gap,
+                                              &staff_position,
+                                              &in_between);
+      else
        {
-         /*
-           Let short ties start over note heads, instead of between.
-         */
-         Drul_array<bool> allow (true, true);
-
-         Direction d = LEFT;
-         do {
-           if (Note_head::has_interface (me->get_bound (d)))
-             {
-               Grob *stem = unsmob_grob (me->get_bound (d)->get_object ("stem"));
-               if (get_grob_direction (stem) == dir
-                   && -d == dir)
-                 allow[d] = false;
-             }
-         } while (flip (&d) != LEFT);
-
-         if (allow[LEFT] && allow[RIGHT])
-           {
-             staff_position += dir;
-             do
-               {
-                 if (Note_head::has_interface (me->get_bound (d)))
-                   {
-                     Interval extent
-                       = robust_relative_extent (me->get_bound (d),
-                                                 common[X_AXIS], X_AXIS);
-
-                     attachments[d] = extent.linear_combination (- 0.5 * d);
-                     in_between = false;
-                   }
-               }
-             while (flip (&d) != LEFT);
-           }
+         Real y = staff_space * 0.5 * staff_position;
+         attachments = get_skyline_attachment (*skylines, y);
+         attachments.widen (-gap);
        }
     }
-  SCM details = me->get_property ("details");
-
-  SCM limit
-    = scm_assq (ly_symbol2scm ("height-limit"), details);
-
-  Real h_inf = robust_scm2double (scm_cdr (limit), 0.75) * staff_space;
-  Real r_0 = robust_scm2double (scm_cdr (scm_assq (ly_symbol2scm ("ratio"), details)),
-                               .333);
 
   Bezier b = slur_shape (attachments.length(),
-                        h_inf, r_0);
+                        details.height_limit_,
+                        details.ratio_);
   b.scale (1, dir);
   
   Offset middle = b.curve_point (0.5);
@@ -282,17 +315,13 @@ Tie::get_configuration (Grob *me_grob, Grob **common,
   
   if (in_space)
     {
-      if (fabs (dy) < 0.4 * staff_space)
+      if (fabs (dy) < 0.45 * staff_space)
        {
          /*
            vertically center in space.
          */
-         Offset middle = b.curve_point (0.5);
-         Offset edge = b.curve_point (0.0);
-
-         Real center = (edge[Y_AXIS] + middle[Y_AXIS])/2.0;
-
-         conf->delta_y_ = - center;
+         conf->attachment_x_ = attachments;
+         conf->center_tie_vertically(details);
        }
       else
        {
@@ -314,6 +343,13 @@ Tie::get_configuration (Grob *me_grob, Grob **common,
 
   conf->dir_ = dir;
   conf->position_ = staff_position;
+
+  if (skylines)
+    {
+      Real y = staff_space * 0.5 * staff_position;
+      attachments = get_skyline_attachment (*skylines, y);
+      attachments.widen (-gap);
+    }
   conf->attachment_x_ = attachments;
 }
 
@@ -322,15 +358,9 @@ void
 Tie::set_default_control_points (Grob *me_grob)
 {
   Spanner *me = dynamic_cast<Spanner*> (me_grob);
-  Grob *common[NO_AXES] = {
-    0, 0
-  };
-  for (int a = X_AXIS; a < NO_AXES; a++)
-    {
-      Axis ax ((Axis) a); 
-      common[ax] = me->get_bound (LEFT)->common_refpoint (me, ax); 
-      common[ax] = me->get_bound (RIGHT)->common_refpoint (common[a], ax); 
-    }
+  Grob *common  = me;
+  common = me->get_bound (LEFT)->common_refpoint (common, X_AXIS); 
+  common = me->get_bound (RIGHT)->common_refpoint (common, X_AXIS); 
   
   Tie_configuration conf;
   if (!get_grob_direction (me))
@@ -338,33 +368,25 @@ Tie::set_default_control_points (Grob *me_grob)
 
   int tie_position = (int) Tie::get_position (me);
   conf.position_ = tie_position;
-
   
-  get_configuration (me, common, &conf);
-  set_control_points (me, common, conf);
+  Tie_details details;
+  details.init (me);
+  get_configuration (me, common, &conf, 0, details);
+  set_control_points (me, common, conf, details);
 }
 
 void
 Tie::set_control_points (Grob *me,
-                        Grob **common,
-                        Tie_configuration const &conf)
+                        Grob *common,
+                        Tie_configuration const &conf,
+                        Tie_details const &details
+                        )
 {
-  SCM details = me->get_property ("details");
-  SCM limit
-    = scm_assq (ly_symbol2scm ("height-limit"), details);
-
-  Real staff_space = Staff_symbol_referencer::staff_space (me);
-  Real h_inf = robust_scm2double (scm_cdr (limit), 0.75) * staff_space;
-  Real r_0 = robust_scm2double (scm_cdr (scm_assq (ly_symbol2scm ("ratio"),
-                                                  details)),
-                               .333);
-
-  Bezier b = slur_shape (conf.attachment_x_.length(),
-                        h_inf, r_0);
+  Bezier b = conf.get_bezier (details);
   b.scale (1, conf.dir_);
   b.translate (Offset (conf.attachment_x_[LEFT]
-                      - me->relative_coordinate (common[X_AXIS], X_AXIS),
-                      0.5 * conf.position_ * staff_space 
+                      - me->relative_coordinate (common, X_AXIS),
+                      0.5 * conf.position_ * details.staff_space_
                       + conf.delta_y_
                       ));
   
@@ -437,20 +459,3 @@ ADD_INTERFACE (Tie,
               "direction "
               "thickness "
               "x-gap ");
-
-int
-Tie_configuration::compare (Tie_configuration const &a,
-                           Tie_configuration const &b)
-{
-  if (a.position_ - b.position_)
-    return sign (a.position_ - b.position_);
-  return sign (a.dir_ - b.dir_);
-}
-                           
-
-Tie_configuration::Tie_configuration ()
-{
-  dir_ = CENTER;
-  position_ = 0;
-  delta_y_ = 0.0;
-}
index b53074f566c0bb3d96ade9b4e6d327027f2bf500..6f99647b16ccd9740c71e80871eddd9d7a47a2c4 100644 (file)
@@ -2543,13 +2543,6 @@ conversions.append (((2, 7, 4), conv,
 def conv (str):
        str = re.sub('Performer_group_performer', 'Performer_group', str)
        str = re.sub('Engraver_group_engraver', 'Engraver_group', str)
-       return str
-
-conversions.append (((2, 7, 6), conv,
-                    '''Performer_group_performer -> Performer_group, Engraver_group_engraver -> Engraver_group'''))
-
-
-def conv (str):
        str = re.sub (r"#'inside-slur\s*=\s*##t *",
                      r"#'avoid-slur = #'inside ", str)
        str = re.sub (r"#'inside-slur\s*=\s*##f *",
@@ -2558,6 +2551,7 @@ def conv (str):
                      r"#'avoid-slur", str)
        return str
 
-conversions.append (((2, 7, 7), conv,
-                    """inside-slur -> avoid-slur"""))
+conversions.append (((2, 7, 6), conv,
+                    '''Performer_group_performer -> Performer_group, Engraver_group_engraver -> Engraver_group
+inside-slur -> avoid-slur'''))
 
index fbf38dc1ded04bb0b1e5bd3b7aca1ef1d705ed52..a3c637534ab8387eb06c12fdcba5190b3ff0d542 100644 (file)
@@ -469,6 +469,8 @@ reading this property.")
 
      (threshold ,number-pair? "(@var{min} . @var{max}), where
 @var{min} and @var{max} are dimensions in staff space.")
+     (tie-configuration ,list? "List of (@var{position} . @var{dir})
+pairs, indicating the desired tie configuration.")
      (transparent ,boolean? "This is almost the same as setting
 @code{print-function} to @code{#f}, but this retains the dimensions of
 this grob, which means that grobs can be erased individually.")