From f1bb461ca8037b12343479b22d56bf96abe238b6 Mon Sep 17 00:00:00 2001 From: Mike Solomon Date: Fri, 21 Oct 2011 09:55:33 +0200 Subject: [PATCH] Fixes issue 1951 (script accidental collision). Scripts now use skylines to avoid accidentals and other grobs above or below which they are positioned. This leads to finer spacing and collision avoidance. --- .../regression/script-accidental-collision.ly | 21 +++ lily/box.cc | 10 ++ lily/grob.cc | 2 - lily/include/box.hh | 1 + lily/include/side-position-interface.hh | 2 + lily/script-engraver.cc | 21 ++- lily/side-position-interface.cc | 152 +++++++++++++++--- lily/slur.cc | 7 + scm/define-grob-properties.scm | 3 +- scm/define-grobs.scm | 2 + 10 files changed, 189 insertions(+), 32 deletions(-) create mode 100644 input/regression/script-accidental-collision.ly diff --git a/input/regression/script-accidental-collision.ly b/input/regression/script-accidental-collision.ly new file mode 100644 index 0000000000..39e204d037 --- /dev/null +++ b/input/regression/script-accidental-collision.ly @@ -0,0 +1,21 @@ +\version "2.15.15" + +\header { + texidoc = "Scripts use skylines with accurate boxes to avoid accidentals. +" +} + +{ + ees''1^\espressivo + e''!1^\espressivo + eis''1^\espressivo + ees''1^\fermata + e''!1^\fermata + eis''1^\fermata + ees'1_\espressivo + e'!1_\espressivo + eis'1_\espressivo + ees'1_\fermata + e'!1_\fermata + eis'1_\fermata +} diff --git a/lily/box.cc b/lily/box.cc index 648c7f7da2..6b12eba700 100644 --- a/lily/box.cc +++ b/lily/box.cc @@ -90,6 +90,16 @@ Box::widen (Real x, Real y) interval_a_[Y_AXIS].widen (y); } +// for debugging + +void +Box::print () +{ + printf ("X left %4.4f right %4.4f Y down %4.4f up %4.4f\n", + interval_a_[X_AXIS][LEFT], interval_a_[X_AXIS][RIGHT], + interval_a_[Y_AXIS][DOWN], interval_a_[Y_AXIS][UP]); +} + /****************************************************************/ #include "ly-smobs.icc" diff --git a/lily/grob.cc b/lily/grob.cc index fa8e1f6843..7f90971803 100644 --- a/lily/grob.cc +++ b/lily/grob.cc @@ -483,8 +483,6 @@ Grob::pure_height (Grob *refp, int start, int end) Interval Grob::maybe_pure_extent (Grob *refp, Axis a, bool pure, int start, int end) { - if (pure && a != Y_AXIS) - programming_error ("tried to get pure width"); return (pure && a == Y_AXIS) ? pure_height (refp, start, end) : extent (refp, a); } diff --git a/lily/include/box.hh b/lily/include/box.hh index f08dea2ca2..af5695b3bc 100644 --- a/lily/include/box.hh +++ b/lily/include/box.hh @@ -31,6 +31,7 @@ public: void widen (Real x, Real y); void scale (Real r); void unite (Box b); + void print (); Box (); Box (Interval ix, Interval iy); }; diff --git a/lily/include/side-position-interface.hh b/lily/include/side-position-interface.hh index b7d1427ee3..b8179eec7f 100644 --- a/lily/include/side-position-interface.hh +++ b/lily/include/side-position-interface.hh @@ -44,6 +44,8 @@ public: static SCM general_side_position (Grob *, Axis, bool, bool my_extents, bool pure, int start, int end, Real *current_off); + static SCM skyline_side_position (Grob *me, Axis a, bool pure, int start, int end, Real *current_offset); + static Axis get_axis (Grob *); static void set_axis (Grob *, Axis); DECLARE_GROB_INTERFACE (); diff --git a/lily/script-engraver.cc b/lily/script-engraver.cc index dee15b9cd1..1b9cf0b08a 100644 --- a/lily/script-engraver.cc +++ b/lily/script-engraver.cc @@ -59,6 +59,7 @@ protected: DECLARE_ACKNOWLEDGER (stem); DECLARE_ACKNOWLEDGER (stem_tremolo); DECLARE_ACKNOWLEDGER (note_column); + DECLARE_ACKNOWLEDGER (inline_accidental); public: TRANSLATOR_DECLARATIONS (Script_engraver); @@ -73,8 +74,7 @@ void Script_engraver::listen_articulation (Stream_event *ev) { /* Discard double articulations for part-combining. */ - int script_count = scripts_.size (); - for (int i = 0; i < script_count; i++) + for (vsize i = 0; i < scripts_.size (); i++) if (ly_is_equal (scripts_[i].event_ ->get_property ("articulation-type"), ev->get_property ("articulation-type"))) @@ -178,8 +178,7 @@ Script_engraver::process_music () void Script_engraver::acknowledge_stem (Grob_info info) { - int script_count = scripts_.size (); - for (int i = 0; i < script_count; i++) + for (vsize i = 0; i < scripts_.size (); i++) { Grob *e = scripts_[i].script_; @@ -193,8 +192,17 @@ Script_engraver::acknowledge_stem (Grob_info info) void Script_engraver::acknowledge_stem_tremolo (Grob_info info) { - int script_count = scripts_.size (); - for (int i = 0; i < script_count; i++) + for (vsize i = 0; i < scripts_.size (); i++) + { + Grob *e = scripts_[i].script_; + Side_position_interface::add_support (e, info.grob ()); + } +} + +void +Script_engraver::acknowledge_inline_accidental (Grob_info info) +{ + for (vsize i = 0; i < scripts_.size (); i++) { Grob *e = scripts_[i].script_; Side_position_interface::add_support (e, info.grob ()); @@ -249,6 +257,7 @@ ADD_ACKNOWLEDGER (Script_engraver, rhythmic_head); ADD_ACKNOWLEDGER (Script_engraver, stem); ADD_ACKNOWLEDGER (Script_engraver, note_column); ADD_ACKNOWLEDGER (Script_engraver, stem_tremolo); +ADD_ACKNOWLEDGER (Script_engraver, inline_accidental); ADD_TRANSLATOR (Script_engraver, /* doc */ diff --git a/lily/side-position-interface.cc b/lily/side-position-interface.cc index 5befccfccb..24422de6fd 100644 --- a/lily/side-position-interface.cc +++ b/lily/side-position-interface.cc @@ -24,6 +24,7 @@ using namespace std; +#include "accidental-interface.hh" #include "axis-group-interface.hh" #include "directional-element-interface.hh" #include "grob.hh" @@ -45,6 +46,38 @@ Side_position_interface::add_support (Grob *me, Grob *e) Pointer_group_interface::add_unordered_grob (me, ly_symbol2scm ("side-support-elements"), e); } +SCM +finish_offset (Grob *me, Direction dir, Real total_off, Real *current_offset) +{ + Real ss = Staff_symbol_referencer::staff_space (me); + Real minimum_space = ss * robust_scm2double (me->get_property ("minimum-space"), -1); + total_off += dir * ss * robust_scm2double (me->get_property ("padding"), 0); + + if (minimum_space >= 0 + && dir + && total_off * dir < minimum_space) + total_off = minimum_space * dir; + + + if (current_offset) + total_off = dir * max (dir * total_off, + dir * (*current_offset)); + + /* FIXME: 1000 should relate to paper size. */ + if (fabs (total_off) > 1000) + { + string msg + = String_convert::form_string ("Improbable offset for grob %s: %f", + me->name ().c_str (), total_off); + + programming_error (msg); + if (strict_infinity_checking) + scm_misc_error (__FUNCTION__, "Improbable offset.", SCM_EOL); + } + + return scm_from_double (total_off); +} + /* Put the element next to the support, optionally taking in account the extent of the support. @@ -56,8 +89,6 @@ Side_position_interface::general_side_position (Grob *me, Axis a, bool use_exten bool pure, int start, int end, Real *current_offset) { - Real ss = Staff_symbol_referencer::staff_space (me); - extract_grob_set (me, "side-support-elements", support); Grob *common = common_refpoint_of_array (support, me->get_parent (a), a); @@ -109,16 +140,8 @@ Side_position_interface::general_side_position (Grob *me, Axis a, bool use_exten dim = Interval (0, 0); Real off = me->get_parent (a)->maybe_pure_coordinate (common, a, pure, start, end); - Real minimum_space = ss * robust_scm2double (me->get_property ("minimum-space"), -1); Real total_off = dim.linear_combination (dir) - off; - total_off += dir * ss * robust_scm2double (me->get_property ("padding"), 0); - - if (minimum_space >= 0 - && dir - && total_off * dir < minimum_space) - total_off = minimum_space * dir; - if (include_my_extent) { Interval iv = me->maybe_pure_extent (me, a, pure, start, end); @@ -133,23 +156,102 @@ Side_position_interface::general_side_position (Grob *me, Axis a, bool use_exten } } - if (current_offset) - total_off = dir * max (dir * total_off, - dir * (*current_offset)); + return finish_offset (me, dir, total_off, current_offset); +} - /* FIXME: 1000 should relate to paper size. */ - if (fabs (total_off) > 1000) +SCM +Side_position_interface::skyline_side_position (Grob *me, Axis a, + bool pure, int start, int end, + Real *current_offset) +{ + extract_grob_set (me, "side-support-elements", support); + + Grob *common[2]; + for (Axis ax = X_AXIS; ax < NO_AXES; incr (ax)) + common[ax] = common_refpoint_of_array (support, ax == a ? me->get_parent (ax) : me, ax); + + Grob *staff_symbol = Staff_symbol_referencer::get_staff_symbol (me); + Direction dir = get_grob_direction (me); + + Box off; + Real my_min_h = dir == LEFT ? -infinity_f : infinity_f; + for (Axis ax = X_AXIS; ax < NO_AXES; incr (ax)) { - string msg - = String_convert::form_string ("Improbable offset for grob %s: %f", - me->name ().c_str (), total_off); + if (ax == a) + off[ax] = me->get_parent (ax)->maybe_pure_coordinate (common[ax], ax, pure, start, end) + + me->maybe_pure_extent (me, ax, pure, start, end); + else + off[ax] = me->maybe_pure_extent (common[ax], ax, pure, start, end); + } - programming_error (msg); - if (strict_infinity_checking) - scm_misc_error (__FUNCTION__, "Improbable offset.", SCM_EOL); + if (off[X_AXIS].is_empty () || off[Y_AXIS].is_empty ()) + return scm_from_double (0.0); + + my_min_h = off[a][dir]; + + Real skyline_padding = 0.1; + + Skyline my_dim (off, skyline_padding, other_axis (a), -dir); + my_dim.set_minimum_height (my_min_h); + + bool include_staff + = staff_symbol + && a == Y_AXIS + && scm_is_number (me->get_property ("staff-padding")) + && !to_boolean (me->get_property ("quantize-position")); + + vector boxes; + Real min_h = dir == LEFT ? infinity_f : -infinity_f; + for (vsize i = 0; i < support.size (); i++) + { + Grob *e = support[i]; + + // In the case of a stem, we will find a note head as well + // ignoring the stem solves cyclic dependencies if the stem is + // attached to a cross-staff beam. + if (a == Y_AXIS + && Stem::has_interface (e) + && dir == - get_grob_direction (e)) + continue; + + if (e) + { + if (Accidental_interface::has_interface (e)) + { + vector bs = Accidental_interface::accurate_boxes (e, common); + boxes.insert (boxes.end (), bs.begin (), bs.end ()); + } + else + { + Box b; + for (Axis ax = X_AXIS; ax < NO_AXES; incr (ax)) + b[ax] = e->maybe_pure_extent (common[ax], ax, pure, start, end); + + if (b[X_AXIS].is_empty () || b[Y_AXIS].is_empty ()) + continue; + + boxes.push_back (b); + min_h = minmax (dir, b[a][-dir], min_h); + } + } } - return scm_from_double (total_off); + Skyline dim (boxes, skyline_padding, other_axis (a), dir); + if (!boxes.size ()) + dim.set_minimum_height (0.0); + else + dim.set_minimum_height (min_h); + + if (include_staff) + { + Interval staff_extents; + common[Y_AXIS] = staff_symbol->common_refpoint (common[Y_AXIS], Y_AXIS); + staff_extents = staff_symbol->maybe_pure_extent (common[Y_AXIS], Y_AXIS, pure, start, end); + dim.set_minimum_height (minmax (dir, min_h, staff_extents[dir])); + } + + Real total_off = dir * dim.distance (my_dim); + return finish_offset (me, dir, total_off, current_offset); } MAKE_SCHEME_CALLBACK (Side_position_interface, y_aligned_on_support_refpoints, 1); @@ -228,8 +330,11 @@ Side_position_interface::aligned_side (Grob *me, Axis a, bool pure, int start, i Real *current_off) { Direction dir = get_grob_direction (me); + bool skyline = to_boolean (me->get_property ("use-skylines")); - Real o = scm_to_double (general_side_position (me, a, true, true, pure, start, end, current_off)); + Real o = scm_to_double (skyline + ? skyline_side_position (me, a, pure, start, end, current_off) + : general_side_position (me, a, true, true, pure, start, end, current_off)); /* Maintain a minimum distance to the staff. This is similar to side @@ -371,4 +476,5 @@ ADD_INTERFACE (Side_position_interface, "side-support-elements " "slur-padding " "staff-padding " + "use-skylines " ); diff --git a/lily/slur.cc b/lily/slur.cc index 1f41607307..bf0fb12361 100644 --- a/lily/slur.cc +++ b/lily/slur.cc @@ -272,6 +272,13 @@ Slur::outside_slur_callback (SCM grob, SCM offset_scm) Interval xext = robust_relative_extent (script, cx, X_AXIS); Interval slur_wid (curve.control_[0][X_AXIS], curve.control_[3][X_AXIS]); + /* + cannot use is_empty because some 0-extent scripts + come up with TabStaffs. + */ + if (xext.length () <= 0 || yext.length () <= 0) + return offset_scm; + bool contains = false; Direction d = LEFT; do diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm index 2c93c3a55c..acda4c25c3 100644 --- a/scm/define-grob-properties.scm +++ b/scm/define-grob-properties.scm @@ -916,7 +916,8 @@ polyphonic patterns.") spacing problem.") (usable-duration-logs ,list? "List of @code{duration-log}s that can be used in typesetting the grob.") - + (use-skylines ,boolean? "Should skylines be used for side +positioning?") ;; ;; v diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index acea431f19..f86fe11f54 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -80,6 +80,7 @@ (side-axis . ,Y) (staff-padding . 0.25) (stencil . ,ly:accidental-interface::print) + (use-skylines . #t) (X-extent . ,ly:accidental-interface::width) (X-offset . ,(ly:make-simple-closure `(,+ @@ -1726,6 +1727,7 @@ (staff-padding . 0.25) (stencil . ,ly:script-interface::print) + (use-skylines . #t) (X-offset . ,script-interface::calc-x-offset) (Y-offset . ,ly:side-position-interface::y-aligned-side) (meta . ((class . Item) -- 2.39.2