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