X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Ffingering-column.cc;h=c069fb7c74c61c8a033c7ec833151c75ffe748a4;hb=750b714488c5af6eae22d07163bba8b554734ac6;hp=d027dfa754acab6f586dda014b3c51513cda7f8a;hpb=f0fe9c843e926066299c1f9a33004649f42e1f24;p=lilypond.git diff --git a/lily/fingering-column.cc b/lily/fingering-column.cc index d027dfa754..c069fb7c74 100644 --- a/lily/fingering-column.cc +++ b/lily/fingering-column.cc @@ -17,6 +17,7 @@ along with LilyPond. If not, see . */ +#include "directional-element-interface.hh" #include "grob.hh" #include "fingering-column.hh" #include "pointer-group-interface.hh" @@ -24,90 +25,130 @@ #include "item.hh" #include "paper-column.hh" -#include +#define EPS 1e-5 + +struct Fingering_and_offset +{ + Grob *fingering_; + Real offset_; + Fingering_and_offset (Grob *fingering, Real offset); +}; + +Fingering_and_offset::Fingering_and_offset (Grob *fingering, Real offset) : + fingering_ (fingering), offset_ (offset) +{ +} + +bool +fingering_and_offset_less (Fingering_and_offset fo0, Fingering_and_offset fo1) +{ + return fo0.offset_ < fo1.offset_; +} 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); + Grob *me = unsmob (smob); if (!me->is_live ()) return SCM_BOOL_T; - map shifted; + me->set_property ("positioning-done", SCM_BOOL_T); - Real ss = Staff_symbol_referencer::staff_space (me); + do_y_positioning (me); + do_x_positioning (me); - me->set_property ("positioning-done", SCM_BOOL_T); + return SCM_BOOL_T; +} +void +Fingering_column::do_y_positioning (Grob *me) +{ 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; + return; } - // 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)}; + Real padding = robust_scm2double (me->get_property ("padding"), 0.2); + + // order the fingerings from bottom to top + vector_sort (fingerings, pure_position_less); + + vector shift(fingerings.size()); + + // Try stacking the fingerings top-to-bottom, and then bottom-to-top. + // Use the average of the resulting stacked locations as the final positions + for (UP_and_DOWN (d)) + { + Real stack_end = -d * infinity_f; + Interval prev_x_ext; + for (vsize i = (d == UP)? 0 : fingerings.size() - 1; + i < fingerings.size (); + i += d) + { + Interval x_ext = fingerings[i]->extent(common[X_AXIS], X_AXIS); + Interval y_ext = fingerings[i]->extent(fingerings[i], Y_AXIS); + Real parent_y = fingerings[i]->parent_relative (common[Y_AXIS], Y_AXIS); + + // Checking only between sequential neighbors, seems good enough + if (!intersection(x_ext, prev_x_ext).is_empty()) + stack_end += d * (y_ext.length() + padding); + // minmax() returns whichever is further along in direction d + stack_end = minmax(d, stack_end, parent_y); + + shift[i] += 0.5 * (stack_end - y_ext[d] - parent_y); + + prev_x_ext = x_ext; + } + } + 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; - } - } + fingerings[i]->translate_axis(shift[i], Y_AXIS); +} +void +Fingering_column::do_x_positioning (Grob *me) +{ + extract_grob_set (me, "fingerings", fingerings); + if (!fingerings.size ()) + return; - return SCM_BOOL_T; + Grob *common_x = common_refpoint_of_array (fingerings, me, X_AXIS); + + Real snap = robust_scm2double (me->get_property ("snap-radius"), 0.3); + vector fos; + + for (vsize i = 0; i < fingerings.size (); i++) + fos.push_back (Fingering_and_offset (fingerings[i], fingerings[i]->relative_coordinate (common_x, X_AXIS))); + + vector_sort (fos, fingering_and_offset_less); + Direction dir = get_grob_direction (fingerings[0]); + if (dir == RIGHT) + reverse (fos); + + Real prev = infinity_f * dir; + for (vsize i = 0; i < fos.size (); i++) + { + if ((fabs (fos[i].offset_ - prev) < snap) + && (fabs (fos[i].offset_ - prev) > EPS)) + fos[i].offset_ = prev; + + prev = fos[i].offset_; + } + + for (vsize i = 0; i < fos.size (); i++) + fos[i].fingering_->translate_axis (fos[i].offset_ - fos[i].fingering_->relative_coordinate (common_x, X_AXIS), X_AXIS); } void @@ -120,9 +161,11 @@ Fingering_column::add_fingering (Grob *fc, Grob *f) ADD_INTERFACE (Fingering_column, "Makes sure that fingerings placed laterally" - " do not collide.", + " do not collide and that they are flush if" + " necessary.", /* properties */ "padding " "positioning-done " + "snap-radius " );