]> git.donarmstrong.com Git - lilypond.git/commitdiff
Fix #138 & #139
authorHan-Wen Nienhuys <hanwen@xs4all.nl>
Fri, 12 Jan 2007 21:01:09 +0000 (22:01 +0100)
committerHan-Wen Nienhuys <hanwen@xs4all.nl>
Fri, 12 Jan 2007 21:01:09 +0000 (22:01 +0100)
- use chord formatting for single tie

- add all notes + accidentals to chord outline

- separate file for Tie_specification

- use convex_amplifier for distance penalties:
penalties increase superlinearly in distance

- tunable padding for skyline

- semi tie: set direction with ^ and _

- debug output for semities

- for single tie case, introduce penalty for wrong direction

- only add symmetry penalties for more than 1 tie.

- use exactness to determine whether to override delta_y_ too.

20 files changed:
input/regression/semi-tie-manual-direction.ly [new file with mode: 0644]
input/regression/tie-accidental.ly [new file with mode: 0644]
input/regression/tie-manual-vertical-tune.ly [new file with mode: 0644]
input/regression/tie-single-chord.ly [new file with mode: 0644]
lily/include/misc.hh
lily/include/tie-configuration.hh
lily/include/tie-details.hh
lily/include/tie-formatting-problem.hh
lily/include/tie-specification.hh [new file with mode: 0644]
lily/laissez-vibrer-engraver.cc
lily/misc.cc
lily/repeat-tie-engraver.cc
lily/semi-tie-column.cc
lily/tie-column.cc
lily/tie-configuration.cc
lily/tie-details.cc
lily/tie-formatting-problem.cc
lily/tie-specification.cc [new file with mode: 0644]
lily/tie.cc
scm/define-grobs.scm

diff --git a/input/regression/semi-tie-manual-direction.ly b/input/regression/semi-tie-manual-direction.ly
new file mode 100644 (file)
index 0000000..bfa4410
--- /dev/null
@@ -0,0 +1,16 @@
+
+\header {
+  texidoc = "Semi tie directions may be forced from the input."
+}
+
+\version "2.10.0"
+
+\layout{
+  ragged-right=##t
+}
+
+{
+  r4
+  c'^\laissezVibrer^\repeatTie
+  r4
+} 
diff --git a/input/regression/tie-accidental.ly b/input/regression/tie-accidental.ly
new file mode 100644 (file)
index 0000000..2f1ec24
--- /dev/null
@@ -0,0 +1,19 @@
+\header { texidoc = "
+  lilypond should flip the tie's direction
+  to avoid a collision with the sharp.
+" }
+
+
+\version "2.11.11"
+
+\paper {
+  debug-tie-scoring = ##t
+  ragged-right = ##t
+}
+
+\relative c'' {
+  \override Tie #'layer = #2
+  a ~ <fis a>
+}
+
+% EOF
diff --git a/input/regression/tie-manual-vertical-tune.ly b/input/regression/tie-manual-vertical-tune.ly
new file mode 100644 (file)
index 0000000..ed631d9
--- /dev/null
@@ -0,0 +1,23 @@
+\header {
+
+
+  texidoc = "If using integers, the tie will vertically tuned for
+staff line avoidance. If using a floating point number, this is taken
+as the exact location."
+
+}
+
+\version "2.11.11"
+
+\layout {
+  ragged-right = ##t
+}
+
+\version "2.10.0"
+\relative c'' {
+  \override Tie #'staff-position = #3
+  d4 ~
+  \override Tie #'staff-position = #3.0
+  d ~
+  d
+ }
diff --git a/input/regression/tie-single-chord.ly b/input/regression/tie-single-chord.ly
new file mode 100644 (file)
index 0000000..c6160ab
--- /dev/null
@@ -0,0 +1,17 @@
+\header {
+
+  texidoc = "Tie directions are also scored. In hairy configurations,
+  the default rule for tie directions is overruled."
+
+}
+
+\version "2.11.11"
+
+\paper
+{
+  ragged-right = ##t
+}
+
+\relative c' {
+  <f d'>~ <e f c'>
+}
index abef7b96c5a9f2093e44dd6971df5617d88071af..d0bb6f417b3f4dcef37ed47e1c73c87415c7ebc8 100644 (file)
@@ -38,6 +38,7 @@ linear_interpolate (Real x, Real x1, Real x2, Real y1, Real y2)
 Real directed_round (Real f, Direction d);
 
 Real peak_around (Real epsilon,  Real threshold, Real x);
+Real convex_amplifier (Real standard_x, Real x);
 string camel_case_to_lisp_identifier (string in);
 
 #endif
index 8801a7be7f5ee23e4889fdf215e6f1cbfab55822..d65604c1dc195f34264eeceebca5229db629fbe9 100644 (file)
@@ -68,6 +68,7 @@ public:
   void reset_score ();
   string card () const; 
   string tie_card (int i) const { return tie_score_cards_[i]; }
+  string complete_tie_card (vsize i) const;
   string complete_score_card () const; 
 };
 
index e30f3ed8661c972c1b8272749ce5923985180b86..18b9127d1e83937c31f6395d504275117892c2a9 100644 (file)
@@ -21,8 +21,10 @@ struct Tie_details
   Real stem_gap_; 
   Real between_length_limit_;
   Real wrong_direction_offset_penalty_;
+  Real same_dir_as_stem_penalty_;
   Real min_length_penalty_factor_;
   Real min_length_;
+  Real skyline_padding_;
   Real tip_staff_line_clearance_;
   Real center_staff_line_clearance_;
   Real staff_line_collision_penalty_;
index c5a71b0314b845c558e1120e5f986e41f19ef156..863712e99e0656828279f52048ef0a25b88440db 100644 (file)
 #include "skyline.hh"
 #include "tie-configuration.hh"
 #include "tie-details.hh"
+#include "tie-specification.hh"
 #include "tuple.hh"
 
 #include <map>
 #include <set>
 
 typedef map< Tuple<int,4>, Tie_configuration *> Tie_configuration_map;
-
-struct Tie_specification
-{
-  int position_;
-  Drul_array<Grob*> note_head_drul_;
-  Drul_array<int> column_ranks_;
-  
-  bool has_manual_position_;
-  bool has_manual_dir_;
-  
-  Real manual_position_;
-  Direction manual_dir_;
-  
-  Tie_specification ();
-  int column_span () const;
-  void get_tie_manual_settings (Grob *);
-};
-
 struct Tie_configuration_variation
 {
   int index_;
@@ -62,11 +45,13 @@ class Tie_formatting_problem
   Grob *x_refpoint_;
 
   
-  Tie_configuration *get_configuration (int position, Direction dir, Drul_array<int> cols) const;
-  Tie_configuration *generate_configuration (int position, Direction dir, Drul_array<int> cols) const;
+  Tie_configuration *get_configuration (int position, Direction dir, Drul_array<int> cols, bool tune_y) const;
+  Tie_configuration *generate_configuration (int position, Direction dir, Drul_array<int> cols, bool tune_y) const;
+
   vector<Tie_configuration_variation> generate_collision_variations (Ties_configuration const &ties) const;
   vector<Tie_configuration_variation> generate_extremal_tie_variations (Ties_configuration const &ties) const;
-
+  vector<Tie_configuration_variation> generate_single_tie_variations (Ties_configuration const &ties) const;
+  
   void score_configuration (Tie_configuration *) const;
   Real score_aptitude (Tie_configuration *, Tie_specification const &,
                       Ties_configuration *, int) const;
@@ -77,7 +62,7 @@ class Tie_formatting_problem
   
   Ties_configuration generate_base_chord_configuration ();
   Ties_configuration find_best_variation (Ties_configuration const &base,
-                                         vector<Tie_configuration_variation> vars);
+                                         vector<Tie_configuration_variation> const &vars);
 
 public:
   Tie_details details_;
@@ -91,9 +76,8 @@ public:
   ~Tie_formatting_problem ();
 
   Tie_specification get_tie_specification (int) const;
-  Ties_configuration generate_optimal_chord_configuration ();
+  Ties_configuration generate_optimal_configuration ();
   Ties_configuration generate_ties_configuration (Ties_configuration const &);
-  Tie_configuration find_optimal_tie_configuration (Tie_specification const &) const;
 
   void from_ties (vector<Grob*> const &ties);
   void from_tie (Grob *tie);
@@ -103,6 +87,7 @@ public:
   void set_manual_tie_configuration (SCM);
   Interval get_attachment (Real, Drul_array<int>) const;
   Grob *common_x_refpoint () const;
+  void set_debug_scoring (Ties_configuration const &);
 };
 
 #endif /* TIE_FORMATTING_PROBLEM_HH */
diff --git a/lily/include/tie-specification.hh b/lily/include/tie-specification.hh
new file mode 100644 (file)
index 0000000..912dc78
--- /dev/null
@@ -0,0 +1,36 @@
+/* 
+  tie-specification.hh -- declare  Tie_specification
+  
+  source file of the GNU LilyPond music typesetter
+  
+  (c) 2007 Han-Wen Nienhuys <hanwen@lilypond.org>
+  
+*/
+
+#ifndef TIE_SPECIFICATION_HH
+#define TIE_SPECIFICATION_HH
+
+#include "lily-proto.hh"
+#include "drul-array.hh"
+
+struct Tie_specification
+{
+  int position_;
+  Drul_array<Grob*> note_head_drul_;
+  Drul_array<int> column_ranks_;
+  Grob *tie_grob_;
+  
+  bool has_manual_position_;
+  bool has_manual_dir_;
+  bool has_manual_delta_y_;
+  
+  Real manual_position_;
+  Direction manual_dir_;
+  
+  Tie_specification ();
+  int column_span () const;
+  void from_grob (Grob *);
+};
+
+#endif /* TIE_SPECIFICATION_HH */
+
index 7a9a4dee72f2b99332021b4da9397c102ebe4fcf..a6a4bd0e2b98ed3ca226e43d3e144b966a854e46 100644 (file)
@@ -60,12 +60,20 @@ Laissez_vibrer_engraver::acknowledge_note_head (Grob_info inf)
     {
       lv_column_ = make_item ("LaissezVibrerTieColumn", event_->self_scm ());
     }
-  
-  Grob *lv_tie = make_item ("LaissezVibrerTie", event_->self_scm ());
+
+  SCM cause = event_->self_scm ();
+  Grob *lv_tie = make_item ("LaissezVibrerTie", cause);
   lv_tie->set_object ("note-head", inf.grob ()->self_scm ());
   
   Pointer_group_interface::add_grob (lv_column_, ly_symbol2scm ("ties"),
                                     lv_tie);
+
+  if (is_direction (unsmob_stream_event (cause)->get_property ("direction")))
+    {
+      Direction d = to_dir (unsmob_stream_event (cause)->get_property ("direction"));
+      lv_tie->set_property ("direction", scm_from_int (d)); 
+    }
+  
   lv_tie->set_parent (lv_column_, Y_AXIS);
 
   lv_ties_.push_back (lv_tie);
index c64983d8642fd224cdd32392ec719e9281c384c5..8d10141524466326886bd64b41982c620b8a8d3b 100644 (file)
@@ -56,6 +56,14 @@ peak_around (Real epsilon,  Real threshold, Real x)
   return max (- epsilon * (x - threshold) / ((x + epsilon)  * threshold), 0.0);
 }
 
+/*
+  0 at 0,  1 at standard_x, and increasing thereafter. 
+ */
+Real
+convex_amplifier (Real standard_x, Real x)
+{
+  return (exp (x / standard_x) - 1.0) / (exp (1) - 1.0); 
+}
 
 string
 camel_case_to_lisp_identifier (string in)
index bb23f7397390a943a59d34ce4f55aea52e567523..6b16fbc08841863d01be8fc7e3afc74ae746214a 100644 (file)
@@ -60,14 +60,23 @@ Repeat_tie_engraver::acknowledge_note_head (Grob_info inf)
     {
       semi_tie_column_ = make_item ("RepeatTieColumn", event_->self_scm ());
     }
-  
-  Grob *semi_tie = make_item ("RepeatTie", event_->self_scm ());
+
+  SCM cause = event_->self_scm ();
+  Grob *semi_tie = make_item ("RepeatTie", cause);
   semi_tie->set_object ("note-head", inf.grob ()->self_scm ());
   
   Pointer_group_interface::add_grob (semi_tie_column_, ly_symbol2scm ("ties"),
                                     semi_tie);
   semi_tie->set_parent (semi_tie_column_, Y_AXIS);
   semi_ties_.push_back (semi_tie);
+
+
+  if (is_direction (unsmob_stream_event (cause)->get_property ("direction")))
+    {
+      Direction d = to_dir (unsmob_stream_event (cause)->get_property ("direction"));
+      semi_tie->set_property ("direction", scm_from_int (d)); 
+    }
+
 }
 
 ADD_ACKNOWLEDGER (Repeat_tie_engraver, note_head);
index 3713bfdaab8808dd389c2774438a39c690cbcee9..c7d44a9568fa506c12196ba8f1285a97f45c137f 100644 (file)
@@ -55,7 +55,7 @@ Semi_tie_column::calc_positioning_done (SCM smob)
   SCM manual_configs = me->get_property ("tie-configuration");
   problem.set_manual_tie_configuration (manual_configs);
 
-  Ties_configuration base = problem.generate_optimal_chord_configuration ();
+  Ties_configuration base = problem.generate_optimal_configuration ();
   for (vsize i = 0; i < lv_ties.size(); i++)
     {
       SCM cp = Tie::get_control_points (lv_ties[i], problem.common_x_refpoint (), base[i],
@@ -63,8 +63,10 @@ Semi_tie_column::calc_positioning_done (SCM smob)
 
       lv_ties[i]->set_property ("control-points", cp);
       set_grob_direction (lv_ties[i], base[i].dir_);
-    }
 
+      problem.set_debug_scoring (base);
+    }
+  
   return SCM_BOOL_T;
 }
   
index 1f6738ef6d7cf4fc5512738bd2929d4111d3913c..9eefbbf8ee10252c5b3360152280c9e759703392 100644 (file)
@@ -79,14 +79,6 @@ Tie_column::calc_positioning_done (SCM smob)
   if (!ties.size ())
     return SCM_BOOL_T;
 
-  if (ties.size() == 1)
-    {
-      /*
-       Already handled by standard mechanisms.
-       */
-      return SCM_BOOL_T;
-    }
-  
   vector_sort (ties, Tie::less);
 
   Tie_formatting_problem problem;
@@ -96,7 +88,7 @@ Tie_column::calc_positioning_done (SCM smob)
   problem.set_manual_tie_configuration (manual_configs);
 
 
-  Ties_configuration base = problem.generate_optimal_chord_configuration ();
+  Ties_configuration base = problem.generate_optimal_configuration ();
 
   for (vsize i = 0; i < base.size(); i++)
     {
@@ -108,24 +100,7 @@ Tie_column::calc_positioning_done (SCM smob)
       set_grob_direction (ties[i],
                          base[i].dir_);
 
-#if DEBUG_TIE_SCORING
-      if (to_boolean (me->layout ()
-                     ->lookup_variable (ly_symbol2scm ("debug-tie-scoring"))))
-       {
-         string card = to_string ("%d (%.2f): ", base[i].position_, base[i].delta_y_)
-           + base[i].card () + base.tie_card (i);
-
-         
-         if (i == 0)
-           card += base.card ();
-         if (i == base.size () - 1)
-           card += to_string ("TOTAL=%.2f", base.score ());
-         
-         ties[i]->set_property ("quant-score",
-                                ly_string2scm (card));
-       }
-#endif
-      
+      problem.set_debug_scoring (base);
     }
   return SCM_BOOL_T;
 }
index ea69fe5a786008a5d13c5513512909921de80f2f..2491f7e3effaa6c52fbcc73975e82c660eb8d916 100644 (file)
@@ -158,15 +158,37 @@ Ties_configuration::score () const
 }
 
 
+string
+Ties_configuration::complete_tie_card (vsize i) const
+{
+  string s;
+  s += to_string ("%d (%.2f) %c: ", (*this)[i].position_, (*this)[i].delta_y_,
+                 ((*this)[i].dir_ == UP ? 'u' : 'd'))
+    + (*this)[i].card () + (*this).tie_card (i);
+  
+  /*
+    this is a little awkward, but we must decide where to put
+    aggregrates.
+   */
+  if (i == 0)
+    s += card ();
+
+  if (i + 1 == size ())
+    s += to_string ("TOTAL=%.2f", score ());
+  
+  return s;
+}
+
 /* for use inside GDB */
 string
 Ties_configuration::complete_score_card () const
 {
-  string s =  score_card_;
-  for (vsize i = 0; i < tie_score_cards_.size();  i++)
+  string s
+  for (vsize i = 0; i < size(); i++)
     {
-      s += "\n" + tie_score_cards_[i];
+      s += complete_tie_card (i);
     }
+
   return s;
 }
 
index c4ed37a2e48568c6bb41e9c8e1a7b5497d8b8466..ddb662fd308658cbe8df5a915aeb780e3efca0db 100644 (file)
@@ -54,6 +54,7 @@ Tie_details::from_grob (Grob *me)
   tie_tie_collision_penalty_ = get_real_detail ("tie-tie-collision-penalty", 30);
   tie_tie_collision_distance_ = get_real_detail ("tie-tie-collision-distance", .25);
   horizontal_distance_penalty_factor_ = get_real_detail ("horizontal-distance-penalty-factor", 5);
+  same_dir_as_stem_penalty_ = get_real_detail ("same-dir-as-stem-penalty", 20);
   vertical_distance_penalty_factor_ = get_real_detail ("vertical-distance-penalty-factor", 5);
   intra_space_threshold_ = get_real_detail ("intra-space-threshold", 1.0);
   outer_tie_length_symmetry_penalty_factor_ = get_real_detail ("outer-tie-length-symmetry-penalty-factor", 3.0);
@@ -62,6 +63,7 @@ Tie_details::from_grob (Grob *me)
   outer_tie_vertical_gap_ = get_real_detail ("outer-tie-vertical-gap", 0.15);
 
   single_tie_region_size_ = get_int_detail ("single-tie-region-size", 3);
+  skyline_padding_ = get_real_detail ("skyline-padding", 0.05);
   multi_tie_region_size_ = get_int_detail ("multi-tie-region-size", 1);
 }
 
index abcc342181f91095ed87430e2863906f047550e7..297fd4a1551ba33804939f6a770f6f7a4d2e6867 100644 (file)
@@ -22,7 +22,8 @@
 #include "tie-configuration.hh"
 #include "tie.hh"
 #include "warn.hh"
-
+#include "pointer-group-interface.hh"
+#include "output-def.hh"
 
 void
 Tie_formatting_problem::print_ties_configuration (Ties_configuration const *ties)
@@ -103,6 +104,9 @@ Tie_formatting_problem::set_column_chord_outline (vector<Item*> bounds,
          Interval x = dots->extent (x_refpoint_, X_AXIS);
          int p = int (Staff_symbol_referencer::get_position (dots));
 
+         /*
+           TODO: shouldn't this use column-rank dependent key?  
+         */
          dot_positions_.insert (p);
          dot_x_.unite (x);
 
@@ -115,45 +119,75 @@ Tie_formatting_problem::set_column_chord_outline (vector<Item*> bounds,
 
   Tuple2<int> key (column_rank, int (dir));
 
-  if (stem
-      && !Stem::is_invisible (stem))
+  if (stem)
     {
-      Interval x;
-      x.add_point (stem->relative_coordinate (x_refpoint_, X_AXIS));
-      x.widen (staff_space / 20); // ugh.
-      Interval y;
-      y.add_point (Stem::stem_end_position (stem) * staff_space * .5);
-
-      Direction stemdir = get_grob_direction (stem);
-      y.add_point (Stem::head_positions (stem)[-stemdir]
-                  * staff_space * .5);
-
-      boxes.push_back (Box (x, y));
+      if (Stem::is_normal_stem (stem))
+       {
+         
+         Interval x;
+         x.add_point (stem->relative_coordinate (x_refpoint_, X_AXIS));
+         x.widen (staff_space / 20); // ugh.
+         Interval y;
+         y.add_point (Stem::stem_end_position (stem) * staff_space * .5);
+
+         Direction stemdir = get_grob_direction (stem);
+         y.add_point (Stem::head_positions (stem)[-stemdir]
+                      * staff_space * .5);
+
+         /*
+           add extents of stem.
+         */
+         boxes.push_back (Box (x, y));
 
-      stem_extents_[key].unite (Box (x,y));
+         stem_extents_[key].unite (Box (x,y));
 
-      if (dir == LEFT)
+         if (dir == LEFT)
+           {
+             Box flag_box = Stem::get_translated_flag (stem).extent_box ();
+             flag_box.translate( Offset (x[RIGHT], X_AXIS));
+             boxes.push_back (flag_box);
+           }
+       }
+      else
        {
-         Box flag_box = Stem::get_translated_flag (stem).extent_box ();
-         flag_box.translate( Offset (x[RIGHT], X_AXIS));
-         boxes.push_back (flag_box);
+         Grob *head = Stem::support_head (stem);
+
+         /*
+           In case of invisible stem, don't pass x-center of heads.
+         */
+         Real x_center = head->extent (x_refpoint_, X_AXIS).center ();
+         Interval x_ext;
+         x_ext[-dir] = x_center;
+         Interval y_ext;
+         for (vsize j = 0; j < head_boxes.size (); j++)
+           y_ext.unite (head_boxes[j][Y_AXIS]);
+
+         boxes.push_back (Box (x_ext, y_ext));
        }
-    }
-  else if (stem)
-    {
-      Grob *head = Stem::support_head (stem);
 
-      /*
-       In case of invisible stem, don't pass x-center of heads.
-       */
-      Real x_center = head->extent (x_refpoint_, X_AXIS).center ();
-      Interval x_ext;
-      x_ext[-dir] = x_center;
-      Interval y_ext;
-      for (vsize j = 0; j < head_boxes.size (); j++)
-       y_ext.unite (head_boxes[j][Y_AXIS]);
+      extract_grob_set (stem, "note-heads", heads);
+      for (vsize i = 0; i < heads.size(); i ++)
+       {
+         if (find (bounds.begin(), bounds.end (), dynamic_cast<Item*> (heads[i])) !=  bounds.end ())
+           continue;
 
-      boxes.push_back (Box (x_ext, y_ext));
+         /*
+           other untied notes in the same chord.
+          */
+         
+         Interval y = Staff_symbol_referencer::extent_in_staff (heads[i]);
+         Interval x = heads[i]->extent (x_refpoint_, X_AXIS);
+         boxes.push_back (Box (x, y));
+
+         
+         Grob *acc = unsmob_grob (heads[i]->get_object ("accidental-grob"));
+         if (acc && dir == RIGHT)
+           {
+             boxes.push_back (Box (acc->extent (x_refpoint_, X_AXIS),
+                                   Staff_symbol_referencer::extent_in_staff (acc)));
+           }
+       }
+      
     }
   
   Direction updowndir = DOWN;
@@ -176,7 +210,7 @@ Tie_formatting_problem::set_column_chord_outline (vector<Item*> bounds,
   while (flip (&updowndir) != DOWN);
 
   /* todo: the horizon_padding is somewhat arbitrary */
-  chord_outlines_[key] = Skyline (boxes, 0.1, Y_AXIS, -dir);
+  chord_outlines_[key] = Skyline (boxes, details_.skyline_padding_, Y_AXIS, -dir);
   if (bounds[0]->break_status_dir ())
     {
       Real x = robust_relative_extent (bounds[0],  x_refpoint_, X_AXIS)[-dir];
@@ -273,9 +307,13 @@ Tie_formatting_problem::from_ties (vector<Grob*> const &ties)
                = dynamic_cast<Item*> (unsmob_grob (ties[i]->get_object ("separation-item")));
              if (sep && sep->get_column () == it->get_column ())
                it = sep;
+
+             bounds.push_back (it);
+           }
+         else 
+           {
+             bounds.push_back (it);
            }
-         
-         bounds.push_back (it);
        }
       
       set_chord_outline (bounds, d);
@@ -286,10 +324,7 @@ Tie_formatting_problem::from_ties (vector<Grob*> const &ties)
   for (vsize i = 0; i < ties.size (); i++)
     {
       Tie_specification spec;
-
-      spec.get_tie_manual_settings (ties[i]);
-      
-
+      spec.from_grob (ties[i]);
       
       do
        {
@@ -324,7 +359,7 @@ Tie_formatting_problem::from_semi_ties (vector<Grob*> const &semi_ties, Directio
          spec.position_ = int (Staff_symbol_referencer::get_position (head));
        }
 
-      spec.get_tie_manual_settings (semi_ties[i]);
+      spec.from_grob (semi_ties[i]);
       
       spec.note_head_drul_[head_dir] = head;
       column_rank = Tie::get_column_rank (semi_ties[i], head_dir);
@@ -361,7 +396,8 @@ Tie_formatting_problem::get_tie_specification (int i) const
   Return configuration, create it if necessary. 
 */
 Tie_configuration*
-Tie_formatting_problem::get_configuration (int pos, Direction dir, Drul_array<int> columns) const
+Tie_formatting_problem::get_configuration (int pos, Direction dir, Drul_array<int> columns,
+                                          bool tune_dy) const
 {
   int key_components[] = {
     pos, dir, columns[LEFT], columns[RIGHT]
@@ -375,14 +411,14 @@ Tie_formatting_problem::get_configuration (int pos, Direction dir, Drul_array<in
     }
 
   
-  Tie_configuration *conf = generate_configuration (pos, dir, columns);
+  Tie_configuration *conf = generate_configuration (pos, dir, columns, tune_dy);
   ((Tie_formatting_problem*) this)->possibilities_[key] = conf;
   return conf;
 }
 
 Tie_configuration*
 Tie_formatting_problem::generate_configuration (int pos, Direction dir,
-                                               Drul_array<int> columns) const
+                                               Drul_array<int> columns, bool y_tune) const
 {
   Tie_configuration *conf = new Tie_configuration;
   conf->position_ = pos;
@@ -392,7 +428,6 @@ Tie_formatting_problem::generate_configuration (int pos, Direction dir,
   
   Real y = conf->position_ * 0.5 * details_.staff_space_;
 
-  bool y_tune = true;
   if (dot_positions_.find (pos) != dot_positions_.end ())
     {
       conf->delta_y_ += dir * 0.25 * details_.staff_space_;
@@ -539,7 +574,7 @@ Tie_formatting_problem::score_aptitude (Tie_configuration *conf,
     }
 
   {
-    Real p = details_.vertical_distance_penalty_factor_ * fabs (curve_y - tie_y);
+    Real p = details_.vertical_distance_penalty_factor_ * convex_amplifier (1.0, fabs (curve_y - tie_y));
     if (ties_conf)
       ties_conf->add_tie_score (p, tie_idx, "vdist");
     else
@@ -554,22 +589,67 @@ Tie_formatting_problem::score_aptitude (Tie_configuration *conf,
       
       Interval head_x = spec.note_head_drul_[d]->extent (x_refpoint_, X_AXIS);
       Real dist = head_x.distance (conf->attachment_x_[d]);
+      
 
       /*
        TODO: flatten with log or sqrt.
        */
-      Real p = details_.horizontal_distance_penalty_factor_ * dist;
+      Real p = details_.horizontal_distance_penalty_factor_
+       * convex_amplifier (1.25, dist);
       if (ties_conf)
        ties_conf->add_tie_score (p, tie_idx,
                                  (d == LEFT) ? "lhdist" : "rhdist");
       else
        penalty += p;
+
     }
   while (flip (&d) != LEFT);
 
+  if (ties_conf
+      && ties_conf->size() == 1)
+    {
+      Direction d = LEFT;
+      Drul_array<Grob*> stems (0, 0);
+      do
+       {
+         if (!spec.note_head_drul_[d])
+           continue;
+
+         Grob *stem = unsmob_grob (spec.note_head_drul_[d]->get_object ("stem"));
+         if (stem
+             && Stem::is_normal_stem (stem))
+           stems[d] = stem;
+       }
+      while (flip (&d) != LEFT);
+
+      bool tie_stem_dir_ok = true;
+      bool tie_position_dir_ok = true;
+      if (stems[LEFT] && !stems[RIGHT])
+       tie_stem_dir_ok = conf->dir_ != get_grob_direction (stems[LEFT]);
+      else if (!stems[LEFT] && stems[RIGHT])
+       tie_stem_dir_ok = conf->dir_ != get_grob_direction (stems[RIGHT]);
+      else if (stems[LEFT] && stems[RIGHT]
+         && get_grob_direction (stems[LEFT]) == get_grob_direction (stems[RIGHT]))
+       tie_stem_dir_ok = conf->dir_ != get_grob_direction (stems[LEFT]);
+      else if (spec.position_)
+       tie_position_dir_ok = conf->dir_ == sign (spec.position_);
+
+      if (!tie_stem_dir_ok)
+       ties_conf->add_score (details_.same_dir_as_stem_penalty_, "tie/stem dir");
+      if (!tie_position_dir_ok)
+       ties_conf->add_score (details_.same_dir_as_stem_penalty_, "tie/pos dir");
+    }
+  while (flip (&d) != LEFT);
+
+           
   return penalty;
 }
 
+
+/*
+  Score a configuration, ie. how well these ties looks without regard
+  to the note heads that they should connect to.
+ */
 void
 Tie_formatting_problem::score_configuration (Tie_configuration *conf) const
 {
@@ -598,7 +678,7 @@ Tie_formatting_problem::score_configuration (Tie_configuration *conf) const
       conf->add_score (
        details_.staff_line_collision_penalty_
        * peak_around (0.1 * details_.center_staff_line_clearance_,
-                    details_.center_staff_line_clearance_,
+                      details_.center_staff_line_clearance_,
                       fabs (top_pos - round_top_pos)),
        "line center");
     }
@@ -639,96 +719,6 @@ Tie_formatting_problem::score_configuration (Tie_configuration *conf) const
   conf->scored_ = true;
 }
 
-Tie_configuration
-Tie_formatting_problem::find_optimal_tie_configuration (Tie_specification const &spec) const
-{
-  vector<Tie_configuration*> confs;
-
-  int pos = spec.position_;
-  Direction dir = spec.manual_dir_;
-
-  for (int i = 0; i < details_.single_tie_region_size_; i ++)
-    {
-      confs.push_back (generate_configuration (pos + i * dir, dir,
-                                              spec.column_ranks_));
-      
-      if (spec.has_manual_position_)
-       {
-         confs.back ()->delta_y_
-           = (spec.manual_position_ - spec.position_)
-           * 0.5 * details_.staff_space_;
-
-         break;
-       }
-    }
-
-  vector<Real> scores;
-
-  int best_idx = -1;
-  Real best_score = 1e6;
-  for (vsize i = 0; i < confs.size (); i ++)
-    {
-      score_configuration (confs[i]);
-      Real score = score_aptitude (confs[i], spec, 0, 0)
-       + confs[i]->score ();
-
-      if (score < best_score)
-       {
-         best_score = score;
-         best_idx = i;
-       }
-    }
-
-  if (best_idx < 0)
-    programming_error ("No best tie configuration found.");
-
-  Tie_configuration best
-    = (best_idx >= 0) ?  *confs[best_idx] : *confs[0];
-  
-  for (vsize i = 0; i < confs.size (); i++)
-    delete confs[i];
-
-  return best;
-}
-
-Tie_specification::Tie_specification ()
-{
-  has_manual_position_ = false;
-  has_manual_dir_ = false;
-  position_ = 0;
-  manual_position_ = 0;
-  manual_dir_ = CENTER;
-  note_head_drul_[LEFT] =
-    note_head_drul_[RIGHT] = 0;
-  column_ranks_[RIGHT] =
-    column_ranks_[LEFT] = 0;
-}
-
-
-void
-Tie_specification::get_tie_manual_settings (Grob *tie)
-{
-  if (scm_is_number (tie->get_property_data ("direction")))
-    {
-      manual_dir_ = to_dir (tie->get_property ("direction"));
-      has_manual_dir_ = true;
-    }
-  
-  position_ = Tie::get_position (tie);
-  if (scm_is_number (tie->get_property ("staff-position")))
-    {
-      manual_position_ = scm_to_double (tie->get_property ("staff-position"));
-      has_manual_position_ = true;
-      position_ = int (my_round (manual_position_));
-    }
-}
-
-int
-Tie_specification::column_span () const
-{
-  return column_ranks_[RIGHT] - column_ranks_[LEFT];
-}
-
 void
 Tie_formatting_problem::score_ties_aptitude (Ties_configuration *ties) const
 {
@@ -794,21 +784,23 @@ Tie_formatting_problem::score_ties_configuration (Ties_configuration *ties) cons
       last_center = center;
     }
 
-  ties->add_score (details_.outer_tie_length_symmetry_penalty_factor_
-                  * fabs (ties->at (0).attachment_x_.length () - ties->back ().attachment_x_.length ()),
-                  "length symm");
+  if (ties->size () > 1)
+    {
+      ties->add_score (details_.outer_tie_length_symmetry_penalty_factor_
+                      * fabs (ties->at (0).attachment_x_.length () - ties->back ().attachment_x_.length ()),
+                      "length symm");
   
-  ties->add_score (details_.outer_tie_vertical_distance_symmetry_penalty_factor_
-                  * fabs (fabs (specifications_[0].position_ * 0.5 * details_.staff_space_
-                                - (ties->at (0).position_ * 0.5 * details_.staff_space_
-                                   + ties->at (0).delta_y_))
-                          -
-                          fabs (specifications_.back ().position_ * 0.5 * details_.staff_space_
-                                - (ties->back ().position_ * 0.5 * details_.staff_space_
-                                   + ties->back ().delta_y_))),
-                  "pos symmetry");
+      ties->add_score (details_.outer_tie_vertical_distance_symmetry_penalty_factor_
+                      * fabs (fabs (specifications_[0].position_ * 0.5 * details_.staff_space_
+                                    - (ties->at (0).position_ * 0.5 * details_.staff_space_
+                                       + ties->at (0).delta_y_))
+                              -
+                              fabs (specifications_.back ().position_ * 0.5 * details_.staff_space_
+                                    - (ties->back ().position_ * 0.5 * details_.staff_space_
+                                       + ties->back ().delta_y_))),
+                      "pos symmetry");
+    }
 }
-
 /*
   Generate with correct X-attachments and beziers, copying delta_y_
   from TIES_CONFIG if necessary.
@@ -820,8 +812,9 @@ Tie_formatting_problem::generate_ties_configuration (Ties_configuration const &t
   for (vsize i = 0; i < ties_config.size (); i++)
     {
       Tie_configuration * ptr = get_configuration (ties_config[i].position_, ties_config[i].dir_,
-                                                  ties_config[i].column_ranks_);
-      if (specifications_[i].has_manual_position_)
+                                                  ties_config[i].column_ranks_,
+                                                  !specifications_[i].has_manual_delta_y_);
+      if (specifications_[i].has_manual_delta_y_)
        {
          ptr->delta_y_
            = (specifications_[i].manual_position_ - ties_config[i].position_)
@@ -845,8 +838,9 @@ Tie_formatting_problem::generate_base_chord_configuration ()
       if (specifications_[i].has_manual_position_)
        {
          conf.position_ = (int) my_round (specifications_[i].manual_position_);
-         conf.delta_y_ = (specifications_[i].manual_position_ - conf.position_)
-           * 0.5 * details_.staff_space_;
+         if (specifications_[i].has_manual_delta_y_)
+           conf.delta_y_ = (specifications_[i].manual_position_ - conf.position_)
+             * 0.5 * details_.staff_space_;
        }
       else
        {
@@ -869,7 +863,7 @@ Tie_formatting_problem::generate_base_chord_configuration ()
 
 Ties_configuration
 Tie_formatting_problem::find_best_variation (Ties_configuration const &base,
-                                            vector<Tie_configuration_variation> vars)
+                                            vector<Tie_configuration_variation> const &vars)
 {
   Ties_configuration best = base;
   
@@ -897,16 +891,24 @@ Tie_formatting_problem::find_best_variation (Ties_configuration const &base,
                                       
 
 Ties_configuration
-Tie_formatting_problem::generate_optimal_chord_configuration ()
+Tie_formatting_problem::generate_optimal_configuration ()
 {
   Ties_configuration base = generate_base_chord_configuration ();
-  vector<Tie_configuration_variation> vars = generate_collision_variations (base);
-  
   score_ties (&base);
+
+  vector<Tie_configuration_variation> vars;  
+  if (specifications_.size () > 1)
+    vars = generate_collision_variations (base);
+  else
+    vars = generate_single_tie_variations (base);
+
   Ties_configuration best = find_best_variation (base, vars);
-  vars = generate_extremal_tie_variations (best);
-  best = find_best_variation (best, vars);
 
+  if (specifications_.size () > 1)
+    {
+      vars = generate_extremal_tie_variations (best);
+      best = find_best_variation (best, vars);
+    }
   return best;
 }
 
@@ -990,7 +992,8 @@ Tie_formatting_problem::generate_extremal_tie_variations (Ties_configuration con
            var.index_ = (d == DOWN) ? 0 : ties.size () - 1;
            var.suggestion_ = get_configuration (boundary (ties, d, 0).position_
                                                 + d * i, d,
-                                                boundary (ties, d, 0).column_ranks_);
+                                                boundary (ties, d, 0).column_ranks_,
+                                                true);
            vars.push_back (var);
          }
     }
@@ -999,6 +1002,41 @@ Tie_formatting_problem::generate_extremal_tie_variations (Ties_configuration con
   return vars;
 }
 
+vector<Tie_configuration_variation>
+Tie_formatting_problem::generate_single_tie_variations (Ties_configuration const &ties) const
+{
+  vector<Tie_configuration_variation> vars;
+
+  int sz = details_.single_tie_region_size_;
+  if (specifications_[0].has_manual_position_)
+    sz = 1;
+  for (int i = 0; i < sz; i ++)
+    {
+      Direction d = LEFT;
+      do
+       {
+         if (i == 0
+             && ties[0].dir_ == d)
+           continue;
+         
+         int p = ties[0].position_ + i * d;
+         
+         if (!specifications_[0].has_manual_dir_
+             || d == specifications_[0].manual_dir_)
+           {
+             Tie_configuration_variation var;
+             var.index_ = 0;
+             var.suggestion_ = get_configuration (p,
+                                                  d, specifications_[0].column_ranks_,
+                                                  !specifications_[0].has_manual_delta_y_);
+             vars.push_back (var);
+           }
+       }
+      while (flip (&d) != LEFT);
+    }
+  return vars;
+}
+
 
 vector<Tie_configuration_variation>
 Tie_formatting_problem::generate_collision_variations (Ties_configuration const &ties) const
@@ -1025,7 +1063,8 @@ Tie_formatting_problem::generate_collision_variations (Ties_configuration const
                                                       - ties[i].dir_,
                                                       - ties[i].dir_,
 
-                                                      ties[i].column_ranks_
+                                                      ties[i].column_ranks_,
+                                                      !specifications_[i].has_manual_delta_y_
                                                       );
 
                  vars.push_back (var);
@@ -1038,7 +1077,9 @@ Tie_formatting_problem::generate_collision_variations (Ties_configuration const
                  var.suggestion_ = get_configuration (specifications_[i-1].position_
                                                       - ties[i-1].dir_,
                                                       - ties[i-1].dir_,
-                                                      specifications_[i-1].column_ranks_);
+                                                      specifications_[i-1].column_ranks_,
+                                                      !specifications_[i-1].has_manual_delta_y_
+                                                      );
 
                  vars.push_back (var);
                }
@@ -1049,7 +1090,10 @@ Tie_formatting_problem::generate_collision_variations (Ties_configuration const
                  Tie_configuration_variation var;
                  var.index_ = i-1;
                  var.suggestion_ = get_configuration (specifications_[i-1].position_ - 1, DOWN,
-                                                      specifications_[i-1].column_ranks_);
+                                                      specifications_[i-1].column_ranks_,
+                                                      !specifications_[i-1].has_manual_delta_y_
+
+                                                      );
                  vars.push_back (var);
                }
              if (i == ties.size() && !specifications_[i].has_manual_position_
@@ -1059,7 +1103,9 @@ Tie_formatting_problem::generate_collision_variations (Ties_configuration const
                  var.index_ = i;
                  var.suggestion_ = get_configuration (specifications_[i].position_
                                                       + 1, UP,
-                                                      specifications_[i].column_ranks_);
+                                                      specifications_[i].column_ranks_,
+                                                      !specifications_[i].has_manual_delta_y_
+                                                      );
                  vars.push_back (var);
                }
            }
@@ -1070,7 +1116,9 @@ Tie_formatting_problem::generate_collision_variations (Ties_configuration const
              var.index_ = i;
              var.suggestion_ = get_configuration (ties[i].position_  + ties[i].dir_,
                                                   ties[i].dir_,
-                                                  ties[i].column_ranks_);
+                                                  ties[i].column_ranks_,
+                                                  !specifications_[i].has_manual_delta_y_
+                                                  );
              vars.push_back (var);
            }
          
@@ -1099,7 +1147,9 @@ Tie_formatting_problem::set_manual_tie_configuration (SCM manual_configs)
            {
              spec.has_manual_position_ = true;
              spec.manual_position_ = scm_to_double (scm_car (entry));
+             spec.has_manual_delta_y_ = (scm_inexact_p (scm_car (entry)) == SCM_BOOL_T);
            }
+         
          if (scm_is_number (scm_cdr (entry)))
            {
              spec.has_manual_dir_ = true;
@@ -1110,3 +1160,20 @@ Tie_formatting_problem::set_manual_tie_configuration (SCM manual_configs)
     }
 }
 
+
+void
+Tie_formatting_problem::set_debug_scoring (Ties_configuration const &base)
+{
+#if DEBUG_TIE_SCORING
+  if (to_boolean (x_refpoint_->layout ()
+                 ->lookup_variable (ly_symbol2scm ("debug-tie-scoring"))))
+    {
+      for (vsize i = 0; i < base.size(); i++)
+       {
+         string card = base.complete_tie_card (i);
+         specifications_[i].tie_grob_->set_property ("quant-score",
+                                                     ly_string2scm (card));
+       }
+    }
+#endif
+}      
diff --git a/lily/tie-specification.cc b/lily/tie-specification.cc
new file mode 100644 (file)
index 0000000..3a7ce34
--- /dev/null
@@ -0,0 +1,47 @@
+#include "tie-formatting-problem.hh"
+#include "grob.hh"
+#include "tie.hh"
+#include "libc-extension.hh"
+#include "tie-specification.hh"
+
+Tie_specification::Tie_specification ()
+{
+  tie_grob_ = 0;
+  has_manual_position_ = false;
+  has_manual_dir_ = false;
+  has_manual_delta_y_ = false;
+  position_ = 0;
+  manual_position_ = 0;
+  manual_dir_ = CENTER;
+  note_head_drul_[LEFT] =
+    note_head_drul_[RIGHT] = 0;
+  column_ranks_[RIGHT] =
+    column_ranks_[LEFT] = 0;
+}
+
+
+void
+Tie_specification::from_grob (Grob *tie)
+{
+  tie_grob_ = tie;
+  if (scm_is_number (tie->get_property_data ("direction")))
+    {
+      manual_dir_ = to_dir (tie->get_property ("direction"));
+      has_manual_dir_ = true;
+    }
+  
+  position_ = Tie::get_position (tie);
+  SCM pos_scm = tie->get_property ("staff-position");
+  if (scm_is_number (pos_scm))
+    {
+      has_manual_delta_y_ = (scm_inexact_p (pos_scm) == SCM_BOOL_T);
+      manual_position_ = scm_to_double (tie->get_property ("staff-position"));
+      has_manual_position_ = true;
+    }
+}
+
+int
+Tie_specification::column_span () const
+{
+  return column_ranks_[RIGHT] - column_ranks_[LEFT];
+}
index 0c03c0fcb55d7acd7e507fdca89c772fec30c8b1..1d4e7fca9ac296659d01bfdfd2deaeae3e9f7df6 100644 (file)
@@ -148,7 +148,8 @@ Tie::calc_direction (SCM smob)
   if ((Tie_column::has_interface (yparent)
        || Semi_tie_column::has_interface (yparent)) 
       && unsmob_grob_array (yparent->get_object ("ties"))
-      && unsmob_grob_array (yparent->get_object ("ties"))->size () > 1)
+      //      && unsmob_grob_array (yparent->get_object ("ties"))->size () > 1
+      )
     {
       /* trigger positioning. */
       (void) yparent->get_property ("positioning-done");
@@ -170,18 +171,17 @@ Tie::get_default_control_points (Grob *me_grob)
   
   Tie_formatting_problem problem;
   problem.from_tie (me);
+  
   Tie_specification spec = problem.get_tie_specification (0);
-  spec.has_manual_dir_ = true;
-  spec.manual_dir_ = get_grob_direction (me);
-
   if (!me->is_live ())
     return SCM_EOL;
 
-  Tie_configuration conf
-    = problem.find_optimal_tie_configuration (spec);
+  
+  Ties_configuration conf
+    = problem.generate_optimal_configuration ();
   
   return get_control_points (me, problem.common_x_refpoint (),
-                            conf, problem.details_);
+                            conf[0], problem.details_);
 }
 
 SCM
@@ -211,14 +211,12 @@ Tie::calc_control_points (SCM smob)
 {
   Grob *me = unsmob_grob (smob);
 
-  // trigger Tie-column
-  (void)  get_grob_direction (me);
-
   Grob *yparent = me->get_parent (Y_AXIS);
   if ((Tie_column::has_interface (yparent)
        || Semi_tie_column::has_interface (yparent)) 
       && unsmob_grob_array (yparent->get_object ("ties"))
-      && unsmob_grob_array (yparent->get_object ("ties"))->size () > 1)
+      //      && unsmob_grob_array (yparent->get_object ("ties"))->size () > 1
+      )
     {
       /* trigger positioning. */
       (void) yparent->get_property ("positioning-done");
@@ -234,7 +232,7 @@ Tie::calc_control_points (SCM smob)
 }
 
 /*
-  TODO: merge witnh Slur::print.
+  TODO: merge with Slur::print.
  */
 MAKE_SCHEME_CALLBACK (Tie, print, 1);
 SCM
@@ -283,8 +281,15 @@ Tie::print (SCM smob)
       Stencil tm = *unsmob_stencil (Text_interface::interpret_markup
                                    (me->layout ()->self_scm (), properties,
                                     quant_score));
-      tm.translate_axis (b.control_[0][Y_AXIS]*2, Y_AXIS);
-      a.add_at_edge (X_AXIS, RIGHT, tm, 1.0, 0);
+      tm.translate (Offset (b.control_[3][X_AXIS] + 0.5,
+                           b.control_[0][Y_AXIS] * 2));
+      tm = tm.in_color (1, 0, 0);
+
+      /*
+       It would be nice if we could put this in a different layer,
+       but alas, this must be done with a Tie override.
+       */
+      a.add_stencil (tm);
     }
 #endif
 
index 8b06fb5927de30ff35ee2bbce0e11c73bfa55bc1..9acbe3beafcd652649b7db7648ef2ec662bcdee2 100644 (file)
                    (stem-gap . 0.35)
                    (height-limit . 1.0)
                    (horizontal-distance-penalty-factor . 10)
+                   (same-dir-as-stem-penalty . 8)
                    (min-length-penalty-factor . 20)
                    (tie-tie-collision-distance . 0.45) 
                    (tie-tie-collision-penalty . 25.0)
                    (intra-space-threshold . 1.25)
                    (outer-tie-vertical-distance-symmetry-penalty-factor . 10)
                    (outer-tie-length-symmetry-penalty-factor . 10)
+                   (vertical-distance-penalty-factor . 7)
                    (outer-tie-vertical-gap . 0.25)
                    (multi-tie-region-size . 1)
+                   (single-tie-region-size . 4)
                    (between-length-limit . 1.0)))
        
        (thickness . 1.2)