]> git.donarmstrong.com Git - lilypond.git/commitdiff
* Documentation/topdocs/NEWS.tely (Top): document new feature.
authorHan-Wen Nienhuys <hanwen@xs4all.nl>
Tue, 13 Dec 2005 15:54:20 +0000 (15:54 +0000)
committerHan-Wen Nienhuys <hanwen@xs4all.nl>
Tue, 13 Dec 2005 15:54:20 +0000 (15:54 +0000)
* lily/tie-formatting-problem.cc (score_ties): new function
(get_variations): new function. Try flipping dirs for collisions.
(generate_optimal_chord_configuration): new function. 1-opt search
for better configuration.

* lily/tie-configuration.cc: new file.

* lily/tie.cc: junk Tie::get_configuration()

* lily/tie-formatting-problem.cc (score_ties_aptitude): new function.
(score_ties_configuration): new function.
(generate_ties_configuration): new function.
(generate_base_chord_configuration): new function.
(set_ties_config_standard_directions): Move body from tie-column-format.cc
(set_manual_tie_configuration): Move body from tie-column-format.cc

* lily/tie-formatting-problem.cc (score_configuration): score
tie/dot collisions.

* lily/tie-helper.cc (get_transformed_bezier): new function

* Documentation/topdocs/NEWS.tely (Top): strip out-www.

14 files changed:
ChangeLog
Documentation/topdocs/NEWS.tely
lily/include/lily-proto.hh
lily/include/tie-column-format.hh
lily/include/tie-configuration.hh [new file with mode: 0644]
lily/include/tie-formatting-problem.hh
lily/include/tie.hh
lily/laissez-vibrer-tie-column.cc
lily/tie-column-format.cc
lily/tie-column.cc
lily/tie-configuration.cc [new file with mode: 0644]
lily/tie-formatting-problem.cc
lily/tie-helper.cc
lily/tie.cc

index bf2afb82590f972c475e932f7332ba8786ce81ad..9e27e68e496c23043c37239d6d76944eda784f0f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,23 @@
 2005-12-13  Han-Wen Nienhuys  <hanwen@xs4all.nl>
 
+       * Documentation/topdocs/NEWS.tely (Top): document new feature.
+
+       * lily/tie-formatting-problem.cc (score_ties): new function
+       (get_variations): new function. Try flipping dirs for collisions.
+       (generate_optimal_chord_configuration): new function. 1-opt search
+       for better configuration.
+
+       * lily/tie-configuration.cc: new file.
+
+       * lily/tie.cc: junk Tie::get_configuration()
+
+       * lily/tie-formatting-problem.cc (score_ties_aptitude): new function.
+       (score_ties_configuration): new function.
+       (generate_ties_configuration): new function.
+       (generate_base_chord_configuration): new function.
+       (set_ties_config_standard_directions): Move body from tie-column-format.cc 
+       (set_manual_tie_configuration): Move body from tie-column-format.cc 
+
        * input/regression/tie-dot.ly: new file.
 
        * lily/tie-formatting-problem.cc (score_configuration): score
index 050f8889ee55372375c853c6aa6e1187b89a0ee0..a2e06d516bc1c8c0a86eda32ccd1fc1763dd44d4 100644 (file)
@@ -45,6 +45,20 @@ This document is also available in @uref{NEWS.pdf,PDF}.
 
 
 @itemize @bullet
+
+@item Ties in chords are also formatted using a scoring based
+formatting. This reduces the number of collisions for ties in
+chords, 
+
+@lilypond[raggedright,fragment,relative=2]
+  <b  d f g> ~  <b  d f g> 
+@end lilypond
+
+Here, the tie for the F is flipped, in spite the default rule for
+directions in chords.
+
+This rewrite was sponsored by Steve Doonan.
+
 @item With the @code{\tweak} music function, layout objects that are directly
 connected to input may be tuned easily,
 
index b0f413fb786822dfef249be5e02d704e3d787157..d7ea27aa7c39c2140eda6ee2d101fa6a01d2d15f 100644 (file)
@@ -161,7 +161,6 @@ class Tie;
 class Tie_details;
 class Tie_configuration;
 class Tie_formatting_problem;
-class Ties_configuration;
 class Tie_performer;
 class Time_scaled_music;
 class Time_scaled_music_iterator;
index dfdb5aa07d366dce394c005abb51530c406f7c0c..ffa43c9ad074523ccf0f518d8fbb14ad8c80c45c 100644 (file)
@@ -1,5 +1,5 @@
 /*
-  tie-column-format.hh -- declare
+  tie-column-format.hh -- declare Tie column format routines.
 
   source file of the GNU LilyPond music typesetter
 
@@ -10,7 +10,8 @@
 #ifndef TIE_COLUMN_FORMAT_HH
 #define TIE_COLUMN_FORMAT_HH
 
-
+#include "lily-proto.hh"
+#include "tie-configuration.hh"
 
 void set_chord_outline (Array<Skyline_entry> *skyline,
                        Link_array<Item> bounds,
diff --git a/lily/include/tie-configuration.hh b/lily/include/tie-configuration.hh
new file mode 100644 (file)
index 0000000..f3add86
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+  tie-configuration.hh -- declare Tie_configuration
+
+  source file of the GNU LilyPond music typesetter
+
+  (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+*/
+
+#ifndef TIE_CONFIGURATION_HH
+#define TIE_CONFIGURATION_HH
+
+#include "lily-proto.hh"
+#include "direction.hh"
+#include "interval.hh"
+#include "compare.hh"
+#include "array.hh"
+
+class Tie_configuration
+{
+public:
+  int position_;
+  Direction dir_;
+  Real delta_y_;
+
+  /* computed. */
+  Interval attachment_x_;
+  
+  Tie_configuration ();
+  void center_tie_vertically (Tie_details const &);
+  Bezier get_transformed_bezier (Tie_details const &) const;
+  Bezier get_untransformed_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);
+
+typedef Array<Tie_configuration> Ties_configuration;
+
+#endif /* TIE_CONFIGURATION_HH */
+
+
+
index 36afc52ff615edb16359e7b8bdae6850589c4fd8..34e0d10bb037f800df6a2856ec195c7ed85e4882 100644 (file)
@@ -14,6 +14,7 @@
 #include "parray.hh"
 #include "skyline.hh"
 #include "lily-proto.hh"
+#include "tie-configuration.hh"
 
 #include <map>
 #include <set>
@@ -34,22 +35,50 @@ struct Tie_details
 
 typedef map< pair<int, int>, Tie_configuration *> Tie_configuration_map;
 
+struct Tie_specification
+{
+  int position_;
+
+  bool has_manual_position_;
+  bool has_manual_dir_;
+  
+  Real manual_position_;
+  Direction manual_dir_;
+  
+  Tie_specification ();
+};
+
+struct Tie_configuration_variation
+{
+  int index_;
+  Tie_configuration *suggestion_;
+  Tie_configuration_variation ();
+};
+
 class Tie_formatting_problem
 {
   Drul_array< Array<Skyline_entry> > chord_outlines_;
   set<int> dot_positions_;
   Interval dot_x_;
+  Array<Tie_specification> specifications_;
   
   Tie_configuration_map possibilities_;
 
-  Tie_configuration *get_configuration (int position, Direction dir);
-  Tie_configuration *generate_configuration (int position, Direction dir);
-  Real score_configuration (Tie_configuration const&);
-  Real score_aptitude (Tie_configuration const&, int);
-  
   Grob *x_refpoint_;
 
   
+  Tie_configuration *get_configuration (int position, Direction dir);
+  Tie_configuration *generate_configuration (int position, Direction dir) const;
+  Array<Tie_configuration_variation> get_variations (Ties_configuration const &ties);
+
+  Real score_configuration (Tie_configuration const&) const;
+  Real score_aptitude (Tie_configuration const&, int) const;
+  Real score_ties_aptitude (Ties_configuration const &ties) const;
+  Real score_ties_configuration (Ties_configuration const &ties) const;
+  void set_ties_config_standard_directions (Ties_configuration *tie_configs_ptr);
+  Real score_ties (Ties_configuration const&) const;
+  Ties_configuration generate_base_chord_configuration ();
+  
 public:
   Tie_details details_;
 
@@ -57,12 +86,15 @@ public:
   Tie_formatting_problem ();
   ~Tie_formatting_problem ();
 
-  Tie_configuration find_optimal_tie_configuration (int p, Direction d);
+
+  Ties_configuration generate_optimal_chord_configuration ();
+  Ties_configuration generate_ties_configuration (Ties_configuration const &);
+  Tie_configuration find_optimal_tie_configuration (int p, Direction d) const;
   void from_ties (Link_array<Grob> const &ties);
   void from_tie (Grob *tie);
   void from_lv_ties (Link_array<Grob> const &);
   void set_chord_outline (Link_array<Item>, Direction);
-
+  void set_manual_tie_configuration (SCM);
   Interval get_attachment (Real) const;
   Grob *common_x_refpoint () const;
 };
index d78e5e1b142724016e4d44090b18e25f62a3fa8d..dc69e9c6a30e42b97124b1077fa43bcbdf33ffb6 100644 (file)
 
 
   
-class Tie_configuration
-{
-public:
-  int position_;
-  Direction dir_;
-  Real delta_y_;
-
-
-  /* computed. */
-  Interval attachment_x_;
-  Grob *tie_;
-  int head_position_;
-  
-  Tie_configuration ();
-  void center_tie_vertically (Tie_details const &);
-  Bezier get_transformed_bezier (Tie_details const &) const;
-  Bezier get_untransformed_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 Ties_configuration
-{
-public:
-  Array<Tie_configuration> ties_;
-};
 
 class Tie
 {
@@ -57,8 +25,12 @@ public:
   static int get_column_rank (Grob *, Direction);
   static int get_position (Grob *);
   static Direction get_default_dir (Grob *);
+
+#if 0
   static void get_configuration (Grob *, Tie_configuration *,
                                 Tie_formatting_problem const &);
+#endif
+  
   static void set_control_points (Grob *, Grob *,
                                  Tie_configuration const&,
                                  Tie_details const&);
@@ -73,7 +45,6 @@ public:
   static Interval get_default_attachments (Spanner *me, Grob *common, Real gap,
                                           int *staff_position, bool *in_between,
                                           Tie_details const &);
-  
 };
 
 
index a65de78ccc20600850169a0207055847a751b300..55e510a91edcd3678238a7c93cedf5d5b88f1d61 100644 (file)
@@ -16,8 +16,9 @@
 #include "pointer-group-interface.hh"
 #include "staff-symbol-referencer.hh"
 #include "item.hh"
-#include "tie-column-format.hh"
 #include "tie-formatting-problem.hh"
+#include "tie-configuration.hh"
+#include "tie-column-format.hh"
 
 
 ADD_INTERFACE(Laissez_vibrer_tie_column,
@@ -46,52 +47,21 @@ Laissez_vibrer_tie_column::calc_positioning_done (SCM smob)
   lv_ties.sort (&Laissez_vibrer_tie::compare);
 
   Ties_configuration ties_config;
-  for (int i = 0; i < lv_ties.size (); i++)
-    {
-      Tie_configuration conf;
-      conf.dir_ = CENTER;
-      Item *head = unsmob_item (lv_ties[i]->get_object ("note-head"));
-
-      if (head)
-       conf.position_ = (int) Staff_symbol_referencer::get_position (head);
-      
-      ties_config.ties_.push (conf);
-    }
-
-  bool manual_override = false;
-  SCM manual_configs = me->get_property ("tie-configuration");
-  set_manual_tie_configuration (&ties_config,
-                               &manual_override,
-                               manual_configs
-                               );
-
-  set_tie_config_directions (&ties_config);
+  
 
   Tie_formatting_problem problem;
+  
   problem.from_lv_ties (lv_ties);
 
-  /*
-    Calculate final width and shape of the ties.
-   */
-  for (int i = 0; i < lv_ties.size(); i++)
-    {
-      final_shape_adjustment (ties_config.ties_[i],
-                             problem, lv_ties[0]);
-    }
-  
-  /*
-    Try to shift small ties into available spaces.
-   */
-  if (!manual_override)
-    {
-      shift_small_ties (&ties_config, lv_ties[0], problem.details_);
-    }
-  
+  SCM manual_configs = me->get_property ("tie-configuration");
+  problem.set_manual_tie_configuration (manual_configs);
+
+  Ties_configuration base = problem.generate_optimal_chord_configuration ();
   for (int i = 0; i < lv_ties.size(); i++)
     {
-      Tie::set_control_points (lv_ties[i], problem.common_x_refpoint (), ties_config.ties_[i],
+      Tie::set_control_points (lv_ties[i], problem.common_x_refpoint (), base[i],
                               problem.details_);
-      set_grob_direction (lv_ties[i], ties_config.ties_[i].dir_);
+      set_grob_direction (lv_ties[i], base[i].dir_);
     }
 
   return SCM_BOOL_T;
index 1c6a3cb36241175415b69f58a99f47da083da8e5..91e65a3448d90a727bbe865ae27b11ec5235e11d 100644 (file)
 #include "directional-element-interface.hh"
 #include "rhythmic-head.hh"
 #include "tie-formatting-problem.hh"
+#include "tie-configuration.hh"
 
 #include <set>
 
-void
-set_manual_tie_configuration (Ties_configuration *ties_config,
-                             bool *manual_override,
-                             SCM manual_configs
-                             )
-{
-  *manual_override = false;
-  int k = 0;
-  for (SCM s = manual_configs;
-       scm_is_pair (s) && k < ties_config->ties_.size(); s = scm_cdr (s))
-    {
-      SCM entry = scm_car (s);
-      if (!scm_is_pair (entry))
-       continue;
-
-      *manual_override = true;
-      Tie_configuration &conf = ties_config->ties_.elem_ref (k);
-      
-      Real complete_pos = robust_scm2double (scm_car (entry),
-                                            conf.position_);
-
-      conf.position_ = int (rint (complete_pos));
-      conf.delta_y_ = complete_pos - conf.position_;
-      conf.dir_ = Direction (robust_scm2int (scm_cdr (entry),
-                                            conf.dir_));
-      k ++;
-    }
-}
 
 void
 shift_small_ties (Ties_configuration *tie_configs,
@@ -55,12 +28,12 @@ shift_small_ties (Ties_configuration *tie_configs,
                  Tie_details const &details)
 {
   set<int> positions_taken;
-  for (int i = 0; i < tie_configs->ties_.size (); i++)
-    positions_taken.insert (int (rint (tie_configs->ties_.elem (i).position_)));
+  for (int i = 0; i < tie_configs->size (); i++)
+    positions_taken.insert (int (rint (tie_configs->elem (i).position_)));
 
-  for (int i = 0; i < tie_configs->ties_.size (); i++)
+  for (int i = 0; i < tie_configs->size (); i++)
     {
-      Tie_configuration * conf = &tie_configs->ties_.elem_ref (i);
+      Tie_configuration * conf = &tie_configs->elem_ref (i);
 
       /*
        on staff line and small enough, translate a little further 
@@ -113,45 +86,4 @@ final_shape_adjustment (Tie_configuration &conf,
     conf.center_tie_vertically (details);
 }
 
-void
-set_tie_config_directions (Ties_configuration *tie_configs_ptr)
-{
-  Array<Tie_configuration> &tie_configs (tie_configs_ptr->ties_);
-  
-  if (!tie_configs[0].dir_)
-    tie_configs[0].dir_ = DOWN;
-  if (!tie_configs.top().dir_)
-    tie_configs.top().dir_ = UP;
-
-  /*
-    Seconds
-   */
-  for (int i = 1; i < tie_configs.size(); i++)
-    {
-      Real diff = tie_configs[i-1].position_
-       - tie_configs[i].position_;
-      
-      if (fabs (diff) <= 1)
-       {
-         if (!tie_configs[i-1].dir_)
-           tie_configs[i-1].dir_ = DOWN;
-         if (!tie_configs[i].dir_)
-           tie_configs[i].dir_ = UP;
-       }
-    }
-
-  for (int i = 1; i < tie_configs.size() - 1; i++)
-    {
-      Tie_configuration &conf = tie_configs.elem_ref (i);
-      if (conf.dir_)
-       continue;
-
-      Direction position_dir =
-       Direction (sign (conf.position_));
-      if (!position_dir)
-       position_dir = DOWN;
-
-      conf.dir_ = position_dir;
-    }
-}
                           
index 31b51592dc2d91093ff6de004f3ffacc89457c66..51bce9bc909fc4f719a5f39a3d54624f147f8ae4 100644 (file)
@@ -19,6 +19,7 @@
 #include "directional-element-interface.hh"
 #include "tie-column-format.hh"
 #include "tie-formatting-problem.hh"
+#include "tie-configuration.hh"
 
 using namespace std;
 
@@ -83,67 +84,22 @@ Tie_column::calc_positioning_done (SCM smob)
   
   ties.sort (&Tie::compare);
 
-  Ties_configuration ties_config;
-  for (int i = 0; i < ties.size (); i++)
-    {
-      Tie_configuration conf;
-      if (scm_is_number (ties[i]->get_property_data (ly_symbol2scm ("direction"))))
-       conf.dir_ = get_grob_direction (ties[i]);
-      conf.position_ = Tie::get_position (ties[i]);
-      ties_config.ties_.push (conf);
-    }
-
-  SCM manual_configs = me->get_property ("tie-configuration");
-  bool manual_override = false;
-  set_manual_tie_configuration (&ties_config,
-                               &manual_override,
-                               manual_configs);
-  set_tie_config_directions (&ties_config);
-
   Tie_formatting_problem problem;
   problem.from_ties (ties);
-  
-  /*
-    Let the ties flow out, according to our single-tie formatting.
-   */
-  if (!manual_override)
-    {
-      Tie::get_configuration (ties[0], &ties_config.ties_.elem_ref (0),
-                             problem);
-      Tie::get_configuration (ties.top (), 
-                             &ties_config.ties_.elem_ref (ties_config.ties_.size()-1),
-                             problem);
-    }
 
-  /*
-    Calculate final width and shape of the ties.
-   */
-  for (int i = 0; i < ties.size(); i++)
-    {
-      if (!manual_override
-         && (i == 0 || i == ties.size () -1))
-       continue;
+  SCM manual_configs = me->get_property ("tie-configuration");
+  problem.set_manual_tie_configuration (manual_configs);
 
 
-      final_shape_adjustment (ties_config.ties_[i],
-                             problem,
-                             ties[0]);
-    }
+  Ties_configuration base = problem.generate_optimal_chord_configuration ();
 
-  
-  /*
-    Try to shift small ties into available spaces.
-   */
-  if (!manual_override)
-    {
-      shift_small_ties (&ties_config, ties[0], problem.details_);
-    }
-  
-  for (int i = 0; i < ties.size(); i++)
+  for (int i = 0; i < base.size(); i++)
     {
-      Tie::set_control_points (ties[i], problem.common_x_refpoint (), ties_config.ties_[i],
+      Tie::set_control_points (ties[i], problem.common_x_refpoint (),
+                              base[i],
                               problem.details_);
-      set_grob_direction (ties[i], ties_config.ties_[i].dir_);
+      set_grob_direction (ties[i],
+                         base[i].dir_);
     }
   return SCM_BOOL_T;
 }
diff --git a/lily/tie-configuration.cc b/lily/tie-configuration.cc
new file mode 100644 (file)
index 0000000..39483b9
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+  tie-configuration.cc -- implement Tie_configuration
+
+  source file of the GNU LilyPond music typesetter
+
+  (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+*/
+
+#include "tie-configuration.hh"
+#include "warn.hh"
+#include "tie-formatting-problem.hh"
+#include "bezier.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_untransformed_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_transformed_bezier (Tie_details const &details) const
+{
+  Bezier b (get_untransformed_bezier (details));
+
+  b.scale (1, dir_);
+  b.translate (Offset (attachment_x_[LEFT],
+                      delta_y_ + details.staff_space_ * 0.5 * position_));
+
+  return b;
+}
+
+/*
+  Get bezier with left control at (0,0)
+ */
+Bezier
+Tie_configuration::get_untransformed_bezier (Tie_details const &details) const
+{
+  Real l = attachment_x_.length();
+  if (isnan (l) || isnan (l))
+    {
+      programming_error ("Inf or NaN encountered");
+      l = 1.0;
+    }
+  return slur_shape (l,
+                    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
+{
+  Real l = attachment_x_.length();
+
+  return slur_shape (l,
+                    details.height_limit_,
+                    details.ratio_).curve_point (0.5)[Y_AXIS]; 
+}
index 2fd6b6063b766aea9bd2394c6dfe89f90b13f62d..ae23935241c32d02f21fd2396ba823735c427871 100644 (file)
@@ -9,16 +9,17 @@
 
 #include "tie-formatting-problem.hh"
 
+#include "tie-configuration.hh"
 #include "directional-element-interface.hh"
 #include "staff-symbol-referencer.hh"
 #include "tie.hh"
-
 #include "item.hh"
 #include "spanner.hh" 
 #include "bezier.hh" 
 #include "stem.hh"
 #include "note-head.hh"
 #include "rhythmic-head.hh"
+#include "warn.hh"
 
 Interval
 Tie_formatting_problem::get_attachment (Real y) const
@@ -195,6 +196,22 @@ Tie_formatting_problem::from_ties (Link_array<Grob> const &ties)
       set_chord_outline (bounds, d);
     }
   while (flip (&d) != LEFT);
+
+
+  for (int i = 0; i < ties.size (); i++)
+    {
+      Tie_specification spec;
+      
+      if (scm_is_number (ties[i]->get_property_data (ly_symbol2scm ("direction"))))
+       {
+         spec.manual_dir_ = to_dir (ties[i]->get_property ("direction"));
+         spec.has_manual_dir_ = true;
+       }
+         
+      spec.position_ = Tie::get_position (ties[i]);
+      
+      specifications_.push (spec);
+    }
 }
 
 void
@@ -205,11 +222,19 @@ Tie_formatting_problem::from_lv_ties (Link_array<Grob> const &lv_ties)
   
   details_.from_grob (lv_ties[0]);
   Link_array<Item> heads;
+  
   for (int i = 0; i < lv_ties.size (); i++)
     {
+      Tie_specification spec;
       Item *head = unsmob_item (lv_ties[i]->get_object ("note-head"));
+       
       if (!head)
-       continue;
+       programming_error ("LV tie without head?!");
+
+      if (head)
+       {
+         spec.position_ = int (Staff_symbol_referencer::get_position (head));
+       }
       
       heads.push (head);
     }
@@ -237,7 +262,7 @@ Tie_formatting_problem::from_lv_ties (Link_array<Grob> const &lv_ties)
 }
 
 Tie_configuration*
-Tie_formatting_problem::get_configuration (int pos, Direction dir)
+Tie_formatting_problem::get_configuration (int pos, Direction dir) 
 {
   pair<int,int> key (pos, dir);
   Tie_configuration_map::const_iterator f = possibilities_.find (key);
@@ -254,7 +279,7 @@ Tie_formatting_problem::get_configuration (int pos, Direction dir)
 }
 
 Tie_configuration*
-Tie_formatting_problem::generate_configuration (int pos, Direction dir)
+Tie_formatting_problem::generate_configuration (int pos, Direction dir) const
 {
   Tie_configuration *conf = new Tie_configuration;
   conf->position_ = pos;
@@ -289,7 +314,7 @@ Tie_formatting_problem::generate_configuration (int pos, Direction dir)
 
 Real
 Tie_formatting_problem::score_aptitude (Tie_configuration const &conf,
-                                       int tie_position)
+                                       int tie_position) const
 {
   Real wrong_direction_offset_penalty_;
   Real distance_penalty_factor_;
@@ -309,7 +334,7 @@ Tie_formatting_problem::score_aptitude (Tie_configuration const &conf,
 
 
 Real
-Tie_formatting_problem::score_configuration (Tie_configuration const &conf)
+Tie_formatting_problem::score_configuration (Tie_configuration const &conf) const
 {
   Real length_penalty_factor = 1.0;
   Real min_length = 0.333;
@@ -372,7 +397,7 @@ Tie_formatting_problem::score_configuration (Tie_configuration const &conf)
 }
 
 Tie_configuration
-Tie_formatting_problem::find_optimal_tie_configuration (int pos, Direction dir)
+Tie_formatting_problem::find_optimal_tie_configuration (int pos, Direction dir) const
 {
   Link_array<Tie_configuration> confs;
 
@@ -405,3 +430,280 @@ Tie_formatting_problem::find_optimal_tie_configuration (int pos, Direction dir)
 
   return best;
 }
+
+Tie_specification::Tie_specification ()
+{
+  has_manual_position_ = false;
+  has_manual_dir_ = false;
+  position_ = 0;
+  manual_position_ = 0;
+  manual_dir_ = CENTER;
+}
+
+
+Real
+Tie_formatting_problem::score_ties_aptitude (Ties_configuration const &ties) const
+{
+  Real score = 0.0;
+  if  (ties.size () != specifications_.size ())
+    {
+      programming_error ("Huh? Mismatch between sizes.");
+      return infinity_f;
+    }
+
+  for (int i = 0; i < ties.size (); i++)
+    score += score_aptitude (ties[i], specifications_[i].position_);
+
+  return score;
+}
+
+Real
+Tie_formatting_problem::score_ties (Ties_configuration const &ties) const
+{
+  return score_ties_configuration (ties)
+    + score_ties_aptitude (ties);
+}
+
+Real
+Tie_formatting_problem::score_ties_configuration (Ties_configuration const &ties) const
+{
+  const Real tie_monotonicity_penalty = 100;
+  const Real tie_collision_penalty = 30;
+  const Real tie_collision_distance = 0.25;
+  
+  Real score = 0.0;
+  for (int i = 0; i < ties.size (); i++)
+    {
+      score += score_configuration (ties[i]);
+    }
+
+
+  Real last_edge = 0.0;
+  Real last_center = 0.0;
+  for (int i = 0; i < ties.size (); i++)
+    {
+      Bezier b (ties[i].get_transformed_bezier (details_));
+       
+      Real center = b.curve_point (0.5)[Y_AXIS];
+      Real edge = b.curve_point (0.0)[Y_AXIS];
+      
+      if (i)
+       {
+         if (edge <= last_edge)
+           score += tie_monotonicity_penalty;
+         if (center <= last_center)
+           score += tie_monotonicity_penalty;
+
+         score +=
+           tie_collision_penalty
+           * max (tie_collision_distance - fabs (center - last_center), 0.0) / tie_collision_distance;
+         score +=
+           tie_collision_penalty
+           * max (tie_collision_distance - fabs (edge - last_edge), 0.0) / tie_collision_distance;
+       }
+
+      last_edge = edge;
+      last_center = center;
+    }
+
+  return score;
+}
+
+/*
+  Generate with correct X-attachments and beziers, copying delta_y_
+  from TIES_CONFIG if necessary.
+*/
+Ties_configuration
+Tie_formatting_problem::generate_ties_configuration (Ties_configuration const &ties_config)
+{
+  Ties_configuration copy;
+  for (int i = 0; i < ties_config.size (); i++)
+    {
+      Tie_configuration * ptr = get_configuration (ties_config[i].position_, ties_config[i].dir_);
+      if (specifications_[i].has_manual_position_)
+       ptr->delta_y_ = specifications_[i].manual_position_;
+
+      copy.push (*ptr);
+    }
+  
+  return copy;
+}
+
+Ties_configuration
+Tie_formatting_problem::generate_base_chord_configuration () 
+{
+  Ties_configuration ties_config;
+  for (int i = 0;  i < specifications_.size (); i ++)
+    {
+      Tie_configuration conf;
+      if (specifications_[i].has_manual_dir_)
+       conf.dir_ = specifications_[i].manual_dir_;
+      if (specifications_[i].has_manual_position_)
+       {
+         conf.position_ = (int) round (specifications_[i].manual_position_);
+         conf.delta_y_ = (specifications_[i].manual_position_ - conf.position_)
+           * 0.5 * details_.staff_space_;
+       }
+      else
+       conf.position_ = specifications_[i].position_;
+      
+      ties_config.push (conf);
+    }
+
+  set_ties_config_standard_directions (&ties_config);
+
+  ties_config = generate_ties_configuration (ties_config);
+  
+  return ties_config;
+}
+
+Ties_configuration
+Tie_formatting_problem::generate_optimal_chord_configuration ()
+{
+  Ties_configuration base = generate_base_chord_configuration ();
+  Array<Tie_configuration_variation> vars = get_variations (base);
+
+  Ties_configuration best = base;
+  Real best_score = score_ties_configuration (best);
+
+  /*
+    This simply is 1-opt: we have K substitions, and we try applying
+    exactly every one for each.
+  */
+  for (int i = 0; i < vars.size (); i++)
+    {
+      Ties_configuration variant = base;
+      variant[vars[i].index_] = *vars[i].suggestion_;
+
+      Real score = (score_ties_configuration (variant)
+                   + score_ties_aptitude (variant));
+      if (score < best_score)
+       {
+         best = variant;
+         best_score = score;
+       }
+    }
+
+  return best;
+}
+
+void
+Tie_formatting_problem::set_ties_config_standard_directions (Ties_configuration *tie_configs)
+{
+  if (!tie_configs->elem (0).dir_)
+    tie_configs->elem_ref (0).dir_ = DOWN;
+  if (!tie_configs->top().dir_)
+    tie_configs->top().dir_ = UP;
+
+  /*
+    Seconds
+   */
+  for (int i = 1; i < tie_configs->size (); i++)
+    {
+      Real diff = (tie_configs->elem (i-1).position_
+                  - tie_configs->elem (i).position_);
+
+      if (fabs (diff) <= 1)
+       {
+         if (!tie_configs->elem (i-1).dir_)
+           tie_configs->elem_ref (i-1).dir_ = DOWN;
+         if (!tie_configs->elem (i).dir_)
+           tie_configs->elem_ref (i).dir_ = UP;
+       }
+    }
+
+  for (int i = 1; i < tie_configs->size() - 1; i++)
+    {
+      Tie_configuration &conf = tie_configs->elem_ref (i);
+      if (conf.dir_)
+       continue;
+
+      Direction position_dir =
+       Direction (sign (conf.position_));
+      if (!position_dir)
+       position_dir = DOWN;
+
+      conf.dir_ = position_dir;
+    }
+}
+
+Tie_configuration_variation::Tie_configuration_variation ()
+{
+  index_ = 0;
+  suggestion_ = 0;
+}
+
+Array<Tie_configuration_variation>
+Tie_formatting_problem::get_variations (Ties_configuration const &ties) 
+{
+  Real center_distance_tolerance = 0.25;
+  
+  Array<Tie_configuration_variation> vars;
+  Real last_center = 0.0;
+  for (int i = 0; i < ties.size (); i++)
+    {
+      Bezier b (ties[i].get_transformed_bezier (details_));
+       
+      Real center = b.curve_point (0.5)[Y_AXIS];
+      
+      if (i)
+       {
+         if (center <= last_center + center_distance_tolerance)
+           {
+             if (!specifications_[i].has_manual_dir_)
+               {
+                 Tie_configuration_variation var;
+                 var.index_ = i;
+                 var.suggestion_ = get_configuration (ties[i].position_,
+                                                      -ties[i].dir_);
+
+                 vars.push (var);
+               }
+
+             if (!specifications_[i-1].has_manual_dir_)
+               {
+                 Tie_configuration_variation var;
+                 var.index_ = i-1;
+                 var.suggestion_ = get_configuration (ties[i-1].position_,
+                                                      -ties[i-1].dir_);
+
+                 vars.push (var);
+               }
+           }
+       }
+
+      last_center = center;
+    }
+
+  return vars;
+  
+}
+
+void
+Tie_formatting_problem::set_manual_tie_configuration (SCM manual_configs)
+{
+  int k = 0;
+  for (SCM s = manual_configs;
+       scm_is_pair (s) && k < specifications_.size(); s = scm_cdr (s))
+    {
+      SCM entry = scm_car (s);
+      if (!scm_is_pair (entry))
+       continue;
+
+      Tie_specification &spec = specifications_[k];
+
+      if (scm_is_number (scm_cdr (entry)))
+       {
+         spec.has_manual_dir_ = true;
+         spec.manual_dir_ = Direction (scm_to_int (scm_cdr (entry)));
+       }
+      if (scm_is_number (scm_car (entry)))
+       {
+         spec.has_manual_position_ = true;
+         spec.manual_position_ = scm_to_double (scm_cdr (entry));
+       }
+         
+      k ++;
+    }
+}
+
index b0ec652d2bb18a150641d219fa0a079c2c9fb98e..454276b42b4d18c49d88628ff306932e3a8b1663 100644 (file)
 #include "warn.hh"
 #include "tie-formatting-problem.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_untransformed_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_transformed_bezier (Tie_details const &details) const
-{
-  Bezier b (get_untransformed_bezier (details));
-
-  b.scale (1, dir_);
-  b.translate (Offset (attachment_x_[LEFT],
-                      delta_y_ + details.staff_space_ * 0.5 * position_));
-
-  return b;
-}
-
-/*
-  Get bezier with left control at (0,0)
- */
-Bezier
-Tie_configuration::get_untransformed_bezier (Tie_details const &details) const
-{
-  Real l = attachment_x_.length();
-  if (isnan (l) || isnan (l))
-    {
-      programming_error ("Inf or NaN encountered");
-      l = 1.0;
-    }
-  return slur_shape (l,
-                    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
-{
-  Real l = attachment_x_.length();
-
-  return slur_shape (l,
-                    details.height_limit_,
-                    details.ratio_).curve_point (0.5)[Y_AXIS]; 
-}
-
-
-
 void
 Tie_details::from_grob (Grob *me)
 {
@@ -107,7 +21,6 @@ Tie_details::from_grob (Grob *me)
   staff_space_ = Staff_symbol_referencer::staff_space (me);
   SCM details = me->get_property ("details");
 
-
   height_limit_ = robust_scm2double (ly_assoc_get (ly_symbol2scm ("height-limit"), details, SCM_EOL),
                                     0.75) * staff_space_;
   
index 2b743a30ca956b89900c4b217f8c0d46d9df5f13..188e1df3bea6b751361ced8aade35df5ea6cda29 100644 (file)
@@ -22,6 +22,7 @@
 #include "tie-column.hh"
 #include "grob-array.hh"
 #include "tie-formatting-problem.hh"
+#include "tie-configuration.hh"
 
 
 int
@@ -193,211 +194,6 @@ Tie::get_default_attachments (Spanner *me, Grob *common, Real gap,
   return attachments;
 }  
 
-void
-Tie::get_configuration (Grob *me_grob, 
-                       Tie_configuration *conf,
-                       Tie_formatting_problem const &problem)
-{
-  Spanner *me = dynamic_cast<Spanner*> (me_grob);
-  if (!head (me, LEFT) && !head (me, RIGHT))
-    {
-      programming_error ("tie without heads");
-      me->suicide ();
-      return ;
-    }
-
-  /*
-    UGH. Don't mirror Tie_configuration.
-   */
-  conf->head_position_ = (int) Tie::get_position (me);
-  if (!conf->dir_)
-    conf->dir_ = get_grob_direction (me);
-  if (!conf->dir_)
-    conf->dir_ = get_default_dir (me);
-
-  Real staff_space = problem.details_.staff_space_;
-  bool in_between = true;
-  Real gap = robust_scm2double (me->get_property ("x-gap"), 0.2);
-
-  if (conf->attachment_x_.is_empty())
-    {
-#if 0
-      if (!skylines)
-       conf->attachment_x_ = get_default_attachments (me, common, gap,
-                                                      &conf->position_,
-                                                      &in_between, problem.details_);
-#endif
-      Real y = staff_space * 0.5 * conf->position_;
-      conf->attachment_x_ = problem.get_attachment (y);
-      conf->attachment_x_.widen (-gap);
-    }
-
-  Bezier b = slur_shape (conf->attachment_x_.length(),
-                        problem.details_.height_limit_,
-                        problem.details_.ratio_);
-  b.scale (1, conf->dir_);
-  
-  Offset middle = b.curve_point (0.5);
-  Offset edge = b.curve_point (0.0);
-
-  conf->position_ = int (rint (conf->position_));
-  
-  Real dy = fabs (middle[Y_AXIS] - edge[Y_AXIS]);
-  bool in_space = !(Staff_symbol_referencer::on_staffline (me, (int) conf->position_));
-  bool fits_in_space =
-    (dy < 0.6 * staff_space);
-  
-  /*
-    Avoid dot
-   */
-  Grob *left_dot = unsmob_grob (me->get_bound (LEFT)->get_object ("dot"));
-  int dot_pos = left_dot
-    ? int (Staff_symbol_referencer::get_position (left_dot))
-    : 0;
-  if (left_dot
-      && (conf->position_ == dot_pos
-         || conf->position_ + conf->dir_ == dot_pos))
-    {
-      conf->position_ += conf->dir_;
-      in_space = !in_space;
-
-      if (conf->position_ == dot_pos)
-       {
-         conf->position_ += conf->dir_;
-         in_space = !in_space;
-       }
-      
-      Real y = staff_space * 0.5 * conf->position_;
-      conf->attachment_x_ = problem.get_attachment (y);
-      conf->attachment_x_.widen (-gap);
-      Bezier b = slur_shape (conf->attachment_x_.length(),
-                            problem.details_.height_limit_,
-                            problem.details_.ratio_);
-      Offset middle = b.curve_point (0.5);
-      Offset edge = b.curve_point (0.0);
-      dy = fabs (middle[Y_AXIS] - edge[Y_AXIS]);
-      fits_in_space =
-       (dy < 0.6 * staff_space);
-    }
-  
-  /*
-    Avoid flag.
-  */
-  Grob *left_stem = unsmob_grob (me->get_bound (LEFT)->get_object ("stem"));
-  if (left_stem)
-    {
-      Stencil flag = Stem::get_translated_flag (left_stem);
-      Real y = conf->position_ * staff_space * 0.5;
-      if (flag.extent (Y_AXIS).contains (y))
-       {
-         conf->position_ += conf->dir_;
-         in_space = !in_space;
-       }
-    }
-
-  if (in_space != fits_in_space)
-    {
-      if (in_space)
-       {
-         conf->position_ += conf->dir_;
-       }
-      else
-       {
-         in_space = true;
-         conf->position_ += conf->dir_;
-       }
-
-      /*
-       ugh: code dup.
-      */
-      Real y = staff_space * 0.5 * conf->position_;
-      conf->attachment_x_ = problem.get_attachment (y);
-      conf->attachment_x_.widen (-gap);
-             
-      Bezier b = slur_shape (conf->attachment_x_.length(),
-                            problem.details_.height_limit_,
-                            problem.details_.ratio_);
-      Offset middle = b.curve_point (0.5);
-      Offset edge = b.curve_point (0.0);
-      dy = fabs (middle[Y_AXIS] - edge[Y_AXIS]);
-      fits_in_space =
-       (dy < 0.6 * staff_space);
-    }
-
-
-  /*
-    Putting larger in-space ties next to the notes forces
-    the edges to be opposite (Y-wise) to the tie direction.
-   */
-  if (conf->position_ == conf->head_position_
-      && in_space
-      && Staff_symbol_referencer::staff_radius (me) > abs (conf->position_) / 2
-      && dy > 0.3 * staff_space
-      )
-    {
-      conf->position_ += 2 * conf->dir_; 
-    }
-
-  if (!in_between
-      && in_space
-      && abs (conf->position_ - conf->head_position_) <= 1)
-    {
-      int amount = conf->dir_;
-      if (sign (conf->position_) != conf->dir_
-         || conf->position_ < Staff_symbol_referencer::staff_radius (me) * 2)
-       amount *= 2;
-
-      conf->position_ += amount;
-    }
-  
-  if (in_space)
-    {
-      if ((sign (conf->position_) != conf->dir_
-          || conf->position_ < Staff_symbol_referencer::staff_radius (me) * 2)
-         &&
-         ((abs (conf->position_ - conf->head_position_) <= 1
-           && fabs (dy) < 0.45 * staff_space)
-          || fabs (dy) < 0.6 * staff_space))
-       {
-         /*
-           vertically center in space.
-         */
-         conf->center_tie_vertically (problem.details_);
-       }
-      else
-       {
-         conf->delta_y_ = 
-           conf->dir_ * staff_space * (- 0.3);
-       }
-    }
-  else
-    {
-      Real where = 0.5 * conf->dir_;
-      
-      Real rounding_dy = (where - middle[Y_AXIS]);
-      conf->delta_y_ = rounding_dy;
-
-      if (conf->dir_ * (b.curve_point (0.0)[Y_AXIS]
-                + conf->position_ * staff_space * 0.5
-                + conf->delta_y_) <
-         conf->dir_ * conf->head_position_ * 0.5 * staff_space)
-       {
-         if (Staff_symbol_referencer::staff_radius (me) >  abs (conf->head_position_) / 2)
-           conf->position_ +=  2 * conf->dir_;
-         else
-           conf->position_ += conf->dir_;
-       }
-    }
-
-
-  Real half_space = 0.5 * staff_space;
-  Real y = conf->position_ * half_space;
-      
-  conf->attachment_x_ = problem.get_attachment (y);
-  conf->attachment_x_.widen (-gap);
-}
-
-
 void
 Tie::set_default_control_points (Grob *me_grob)
 {