From 66a7c3e925cbc1a34eaad04f80d4bc42ad9834ac Mon Sep 17 00:00:00 2001 From: Mike Solomon Date: Wed, 29 Aug 2012 10:22:31 +0200 Subject: [PATCH] Uses FingeringColumn to avoid collisions of overlapping Fingerings. --- input/regression/fingering-column.ly | 16 ++++ lily/fingering-column-engraver.cc | 118 ++++++++++++++++++++++++ lily/fingering-column.cc | 128 +++++++++++++++++++++++++++ lily/include/fingering-column.hh | 34 +++++++ ly/engraver-init.ly | 1 + scm/define-grobs.scm | 7 ++ 6 files changed, 304 insertions(+) create mode 100644 input/regression/fingering-column.ly create mode 100644 lily/fingering-column-engraver.cc create mode 100644 lily/fingering-column.cc create mode 100644 lily/include/fingering-column.hh diff --git a/input/regression/fingering-column.ly b/input/regression/fingering-column.ly new file mode 100644 index 0000000000..be6fe7d4b6 --- /dev/null +++ b/input/regression/fingering-column.ly @@ -0,0 +1,16 @@ +\version "2.17.1" + +\header { + texidoc = "Horizontal @code{Fingering} grobs that collide do not intersect. +Non-intersecting @code{Fingering} grobs are left alone. +" +} + +\relative c'' { + \set fingeringOrientations = #'(left) + \override Fingering #'staff-padding = #'() + \override Fingering #'add-stem-support = ##f + 4 + + +} diff --git a/lily/fingering-column-engraver.cc b/lily/fingering-column-engraver.cc new file mode 100644 index 0000000000..9cca711391 --- /dev/null +++ b/lily/fingering-column-engraver.cc @@ -0,0 +1,118 @@ +/* + This file is part of LilyPond, the GNU music typesetter. + + Copyright (C) 1999--2012 Han-Wen Nienhuys + + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . +*/ + +#include "engraver.hh" +#include "side-position-interface.hh" +#include "pointer-group-interface.hh" +#include "fingering-column.hh" +#include "item.hh" + +#include "translator.icc" + +/** + Find potentially colliding scripts, and put them in a + Fingering_column, that will fix the collisions. */ +class Fingering_column_engraver : public Engraver +{ + Drul_array fingering_columns_; + Drul_array > scripts_; + vector possibles_; + +public: + TRANSLATOR_DECLARATIONS (Fingering_column_engraver); +protected: + DECLARE_ACKNOWLEDGER (finger); + void process_acknowledged (); + void stop_translation_timestep (); +}; + +Fingering_column_engraver::Fingering_column_engraver () +{ + for (LEFT_and_RIGHT (d)) + fingering_columns_[d] = 0; +} + +void +Fingering_column_engraver::stop_translation_timestep () +{ + for (vsize i = 0; i < possibles_.size (); i++) + if (!Item::is_non_musical (possibles_[i])) + { + if (Side_position_interface::get_axis (possibles_[i]) == X_AXIS) + { + Direction d = robust_scm2dir (possibles_[i]->get_property ("direction"), CENTER); + if (d) + scripts_[d].push_back (possibles_[i]); + else + possibles_[i]->warning ("Cannot add a fingering without a direction."); + } + } + + for (LEFT_and_RIGHT (d)) + { + if (scripts_[d].size () < 2 && fingering_columns_[d]) + { + fingering_columns_[d]->suicide (); + fingering_columns_[d] = 0; + } + if (fingering_columns_[d]) + { + for (vsize i = 0; i < scripts_[d].size (); i++) + Fingering_column::add_fingering (fingering_columns_[d], scripts_[d][i]); + + } + scripts_[d].clear (); + fingering_columns_[d] = 0; + } + possibles_.clear (); +} + +void +Fingering_column_engraver::acknowledge_finger (Grob_info inf) +{ + Item *thing = dynamic_cast (inf.grob ()); + if (thing) + possibles_.push_back (thing); +} + +void +Fingering_column_engraver::process_acknowledged () +{ + for (LEFT_and_RIGHT (d)) + { + if (possibles_.size () > 1 && !fingering_columns_[d]) + fingering_columns_[d] = make_item ("FingeringColumn", SCM_EOL); + } +} + +ADD_ACKNOWLEDGER (Fingering_column_engraver, finger); +ADD_TRANSLATOR (Fingering_column_engraver, + /* doc */ + "Find potentially colliding scripts and put them into a" + " @code{FingeringColumn} object; that will fix the collisions.", + + /* create */ + "FingeringColumn ", + + /* read */ + "", + + /* write */ + "" + ); diff --git a/lily/fingering-column.cc b/lily/fingering-column.cc new file mode 100644 index 0000000000..b4e13715a6 --- /dev/null +++ b/lily/fingering-column.cc @@ -0,0 +1,128 @@ +/* + This file is part of LilyPond, the GNU music typesetter. + + Copyright (C) 2002--2012 Han-Wen Nienhuys + + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . +*/ + +#include "grob.hh" +#include "fingering-column.hh" +#include "pointer-group-interface.hh" +#include "staff-symbol-referencer.hh" +#include "item.hh" +#include "paper-column.hh" + +#include + +MAKE_SCHEME_CALLBACK (Fingering_column, calc_positioning_done, 1); +SCM +Fingering_column::calc_positioning_done (SCM smob) +{ + Grob *me = unsmob_grob (smob); + Real padding = robust_scm2double (me->get_property ("padding"), 0.0); + if (!me->is_live ()) + return SCM_BOOL_T; + + map shifted; + + Real ss = Staff_symbol_referencer::staff_space (me); + + me->set_property ("positioning-done", SCM_BOOL_T); + + extract_grob_set (me, "fingerings", const_fingerings); + + if (const_fingerings.size () < 2) + { + me->programming_error ("This FingeringColumn should have never been created."); + return SCM_BOOL_T; + } + + // order the fingerings from bottom to top + vector fingerings; + for (vsize i = 0; i < const_fingerings.size (); i++) + fingerings.push_back (const_fingerings[i]); + + vector_sort (fingerings, pure_position_less); + + Grob *common[2] = {common_refpoint_of_array (fingerings, me, X_AXIS), + common_refpoint_of_array (fingerings, me, Y_AXIS)}; + + for (vsize i = 0; i < fingerings.size (); i++) + fingerings[i]->translate_axis (-fingerings[i]->extent (common[Y_AXIS], Y_AXIS).length () / 2, Y_AXIS); + + for (vsize i = min (fingerings.size () - 1, fingerings.size () / 2 + 1); i >= 1; i--) + for (vsize j = i; j--;) + { + Interval ex_i = fingerings[i]->extent (common[X_AXIS], X_AXIS); + Interval ex_j = fingerings[j]->extent (common[X_AXIS], X_AXIS); + Interval ey_i = fingerings[i]->extent (common[Y_AXIS], Y_AXIS); + Interval ey_j = fingerings[j]->extent (common[Y_AXIS], Y_AXIS); + Real tval = min (0.0, (ey_i[DOWN] - ey_j[UP] - padding) / 2); + if (tval != 0.0 && !intersection (ex_i, ex_j).is_empty ()) + { + if (shifted[fingerings[i]] || shifted[fingerings[j]]) + fingerings[j]->translate_axis (tval * 2, Y_AXIS); + else + { + fingerings[i]->translate_axis (-tval, Y_AXIS); + fingerings[j]->translate_axis (tval, Y_AXIS); + } + shifted[fingerings[i]] = true; + shifted[fingerings[j]] = true; + } + } + + for (vsize i = fingerings.size () / 2 - 1; i < fingerings.size () - 1; i++) + for (vsize j = i + 1; j < fingerings.size (); j++) + { + Interval ex_i = fingerings[i]->extent (common[X_AXIS], X_AXIS); + Interval ex_j = fingerings[j]->extent (common[X_AXIS], X_AXIS); + Interval ey_i = fingerings[i]->extent (common[Y_AXIS], Y_AXIS); + Interval ey_j = fingerings[j]->extent (common[Y_AXIS], Y_AXIS); + Real tval = max (0.0, (ey_i[UP] - ey_j[DOWN] + padding) / 2); + if (tval != 0.0 && !intersection (ex_i, ex_j).is_empty ()) + { + if (shifted[fingerings[i]] || shifted[fingerings[j]]) + fingerings[j]->translate_axis (tval * 2, Y_AXIS); + else + { + fingerings[i]->translate_axis (-tval, Y_AXIS); + fingerings[j]->translate_axis (tval, Y_AXIS); + } + shifted[fingerings[i]] = true; + shifted[fingerings[j]] = true; + } + } + + + return SCM_BOOL_T; +} + +void +Fingering_column::add_fingering (Grob *fc, Grob *f) +{ + Pointer_group_interface::add_grob (fc, ly_symbol2scm ("fingerings"), f); + f->set_parent (fc, X_AXIS); + f->set_property ("Y-offset", Grob::x_parent_positioning_proc); +} + +ADD_INTERFACE (Fingering_column, + "Makes sure that fingerings placed laterally" + " do not collide.", + + /* properties */ + "padding " + "positioning-done " + ); diff --git a/lily/include/fingering-column.hh b/lily/include/fingering-column.hh new file mode 100644 index 0000000000..6d6bef2376 --- /dev/null +++ b/lily/include/fingering-column.hh @@ -0,0 +1,34 @@ +/* + This file is part of LilyPond, the GNU music typesetter. + + Copyright (C) 1999--2012 Han-Wen Nienhuys + + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . +*/ + +#ifndef FINGERING_COLUMN_HH +#define FINGERING_COLUMN_HH + +#include "lily-proto.hh" +#include "grob-interface.hh" +#include "std-vector.hh" + +struct Fingering_column +{ + static void add_fingering (Grob *, Grob *); + DECLARE_SCHEME_CALLBACK (calc_positioning_done, (SCM)); + DECLARE_GROB_INTERFACE (); +}; + +#endif /* FINGERING_COLUMN_HH */ diff --git a/ly/engraver-init.ly b/ly/engraver-init.ly index 4d2329032d..47af14b023 100644 --- a/ly/engraver-init.ly +++ b/ly/engraver-init.ly @@ -260,6 +260,7 @@ multiple voices on the same staff." \consists "Script_engraver" \consists "Script_column_engraver" + \consists "Fingering_column_engraver" \consists "Rhythmic_column_engraver" \consists "Note_spacing_engraver" \consists "Spanner_break_forbid_engraver" diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index 9331744168..40218b3d2d 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -902,6 +902,13 @@ text-interface text-script-interface)))))) + (FingeringColumn + . ( + (padding . 0.2) + (positioning-done . ,ly:fingering-column::calc-positioning-done) + (meta . ((class . Item) + (interfaces . (fingering-column-interface)))))) + (Flag . ( (glyph-name . ,ly:flag::glyph-name) -- 2.39.2