From c89de2a770104af7b014bd4674e871957951e8fb Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Sun, 19 May 2002 10:37:05 +0000 Subject: [PATCH] collision note head merge --- ChangeLog | 7 + Documentation/regression-test.tely | 2 + Documentation/user/refman.itely | 2 +- input/regression/collision-heads.ly | 29 ++++ lily/accidental-placement.cc | 4 +- lily/collision-engraver.cc | 4 +- .../{collision.hh => note-collision.hh} | 6 +- lily/include/note-head.hh | 2 +- lily/include/rhythmic-head.hh | 2 +- lily/mensural-ligature-engraver.cc | 2 +- lily/{collision.cc => note-collision.cc} | 142 ++++++++++++------ lily/note-head.cc | 13 +- lily/rest-collision-engraver.cc | 2 +- lily/rhythmic-head.cc | 14 +- lily/stem.cc | 4 +- scm/grob-property-description.scm | 13 +- scripts/lilypond-book.py | 1 + 17 files changed, 178 insertions(+), 71 deletions(-) create mode 100644 input/regression/collision-heads.ly rename lily/include/{collision.hh => note-collision.hh} (80%) rename lily/{collision.cc => note-collision.cc} (75%) diff --git a/ChangeLog b/ChangeLog index 4c62d7d994..887100f5b1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2002-05-19 Han-Wen + + * lily/note-collision.cc (check_meshing_chords): move file from + collision.cc, implement merged note heads (there you go, Drarn :-) + + * input/regression/collision-heads.ly: new file + 2002-05-18 Juergen Reuter * mf/parmesan-heads.mf, scm/grob-description.scm, diff --git a/Documentation/regression-test.tely b/Documentation/regression-test.tely index a546114a64..775d1df6a5 100644 --- a/Documentation/regression-test.tely +++ b/Documentation/regression-test.tely @@ -248,6 +248,8 @@ Grace note do weird things with timing. Fragile. @lilypondfile[printfilename]{collision-dots.ly} +@lilypondfile[printfilename]{collision-heads.ly} + @lilypondfile[printfilename]{collision-mesh.ly} @lilypondfile[printfilename]{number-staff-lines.ly} diff --git a/Documentation/user/refman.itely b/Documentation/user/refman.itely index ea6a73ff37..b0baf887d7 100644 --- a/Documentation/user/refman.itely +++ b/Documentation/user/refman.itely @@ -1458,7 +1458,7 @@ Unbeamed eighth notes and shorter by default have a slash through the stem. @lilypond[fragment,verbatim] -\relative c'' { +\relative c'' \context Voice { \grace c8 c4 \grace { [c16 c16] } c4 \grace { \property Voice.Stem \override #'flag-style = #'() diff --git a/input/regression/collision-heads.ly b/input/regression/collision-heads.ly new file mode 100644 index 0000000000..04ef2f7326 --- /dev/null +++ b/input/regression/collision-heads.ly @@ -0,0 +1,29 @@ +\header { + texidoc = + + "If @code{merge-differently-headed}, then +open note heads may be merged with black noteheads, but only +if the black note heads are from 8th or shorter notes. +" + +} +\score { \notes \context Staff\relative c''< +\context Voice = VA { + \voiceOne + c2 c8 c4. + + \property Staff.NoteCollision \override #'merge-differently-headed = ##t + c2 + c4. c8 + c2 +} +\context Voice = VB { + \voiceTwo + c8 c4. + c2 + c8 c4. + c2 + c4 +} + > + } diff --git a/lily/accidental-placement.cc b/lily/accidental-placement.cc index f4576cb022..edefc20fb2 100644 --- a/lily/accidental-placement.cc +++ b/lily/accidental-placement.cc @@ -17,7 +17,7 @@ source file of the GNU LilyPond music typesetter #include "accidental-placement.hh" #include "note-column.hh" #include "group-interface.hh" -#include "collision.hh" +#include "note-collision.hh" MAKE_SCHEME_CALLBACK(Accidental_placement,extent_callback, 2); SCM @@ -206,7 +206,7 @@ Accidental_placement::position_accidentals (Grob * me) for (int i = note_cols.size() ; i--;) { Grob *c = note_cols[i]->get_parent (X_AXIS); - if (Collision::has_interface (c)) + if (Note_collision_interface::has_interface (c)) { Link_array gs = Pointer_group_interface__extract_grobs (c, (Grob*)0, "elements"); diff --git a/lily/collision-engraver.cc b/lily/collision-engraver.cc index 2b8c4923fe..8e8c0f4fa0 100644 --- a/lily/collision-engraver.cc +++ b/lily/collision-engraver.cc @@ -7,7 +7,7 @@ */ #include "note-column.hh" -#include "collision.hh" +#include "note-collision.hh" #include "engraver.hh" #include "axis-group-interface.hh" @@ -40,7 +40,7 @@ Collision_engraver::create_grobs () } for (int i=0; i< note_column_l_arr_.size (); i++) - Collision::add_column (col_p_,note_column_l_arr_[i]); + Note_collision_interface::add_column (col_p_,note_column_l_arr_[i]); } void diff --git a/lily/include/collision.hh b/lily/include/note-collision.hh similarity index 80% rename from lily/include/collision.hh rename to lily/include/note-collision.hh index 5704ca9789..e8674d9aeb 100644 --- a/lily/include/collision.hh +++ b/lily/include/note-collision.hh @@ -25,11 +25,13 @@ * Make interface of this, similar to align-interface. */ -class Collision // interface +class Note_collision_interface { public: - static SCM automatic_shift (Grob*); + static SCM automatic_shift (Grob*, Drul_array< Link_array >); static SCM forced_shift (Grob*); + + static Drul_array< Link_array > get_clash_groups (Grob *me); DECLARE_SCHEME_CALLBACK (force_shift_callback, (SCM element, SCM axis)); static void do_shifts (Grob*); static void add_column (Grob*me,Grob*ncol_l); diff --git a/lily/include/note-head.hh b/lily/include/note-head.hh index 55a9aa0b5a..aba379dec6 100644 --- a/lily/include/note-head.hh +++ b/lily/include/note-head.hh @@ -27,7 +27,7 @@ public: DECLARE_SCHEME_CALLBACK (brew_ez_molecule, (SCM )); static bool has_interface (Grob*); static Real stem_attachment_coordinate (Grob *, Axis a); - + static int balltype_i (Grob*) ; }; #endif // NOTEHEAD_HH diff --git a/lily/include/rhythmic-head.hh b/lily/include/rhythmic-head.hh index af4af02ae8..1da23356b1 100644 --- a/lily/include/rhythmic-head.hh +++ b/lily/include/rhythmic-head.hh @@ -16,7 +16,7 @@ class Rhythmic_head { public: - static int balltype_i (Grob*) ; + static int duration_log (Grob*); static void set_dots (Grob*,Item *); static Item * stem_l (Grob*) ; static Item * dots_l (Grob*) ; diff --git a/lily/mensural-ligature-engraver.cc b/lily/mensural-ligature-engraver.cc index 9adb710d8f..9be0e8a0cf 100644 --- a/lily/mensural-ligature-engraver.cc +++ b/lily/mensural-ligature-engraver.cc @@ -340,7 +340,7 @@ Mensural_ligature_engraver::transform_heads () have_last_pitch = have_pitch; Grob_info info = primitives_arr_[i]; int duration_log = - Rhythmic_head::balltype_i (dynamic_cast (info.grob_l_)); + Note_head::balltype_i (dynamic_cast (info.grob_l_)); Note_req *nr = dynamic_cast (info.music_cause ()); if (!nr) { diff --git a/lily/collision.cc b/lily/note-collision.cc similarity index 75% rename from lily/collision.cc rename to lily/note-collision.cc index ee4b039f13..fa977fda00 100644 --- a/lily/collision.cc +++ b/lily/note-collision.cc @@ -1,3 +1,4 @@ + /* collision.cc -- implement Collision @@ -7,18 +8,19 @@ */ #include "debug.hh" -#include "collision.hh" +#include "note-collision.hh" #include "note-column.hh" +#include "note-head.hh" #include "rhythmic-head.hh" #include "paper-def.hh" #include "axis-group-interface.hh" #include "item.hh" #include "stem.hh" -MAKE_SCHEME_CALLBACK (Collision,force_shift_callback,2); +MAKE_SCHEME_CALLBACK (Note_collision_interface,force_shift_callback,2); SCM -Collision::force_shift_callback (SCM element_smob, SCM axis) +Note_collision_interface::force_shift_callback (SCM element_smob, SCM axis) { Grob *me = unsmob_grob (element_smob); Axis a = (Axis) gh_scm2int (axis); @@ -106,18 +108,32 @@ check_meshing_chords (Grob*me, bool merge_possible = (ups[0] >= dps[0]) && (ups.top () >= dps.top ()); - merge_possible = merge_possible && - Rhythmic_head::balltype_i (nu_l) == Rhythmic_head::balltype_i (nd_l); - - /* don't merge whole notes (or longer, like breve, longa, maxima) */ - merge_possible = merge_possible && (Rhythmic_head::balltype_i (nu_l) > 0); + + int upball_type = Note_head::balltype_i (nu_l); + int dnball_type = Note_head::balltype_i (nd_l); + + merge_possible = merge_possible && (upball_type > 0); if (!to_boolean (me->get_grob_property ("merge-differently-dotted"))) merge_possible = merge_possible && Rhythmic_head::dot_count (nu_l) == Rhythmic_head::dot_count (nd_l); + + if (!to_boolean (me->get_grob_property ("merge-differently-headed"))) + merge_possible = merge_possible && + upball_type == dnball_type; + else + /* + Can't merge quarter and half notes. + */ + merge_possible = merge_possible && + !((Rhythmic_head::duration_log (nu_l) == 1 + && Rhythmic_head::duration_log (nd_l) == 2) + ||(Rhythmic_head::duration_log (nu_l) == 2 + && Rhythmic_head::duration_log (nd_l) == 1)); + int i = 0, j=0; while (i < ups.size () && j < dps.size ()) { @@ -170,7 +186,21 @@ check_meshing_chords (Grob*me, to tune this behavior. */ if (merge_possible) - shift_amount *= 0.0; + { + shift_amount *= 0.0; + Grob *wipe_ball = 0; + + if (upball_type < dnball_type) + wipe_ball = nd_l; + else if (upball_type > dnball_type) + wipe_ball = nu_l; + + if (wipe_ball) + { + wipe_ball->set_grob_property ("transparent", SCM_BOOL_T); + wipe_ball->set_grob_property ("molecule", SCM_EOL); + } + } else if (close_half_collide && !touch) shift_amount *= 0.52; else if (distant_half_collide && !touch) @@ -195,30 +225,31 @@ check_meshing_chords (Grob*me, while ((flip (&d))!= UP); } - -/* - TODO: make callback of this. - - TODO: - - note-width is hardcoded, making it difficult to handle all note - heads sanely. We should really look at the widths of the colliding - columns, and have a separate setting for "align stems". - - - */ void -Collision::do_shifts (Grob* me) +Note_collision_interface::do_shifts (Grob* me) { - SCM autos (automatic_shift (me)); + Drul_array< Link_array > cg = get_clash_groups (me); + + SCM autos (automatic_shift (me, cg)); SCM hand (forced_shift (me)); - - Link_array done; + + + Direction d = UP; + Real wid = 0.0; + do + { + if(cg[d].size()) + { + Grob *h = cg[d][0]; + wid = Note_column::first_head(h)->extent(h,X_AXIS).length() ; + } + } + + while (flip (&d) != UP); - Real wid - = gh_scm2double (me->get_grob_property ("note-width")); + Link_array done; for (; gh_pair_p (hand); hand =ly_cdr (hand)) { Grob * s = unsmob_grob (ly_caar (hand)); @@ -237,18 +268,11 @@ Collision::do_shifts (Grob* me) } } -/** This complicated routine moves note columns around horizontally to - ensure that notes don't clash. - - This should be put into Scheme. - */ -SCM -Collision::automatic_shift (Grob *me) +Drul_array< Link_array > +Note_collision_interface::get_clash_groups (Grob *me) { Drul_array > clash_groups; - Drul_array > shifts; - SCM tups = SCM_EOL; - + SCM s = me->get_grob_property ("elements"); for (; gh_pair_p (s); s = ly_cdr (s)) { @@ -258,6 +282,30 @@ Collision::automatic_shift (Grob *me) if (Note_column::has_interface (se)) clash_groups[Note_column::dir (se)].push (se); } + + Direction d = UP; + do + { + Link_array & clashes (clash_groups[d]); + clashes.sort (Note_column::shift_compare); + } + while ((flip (&d))!= UP); + + return clash_groups; +} + +/** This complicated routine moves note columns around horizontally to + ensure that notes don't clash. + + This should be put into Scheme. + */ +SCM +Note_collision_interface::automatic_shift (Grob *me, + Drul_array< Link_array > + clash_groups) +{ + Drul_array > shifts; + SCM tups = SCM_EOL; Direction d = UP; @@ -266,8 +314,6 @@ Collision::automatic_shift (Grob *me) Array & shift (shifts[d]); Link_array & clashes (clash_groups[d]); - clashes.sort (Note_column::shift_compare); - for (int i=0; i < clashes.size (); i++) { SCM sh @@ -348,7 +394,7 @@ Collision::automatic_shift (Grob *me) SCM -Collision::forced_shift (Grob *me) +Note_collision_interface::forced_shift (Grob *me) { SCM tups = SCM_EOL; @@ -368,16 +414,18 @@ Collision::forced_shift (Grob *me) } void -Collision::add_column (Grob*me,Grob* ncol_l) +Note_collision_interface::add_column (Grob*me,Grob* ncol_l) { - ncol_l->add_offset_callback (Collision::force_shift_callback_proc, X_AXIS); + ncol_l->add_offset_callback (Note_collision_interface::force_shift_callback_proc, X_AXIS); Axis_group_interface::add_element (me, ncol_l); me->add_dependency (ncol_l); } -ADD_INTERFACE (Collision, "note-collision-interface", - "An object that handles collisions between notes with different -stem directions and horizontal shifts. Most of the interesting -properties are to be set in @ref{note-column-interface}", - "merge-differently-dotted note-width collision-done"); +ADD_INTERFACE (Note_collision_interface, "note-collision-interface", + "An object that handles collisions between notes with different stem +directions and horizontal shifts. Most of the interesting properties +are to be set in @ref{note-column-interface}: these are +@code{force-hshift} and @{horizontal-shift}. +", + "merge-differently-dotted merge-differently-headed collision-done"); diff --git a/lily/note-head.cc b/lily/note-head.cc index 01ecae6a33..1967691f0e 100644 --- a/lily/note-head.cc +++ b/lily/note-head.cc @@ -121,7 +121,7 @@ internal_brew_molecule (Grob *me, bool ledger_take_space) UGH: use grob-property. */ - SCM log = gh_int2scm (Rhythmic_head::balltype_i (me)); + SCM log = gh_int2scm (Note_head::balltype_i (me)); SCM exp = scm_list_n (ly_symbol2scm ("find-notehead-symbol"), log, ly_quote_scm (style), SCM_UNDEFINED); @@ -191,7 +191,7 @@ SCM Note_head::brew_ez_molecule (SCM smob) { Grob *me = unsmob_grob (smob); - int l = Rhythmic_head::balltype_i (me); + int l = Note_head::balltype_i (me); int b = (l >= 2); @@ -246,6 +246,15 @@ Note_head::stem_attachment_coordinate (Grob *me, Axis a) return gh_number_p (result) ? gh_scm2double (result) : 0.0; } + +int +Note_head::balltype_i (Grob*me) +{ + SCM s = me->get_grob_property ("duration-log"); + return gh_number_p (s) ? gh_scm2int (s) get_grob_property ("duration-log"); - return gh_number_p (s) ? gh_scm2int (s) get_grob_property ("duration-log"); + return gh_number_p (s) ? gh_scm2int (s) : 0; +} + ADD_INTERFACE (Rhythmic_head,"rhythmic-head-interface", diff --git a/lily/stem.cc b/lily/stem.cc index 7b8db24062..2b1ad6440a 100644 --- a/lily/stem.cc +++ b/lily/stem.cc @@ -122,7 +122,7 @@ Stem::set_stemend (Grob*me, Real se) int Stem::type_i (Grob*me) { - return first_head (me) ? Rhythmic_head::balltype_i (first_head (me)) : 2; + return first_head (me) ? Note_head::balltype_i (first_head (me)) : 2; } /* @@ -238,7 +238,7 @@ Stem::add_head (Grob*me, Grob *n) bool Stem::invisible_b (Grob*me) { - return ! (head_count (me) && Rhythmic_head::balltype_i (support_head (me)) >= 1); + return ! (head_count (me) && Note_head::balltype_i (support_head (me)) >= 1); } Direction diff --git a/scm/grob-property-description.scm b/scm/grob-property-description.scm index 22fc2fc0d2..7f5e9b11cc 100644 --- a/scm/grob-property-description.scm +++ b/scm/grob-property-description.scm @@ -223,7 +223,17 @@ and will have no effect. (grob-property-description 'measure-length moment? "Length of a measure. Used in some spacing situations.") (grob-property-description 'measure-count integer? "number of measures for a multimeasure rest.") -(grob-property-description 'merge-differently-dotted boolean? " Merge noteheads in collisions, even if they have a different number of dots. This normal notation for some types of polyphonic music. The value of this setting is used by @ref{note-collision-interface} .") + +(grob-property-description 'merge-differently-headed boolean? "Merge +noteheads in collisions, even if they have different note heads. The +smaller of the two heads will be rendered invisible. This used +polyphonic guitar notation. The value of this setting is used by +@ref{note-collision-interface} .") + +(grob-property-description 'merge-differently-dotted boolean? " Merge +noteheads in collisions, even if they have a different number of +dots. This normal notation for some types of polyphonic music. The +value of this setting is used by @ref{note-collision-interface} .") (grob-property-description 'meta list? "Alist of meta information of this grob.") (grob-property-description 'minimum-distance number? "minimum distance between notes and rests.") @@ -254,7 +264,6 @@ FIXME: also pair? (cons LEFT RIGHT) (grob-property-description 'no-spacing-rods boolean? "read from grobs: boolean that makes Separation_item ignore this item (MOVE ME TO ITEM).") (grob-property-description 'no-stem-extend boolean? "should stem not be extended to middle staff line?.") (grob-property-description 'non-default boolean? "not set because of existence of a bar?.") -(grob-property-description 'note-width number? "unit for horizontal translation, measured in staff-space.") (grob-property-description 'note-heads list? "List of note head grobs") (grob-property-description 'number-threshold number? "only put numbers bigger than this threshold over multi measuer rest.") (grob-property-description 'old-accidentals list? "list of (pitch, accidental) pairs.") diff --git a/scripts/lilypond-book.py b/scripts/lilypond-book.py index cd0191b0c7..aaa1f57370 100644 --- a/scripts/lilypond-book.py +++ b/scripts/lilypond-book.py @@ -1246,6 +1246,7 @@ def compile_all_files (chunks): texfiles = string.join (tex, ' ') cmd = 'lilypond --header=texidoc %s %s %s' \ % (lilyopts, g_extra_opts, texfiles) + system (cmd) # -- 2.39.5