From b9955d706ca6f136b160f0611db85c6bdf0fea9b Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Sat, 21 Jun 2003 00:14:30 +0000 Subject: [PATCH] * lily/align-interface.cc (find_fixed_alignment_parent): new function. * lily/line-spanner.cc (broken_trend_offset): remove function. (get_broken_offset): idem. (brew_molecule): rewrite the line-break case. * input/regression/follow-voice-break.ly: new file. * lily/line-spanner.cc (after_line_breaking): remove lines at the start of a system. --- ChangeLog | 14 +- input/regression/follow-voice-break.ly | 23 +++ input/test/follow-thread.ly | 6 +- lily/align-interface.cc | 22 +++ lily/context-specced-music-iterator.cc | 9 +- lily/include/align-interface.hh | 3 + lily/include/line-spanner.hh | 2 +- lily/line-spanner.cc | 217 +++++++++++++++---------- scm/define-grobs.scm | 2 + 9 files changed, 200 insertions(+), 98 deletions(-) create mode 100644 input/regression/follow-voice-break.ly diff --git a/ChangeLog b/ChangeLog index 6a81127d54..18589239dc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2003-06-21 Han-Wen Nienhuys + + * lily/align-interface.cc (find_fixed_alignment_parent): new function. + + * lily/line-spanner.cc (broken_trend_offset): remove function. + (get_broken_offset): idem. + (brew_molecule): rewrite the line-break case. + + * input/regression/follow-voice-break.ly: new file. + + * lily/line-spanner.cc (after_line_breaking): remove lines at the + start of a system. + 2003-06-20 Graham Percival * input/test/tuplet-rest.ly: moved to regression. @@ -15,7 +28,6 @@ * ly/engraver-init.ly (ScoreContext): put key-signature after staff-bar - 2003-06-20 Graham Percival * input/test/ broken.ly lyric-phrasing.ly: deleted. diff --git a/input/regression/follow-voice-break.ly b/input/regression/follow-voice-break.ly new file mode 100644 index 0000000000..9ec1c91bcc --- /dev/null +++ b/input/regression/follow-voice-break.ly @@ -0,0 +1,23 @@ +\version "1.7.18" +\header{ + texidoc = " +When put across line breaks, only the part before the line break is +printed. The line-spanners connects to the Y position of the note on the next line. +" + +} + +\score{ + \context PianoStaff < + \property PianoStaff.followVoice = ##t + \context Staff=one \notes\relative c''{ + a1 \break + \translator Staff=two + a, + } + \context Staff=two { \clef bass \skip 1*2 } + > + \paper{ + raggedright = ##t + } +} diff --git a/input/test/follow-thread.ly b/input/test/follow-thread.ly index 80d89fe95c..b1a0e1fe43 100644 --- a/input/test/follow-thread.ly +++ b/input/test/follow-thread.ly @@ -18,11 +18,9 @@ property @code{followVoice}. " } b2 a % these lines from follow-break.ly: \translator Staff=one - a1 \break - \translator Staff=two - a, + a1 } - \context Staff=two {\clef bass \skip 1*4} + \context Staff=two {\clef bass \skip 1*3 } > } diff --git a/lily/align-interface.cc b/lily/align-interface.cc index 6a39e6b08d..d9cef2771c 100644 --- a/lily/align-interface.cc +++ b/lily/align-interface.cc @@ -262,6 +262,27 @@ Align_interface::set_axis (Grob*me,Axis a) } +/* + Find Y-axis parent of G that has a #'forced-distance property. This + has the effect of finding the piano-staff given an object in that + piano staff. + */ +Grob * +find_fixed_alignment_parent (Grob *g) +{ + while (g) + { + if (gh_number_p (g->get_grob_property ("forced-distance"))) + return g; + + g = g->get_parent (Y_AXIS); + } + + return 0; +} + + + ADD_INTERFACE (Align_interface, "align-interface", " Order grobs top to bottom/left to right/right to left etc.", @@ -272,3 +293,4 @@ struct Foobar { bool has_interface (Grob*); }; + diff --git a/lily/context-specced-music-iterator.cc b/lily/context-specced-music-iterator.cc index dc3c929781..f1e64ba558 100644 --- a/lily/context-specced-music-iterator.cc +++ b/lily/context-specced-music-iterator.cc @@ -1,11 +1,12 @@ /* -context-specced-music-iterator.cc -- implement + context-specced-music-iterator.cc -- implement + Context_specced_music_iterator -source file of the GNU LilyPond music typesetter + source file of the GNU LilyPond music typesetter -(c) 2002--2003 Han-Wen Nienhuys + (c) 2002--2003 Han-Wen Nienhuys - */ +*/ #include "music-wrapper-iterator.hh" #include "translator-group.hh" diff --git a/lily/include/align-interface.hh b/lily/include/align-interface.hh index 3e50030e41..cdc15a5e8a 100644 --- a/lily/include/align-interface.hh +++ b/lily/include/align-interface.hh @@ -27,5 +27,8 @@ struct Align_interface { static bool has_interface (Grob*); }; +Grob *find_fixed_alignment_parent (Grob *g); + + #endif /* ALIGN_INTERFACE_HH */ diff --git a/lily/include/line-spanner.hh b/lily/include/line-spanner.hh index dbc6bcf4d5..a784b02bb2 100644 --- a/lily/include/line-spanner.hh +++ b/lily/include/line-spanner.hh @@ -16,7 +16,7 @@ class Line_spanner { public: DECLARE_SCHEME_CALLBACK (brew_molecule, (SCM)); - + DECLARE_SCHEME_CALLBACK(after_line_breaking, (SCM)); static Molecule line_molecule (Grob* me, Real thick, Real dx, Real dy); static bool has_interface (Grob*); diff --git a/lily/line-spanner.cc b/lily/line-spanner.cc index 7ed5314f28..7e1ed4b5a2 100644 --- a/lily/line-spanner.cc +++ b/lily/line-spanner.cc @@ -15,6 +15,7 @@ #include "staff-symbol-referencer.hh" #include "font-interface.hh" #include "warn.hh" +#include "align-interface.hh" #include @@ -84,6 +85,39 @@ zigzag_atom (Grob* me, Real thick, Real dx, Real dy) return list; } +MAKE_SCHEME_CALLBACK(Line_spanner, after_line_breaking, 1); +SCM +Line_spanner::after_line_breaking (SCM g) +{ + Grob *me = unsmob_grob (g); + Spanner*sp = dynamic_cast (me); + + /* + We remove the line at the start of the line. For piano voice + indicators, it makes no sense to have them at the start of the + line. + + I'm not sure what the official rules for glissandi are, but + usually the 2nd note of the glissando is "exact", so when playing + from the start of the line, there is no need to glide. + + From a typographical p.o.v. this makes sense, since the amount of + space left of a note at the start of a line is very small. + + --hwn. + + */ + if (sp->get_bound (LEFT)->break_status_dir() + && !sp->get_bound (RIGHT)->break_status_dir()) + { + /* + Can't do suicide, since this mucks up finding the trend. + */ + me->set_grob_property ("molecule-callback", SCM_EOL); + + } + return SCM_EOL; +} Molecule @@ -139,52 +173,26 @@ Line_spanner::line_molecule (Grob* me, Real thick, Real dx, Real dy) return mol; } -Offset -Line_spanner::get_broken_offset (Grob *me, Direction dir) +/* + Find a common Y parent, which --if found-- should be the + fixed-distance alignment. + */ +Grob * +line_spanner_common_parent (Grob *me) { - Spanner *spanner = dynamic_cast (me); - Item* bound = spanner->get_bound (dir); - - if (!bound->break_status_dir ()) + Grob * common = find_fixed_alignment_parent (me); + if (!common) { - Grob *common[] = { - bound->common_refpoint (Staff_symbol_referencer::get_staff_symbol (me), - X_AXIS), - bound->common_refpoint (Staff_symbol_referencer::get_staff_symbol (me), - Y_AXIS) - }; - - return Offset (abs (bound->extent (common[X_AXIS], X_AXIS)[-dir]), - bound->extent (common[Y_AXIS], Y_AXIS).center ()); + common = Staff_symbol_referencer::get_staff_symbol (me); + if (common) + common = common->get_parent (Y_AXIS); + else + common = me->get_parent (Y_AXIS); } - return Offset (); -} -/* A broken line-spaner should maintain the same vertical trend - the unbroken line-spanner would have had. - From slur */ -Offset -Line_spanner::broken_trend_offset (Grob *me, Direction dir) -{ - Offset o; - - if (Spanner *mother = dynamic_cast (me->original_)) - { - int k = broken_spanner_index (dynamic_cast (me)); - Grob *neighbour = mother->broken_intos_[k + dir]; - Offset neighbour_o = get_broken_offset (neighbour, dir); - Offset me_o = get_broken_offset (me, -dir); - - // Hmm, why not return me_o[X], but recalc in brew_mol? - o = Offset (0, - (neighbour_o[Y_AXIS]*me_o[X_AXIS] - - me_o[Y_AXIS]*neighbour_o[X_AXIS]) * dir / - (me_o[X_AXIS] + neighbour_o[X_AXIS])); - } - return o; + return common; } - /* Warning: this thing is a cross-staff object, so it should have empty Y-dimensions. @@ -194,28 +202,16 @@ Line_spanner::broken_trend_offset (Grob *me, Direction dir) */ + MAKE_SCHEME_CALLBACK (Line_spanner, brew_molecule, 1); SCM Line_spanner::brew_molecule (SCM smob) { - Grob *me= unsmob_grob (smob); + Spanner *me = dynamic_cast (unsmob_grob (smob)); - Spanner *spanner = dynamic_cast (me); - Drul_array bound (spanner->get_bound (LEFT), - spanner->get_bound (RIGHT)); + Drul_array bound (me->get_bound (LEFT), + me->get_bound (RIGHT)); - Grob *common[] = { me, me }; - for (int a = X_AXIS; a < NO_AXES; a++) - { - common[a] = me->common_refpoint (bound[RIGHT], Axis (a)); - common[a] = common[a]->common_refpoint (bound[LEFT], Axis (a)); - - if (!common[a]) - { - programming_error ("No common point!"); - return SCM_EOL; - } - } Real gap = gh_scm2double (me->get_grob_property ("gap")); @@ -223,35 +219,88 @@ Line_spanner::brew_molecule (SCM smob) Offset dxy ; Offset my_off; Offset his_off; + + Real thick = me->get_paper ()->get_var ("linethickness"); + SCM s = me->get_grob_property ("thickness"); + if (gh_number_p (s)) + thick *= gh_scm2double (s); - - if (bound[LEFT]->break_status_dir () || bound[RIGHT]->break_status_dir ()) - /* across line break */ + if (bound[RIGHT]->break_status_dir()) { - Direction broken = bound[LEFT]->break_status_dir () ? LEFT : RIGHT; - - dxy[X_AXIS] = bound[RIGHT]->extent (common[X_AXIS], X_AXIS)[LEFT] - - bound[LEFT]->extent (common[X_AXIS], X_AXIS)[RIGHT]; - - dxy += broken_trend_offset (me, broken); - dxy[X_AXIS] -= 1 * gap; + if (bound[LEFT]->break_status_dir ()) + { + programming_error ("line-spanner with two broken ends. Farewell sweet world."); - my_off = Offset (0, - me->relative_coordinate (common[Y_AXIS], Y_AXIS)); + me->suicide(); + return SCM_EOL; + } - his_off = Offset (0, - bound[-broken]->relative_coordinate (common[Y_AXIS], - Y_AXIS)); + /* + This is hairy. For the normal case, we simply find common + parents, and draw a line between the bounds. When two note + heads are on different lines, there is no common parent + anymore. We have to find the piano-staff object. + */ + + int k = broken_spanner_index (me); + Spanner * parent_sp = dynamic_cast (me->original_); + Spanner * next_sp = parent_sp->broken_intos_ [k+1]; + Item * next_bound = next_sp->get_bound (RIGHT); - if (broken == LEFT) + if (next_bound->break_status_dir()) { - my_off[Y_AXIS] += dxy[Y_AXIS]; + programming_error ("no note heads for the line spanner on next line?" + " Confused."); + me->suicide(); + return SCM_EOL; } + + Grob *commonx = bound[LEFT]->common_refpoint (bound[RIGHT], X_AXIS); + commonx = me->common_refpoint (commonx, X_AXIS); + + Grob * next_common_y = line_spanner_common_parent (next_bound); + Grob * this_common_y = line_spanner_common_parent (bound[LEFT]); + + Grob * all_common_y = me->common_refpoint (this_common_y, Y_AXIS); + + Interval next_ext = next_bound->extent (next_common_y, Y_AXIS); + Interval this_ext = bound[LEFT]->extent (this_common_y, Y_AXIS); + + Real yoff = this_common_y->relative_coordinate (all_common_y, Y_AXIS); + + Offset p1 (bound[LEFT]->extent (commonx, X_AXIS)[RIGHT], + this_ext.center () + yoff); + Offset p2 (bound[RIGHT]->extent (commonx, X_AXIS)[LEFT], + next_ext.center () + yoff); + + Offset dz (p2 -p1); + Real len = dz.length (); + + Offset dir = dz *(1/ len); + dz = (dz.length () - 2*gap) *dir; + + + Molecule l (line_molecule (me, thick, dz[X_AXIS], + dz[Y_AXIS])); + + l.translate (dir * gap + p1 + - Offset (me->relative_coordinate (commonx, X_AXIS), + me->relative_coordinate (all_common_y, Y_AXIS))); + + return l.smobbed_copy (); } else { - Real off = gap + ((bound[LEFT]->extent (bound[LEFT], X_AXIS).length ()*3)/4); // distance from center to start of line + Grob *common[] = { me, me }; + for (int a = X_AXIS; a < NO_AXES; a++) + { + common[a] = me->common_refpoint (bound[RIGHT], Axis (a)); + common[a] = common[a]->common_refpoint (bound[LEFT], Axis (a)); + } + + // distance from center to start of line + Real off = gap + ((bound[LEFT]->extent (bound[LEFT], X_AXIS).length ()*3)/4); for (int a = X_AXIS; a < NO_AXES; a++) { @@ -267,24 +316,16 @@ Line_spanner::brew_molecule (SCM smob) ofxy = dxy * (off/dxy.length ()); dxy -= 2*ofxy; - } - - Real thick = me->get_paper ()->get_var ("linethickness"); - - SCM s = me->get_grob_property ("thickness"); - if (gh_number_p (s)) - thick *= gh_scm2double (s); - - Molecule line = line_molecule (me, thick, dxy[X_AXIS], dxy[Y_AXIS]); - line.translate_axis (bound[LEFT]->extent (bound[LEFT], - X_AXIS).length ()/2, X_AXIS); - line.translate (ofxy - my_off + his_off); - return line.smobbed_copy (); + Molecule line = line_molecule (me, thick, dxy[X_AXIS], dxy[Y_AXIS]); + line.translate_axis (bound[LEFT]->extent (bound[LEFT], + X_AXIS).length ()/2, X_AXIS); + line.translate (ofxy - my_off + his_off); + return line.smobbed_copy (); + } } - ADD_INTERFACE (Line_spanner, "line-spanner-interface", "Generic line drawn between two objects, eg. for use with glissandi.\n" "gap is measured in staff-spaces.\n" diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index 702f5c424d..8eb4022f1a 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -617,6 +617,7 @@ (breakable . #t) (X-extent-callback . #f) (Y-extent-callback . #f) + (after-line-breaking-callback . ,Line_spanner::after_line_breaking) (molecule-callback . ,Line_spanner::brew_molecule) (meta . ((interfaces . (line-spanner-interface spanner-interface)))) )) @@ -629,6 +630,7 @@ (X-extent-callback . #f) (Y-extent-callback . #f) (molecule-callback . ,Line_spanner::brew_molecule) + (after-line-breaking-callback . ,Line_spanner::after_line_breaking) (meta . ((interfaces . (line-spanner-interface spanner-interface)))) )) -- 2.39.2