summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHan-Wen Nienhuys <hanwen@xs4all.nl>2007-01-12 22:01:09 +0100
committerHan-Wen Nienhuys <hanwen@xs4all.nl>2007-01-12 22:01:09 +0100
commite832bb9391d6053f7328250ff1035376cf4b9d4b (patch)
tree7993d3296627877db28a579c3b146a6b0a2749a2
parent3032ee2728314075c2cf98ef7f9f0d42008fb707 (diff)
Fix #138 & #139
- 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.
-rw-r--r--input/regression/semi-tie-manual-direction.ly16
-rw-r--r--input/regression/tie-accidental.ly19
-rw-r--r--input/regression/tie-manual-vertical-tune.ly23
-rw-r--r--input/regression/tie-single-chord.ly17
-rw-r--r--lily/include/misc.hh1
-rw-r--r--lily/include/tie-configuration.hh1
-rw-r--r--lily/include/tie-details.hh2
-rw-r--r--lily/include/tie-formatting-problem.hh33
-rw-r--r--lily/include/tie-specification.hh36
-rw-r--r--lily/laissez-vibrer-engraver.cc12
-rw-r--r--lily/misc.cc8
-rw-r--r--lily/repeat-tie-engraver.cc13
-rw-r--r--lily/semi-tie-column.cc6
-rw-r--r--lily/tie-column.cc29
-rw-r--r--lily/tie-configuration.cc28
-rw-r--r--lily/tie-details.cc2
-rw-r--r--lily/tie-formatting-problem.cc401
-rw-r--r--lily/tie-specification.cc47
-rw-r--r--lily/tie.cc33
-rw-r--r--scm/define-grobs.scm3
20 files changed, 489 insertions, 241 deletions
diff --git a/input/regression/semi-tie-manual-direction.ly b/input/regression/semi-tie-manual-direction.ly
new file mode 100644
index 0000000000..bfa44106df
--- /dev/null
+++ b/input/regression/semi-tie-manual-direction.ly
@@ -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
index 0000000000..2f1ec24218
--- /dev/null
+++ b/input/regression/tie-accidental.ly
@@ -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
index 0000000000..ed631d9a01
--- /dev/null
+++ b/input/regression/tie-manual-vertical-tune.ly
@@ -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
index 0000000000..c6160ab8d8
--- /dev/null
+++ b/input/regression/tie-single-chord.ly
@@ -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'>
+}
diff --git a/lily/include/misc.hh b/lily/include/misc.hh
index abef7b96c5..d0bb6f417b 100644
--- a/lily/include/misc.hh
+++ b/lily/include/misc.hh
@@ -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
diff --git a/lily/include/tie-configuration.hh b/lily/include/tie-configuration.hh
index 8801a7be7f..d65604c1dc 100644
--- a/lily/include/tie-configuration.hh
+++ b/lily/include/tie-configuration.hh
@@ -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;
};
diff --git a/lily/include/tie-details.hh b/lily/include/tie-details.hh
index e30f3ed866..18b9127d1e 100644
--- a/lily/include/tie-details.hh
+++ b/lily/include/tie-details.hh
@@ -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_;
diff --git a/lily/include/tie-formatting-problem.hh b/lily/include/tie-formatting-problem.hh
index c5a71b0314..863712e99e 100644
--- a/lily/include/tie-formatting-problem.hh
+++ b/lily/include/tie-formatting-problem.hh
@@ -14,30 +14,13 @@
#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
index 0000000000..912dc78689
--- /dev/null
+++ b/lily/include/tie-specification.hh
@@ -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 */
+
diff --git a/lily/laissez-vibrer-engraver.cc b/lily/laissez-vibrer-engraver.cc
index 7a9a4dee72..a6a4bd0e2b 100644
--- a/lily/laissez-vibrer-engraver.cc
+++ b/lily/laissez-vibrer-engraver.cc
@@ -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);
diff --git a/lily/misc.cc b/lily/misc.cc
index c64983d864..8d10141524 100644
--- a/lily/misc.cc
+++ b/lily/misc.cc
@@ -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)
diff --git a/lily/repeat-tie-engraver.cc b/lily/repeat-tie-engraver.cc
index bb23f73973..6b16fbc088 100644
--- a/lily/repeat-tie-engraver.cc
+++ b/lily/repeat-tie-engraver.cc
@@ -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);
diff --git a/lily/semi-tie-column.cc b/lily/semi-tie-column.cc
index 3713bfdaab..c7d44a9568 100644
--- a/lily/semi-tie-column.cc
+++ b/lily/semi-tie-column.cc
@@ -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;
}
diff --git a/lily/tie-column.cc b/lily/tie-column.cc
index 1f6738ef6d..9eefbbf8ee 100644
--- a/lily/tie-column.cc
+++ b/lily/tie-column.cc
@@ -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;
}
diff --git a/lily/tie-configuration.cc b/lily/tie-configuration.cc
index ea69fe5a78..2491f7e3ef 100644
--- a/lily/tie-configuration.cc
+++ b/lily/tie-configuration.cc
@@ -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;
}
diff --git a/lily/tie-details.cc b/lily/tie-details.cc
index c4ed37a2e4..ddb662fd30 100644
--- a/lily/tie-details.cc
+++ b/lily/tie-details.cc
@@ -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);
}
diff --git a/lily/tie-formatting-problem.cc b/lily/tie-formatting-problem.cc
index abcc342181..297fd4a155 100644
--- a/lily/tie-formatting-problem.cc
+++ b/lily/tie-formatting-problem.cc
@@ -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
index 0000000000..3a7ce345cb
--- /dev/null
+++ b/lily/tie-specification.cc
@@ -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];
+}
diff --git a/lily/tie.cc b/lily/tie.cc
index 0c03c0fcb5..1d4e7fca9a 100644
--- a/lily/tie.cc
+++ b/lily/tie.cc
@@ -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
diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm
index 8b06fb5927..9acbe3beaf 100644
--- a/scm/define-grobs.scm
+++ b/scm/define-grobs.scm
@@ -1822,14 +1822,17 @@
(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)