X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fnote-collision.cc;h=d93260afd624419ce48d11761f0064cc927bf8b1;hb=840936be1b28526ef292b5dae8ae031b4fa587f9;hp=bcdd36b4d5ec4aca26399868c5992b4d605dc01d;hpb=791dceb3e66575a6e8bc837c7f461b198837c0d0;p=lilypond.git diff --git a/lily/note-collision.cc b/lily/note-collision.cc index bcdd36b4d5..d93260afd6 100644 --- a/lily/note-collision.cc +++ b/lily/note-collision.cc @@ -1,9 +1,9 @@ /* - collision.cc -- implement Collision + note-collision.cc -- implement Note_collision source file of the GNU LilyPond music typesetter - (c) 1997--2007 Han-Wen Nienhuys + (c) 1997--2009 Han-Wen Nienhuys */ #include "note-collision.hh" @@ -30,7 +30,7 @@ check_meshing_chords (Grob *me, Drul_array > const &clash_groups) { - if (!extents[UP].size () || ! extents[DOWN].size ()) + if (!extents[UP].size () || !extents[DOWN].size ()) return; Grob *clash_up = clash_groups[UP][0]; @@ -49,7 +49,7 @@ check_meshing_chords (Grob *me, vector ups = Stem::note_head_positions (Note_column::get_stem (clash_up)); vector dps = Stem::note_head_positions (Note_column::get_stem (clash_down)); - /* Too far apart to collide. */ + /* Too far apart to collide. */ if (ups[0] > dps.back () + 1) return; @@ -65,7 +65,7 @@ check_meshing_chords (Grob *me, int up_ball_type = Rhythmic_head::duration_log (head_up); int down_ball_type = Rhythmic_head::duration_log (head_down); - /* Do not merge whole notes (or longer, like breve, longa, maxima). */ + /* Do not merge whole notes (or longer, like breve, longa, maxima). */ if (merge_possible && (up_ball_type <= 0 || down_ball_type <= 0)) merge_possible = false; @@ -74,23 +74,12 @@ check_meshing_chords (Grob *me, && !to_boolean (me->get_property ("merge-differently-dotted"))) merge_possible = false; - /* Can only merge different heads if merge-differently-headed is - set. */ + /* Can only merge different heads if merge-differently-headed is set. */ if (merge_possible && up_ball_type != down_ball_type && !to_boolean (me->get_property ("merge-differently-headed"))) merge_possible = false; - if (merge_possible - && head_up->get_property ("style") == ly_symbol2scm ("fa") - && head_down->get_property ("style") == ly_symbol2scm ("fa")) - { - Interval uphead_size = head_up->extent (head_up, Y_AXIS); - Offset att = Offset (0.0, -1.0); - head_up->set_property ("stem-attachment", ly_offset2scm (att)); - head_up->set_property ("transparent", SCM_BOOL_T); - } - /* Should never merge quarter and half notes, as this would make them indistinguishable. */ if (merge_possible @@ -164,30 +153,49 @@ check_meshing_chords (Grob *me, full_collide = full_collide || (close_half_collide && distant_half_collide); - Drul_array center_note_shifts; - center_note_shifts[LEFT] = 0.0; - center_note_shifts[RIGHT] = 0.0; - Real shift_amount = 1; bool touch = (ups[0] >= dps.back ()); + /* As a special case, if the topmost part of the downstem chord is a second, + the top note of which is the same pitch as the lowest upstem note, they + shouldn't count as touching. + */ + if (dps.back () == ups[0] && dps.size () > 1 && dps[dps.size() - 2] == ups[0] - 1) + touch = false; + if (touch) shift_amount *= -1; /* For full collisions, the right hand head may obscure dots, so - make sure the dotted heads go to the right. */ + make sure the dotted heads go to the right. */ bool stem_to_stem = false; if (full_collide) - if (Rhythmic_head::dot_count (head_up) > Rhythmic_head::dot_count (head_down)) - shift_amount = 1; - else if (Rhythmic_head::dot_count (head_up) < Rhythmic_head::dot_count (head_down)) - stem_to_stem = true; + { + if (Rhythmic_head::dot_count (head_up) > Rhythmic_head::dot_count (head_down)) + shift_amount = 1; + else if (Rhythmic_head::dot_count (head_up) < Rhythmic_head::dot_count (head_down)) + stem_to_stem = true; + } + /* The solfa is a triangle, which is inverted depending on stem + direction. In case of a collision, one of them should be removed, + so the resulting note does not look like a block. + */ + if (merge_possible + && head_up->get_property ("style") == ly_symbol2scm ("fa") + && head_down->get_property ("style") == ly_symbol2scm ("fa")) + { + Interval uphead_size = head_up->extent (head_up, Y_AXIS); + Offset att = Offset (0.0, -1.0); + head_up->set_property ("stem-attachment", ly_offset2scm (att)); + head_up->set_property ("transparent", SCM_BOOL_T); + } + if (merge_possible) { shift_amount = 0; - /* If possible, don't wipe any heads. Else, wipe shortest head, + /* If possible, don't wipe any heads. Else, wipe shortest head, or head with smallest amount of dots. Note: when merging different heads, dots on the smaller one disappear. */ Grob *wipe_ball = 0; @@ -217,6 +225,15 @@ check_meshing_chords (Grob *me, { wipe_ball = head_up; dot_wipe_head = head_up; + /* + If upper head is eighth note or shorter, and lower head is half note, + shift by the difference between the open and filled note head widths, + otherwise upper stem will be misaligned slightly. + */ + if (Stem::duration_log (stems[DOWN]) == 1 + && Stem::duration_log (stems[UP]) >= 3) + shift_amount = (1 - head_up->extent (head_up, X_AXIS).length () / + head_down->extent (head_down, X_AXIS).length ()) * 0.5; } if (dot_wipe_head) @@ -226,12 +243,10 @@ check_meshing_chords (Grob *me, } if (wipe_ball && wipe_ball->is_live ()) - { - wipe_ball->set_property ("transparent", SCM_BOOL_T); - } + wipe_ball->set_property ("transparent", SCM_BOOL_T); } /* TODO: these numbers are magic; should devise a set of grob props - to tune this behavior. */ + to tune this behavior. */ else if (stem_to_stem) shift_amount = -abs (shift_amount) * 0.65; else if (close_half_collide && !touch) @@ -241,7 +256,7 @@ check_meshing_chords (Grob *me, else if (distant_half_collide || close_half_collide || full_collide) shift_amount *= 0.5; - /* we're meshing. */ + /* we're meshing. */ else if (Rhythmic_head::dot_count (head_up) || Rhythmic_head::dot_count (head_down)) shift_amount *= 0.1; else @@ -278,15 +293,23 @@ check_meshing_chords (Grob *me, Grob *staff = Staff_symbol_referencer::get_staff_symbol (me); if (!Staff_symbol_referencer::on_line (staff, ups[0])) { - Grob *d = unsmob_grob (head_up->get_object ("dot")); - Grob *parent = d->get_parent (X_AXIS); - if (Dot_column::has_interface (parent)) - Side_position_interface::add_support (parent, head_down); + /* + TODO: consider junking the else body. + */ + if (to_boolean (me->get_property ("prefer-dotted-right"))) + shift_amount = 0.5; + else + { + Grob *d = unsmob_grob (head_up->get_object ("dot")); + Grob *parent = d->get_parent (X_AXIS); + if (Dot_column::has_interface (parent)) + Side_position_interface::add_support (parent, head_down); + } } } /* For full or close half collisions, the right hand head may - obscure dots. Move dots to the right. */ + obscure dots. Move dots to the right. */ if (abs (shift_amount) > 1e-6 && Rhythmic_head::dot_count (head_down) > Rhythmic_head::dot_count (head_up) && (full_collide || close_half_collide)) @@ -331,30 +354,30 @@ Note_collision_interface::calc_positioning_done (SCM smob) Grob *me = unsmob_grob (smob); me->set_property ("positioning-done", SCM_BOOL_T); - Drul_array > cg = get_clash_groups (me); + Drul_array > clash_groups = get_clash_groups (me); Direction d = UP; do { - for (vsize i = cg[d].size (); i--; ) + for (vsize i = clash_groups[d].size (); i--; ) { /* Trigger positioning - */ - cg[d][i]->extent (me, X_AXIS); + */ + clash_groups[d][i]->extent (me, X_AXIS); } } while (flip (&d) != UP); - SCM autos (automatic_shift (me, cg)); + SCM autos (automatic_shift (me, clash_groups)); SCM hand (forced_shift (me)); Real wid = 0.0; do { - if (cg[d].size ()) + if (clash_groups[d].size ()) { - Grob *h = cg[d][0]; + Grob *h = clash_groups[d][0]; Grob *fh = Note_column::first_head (h); if (fh) wid = fh->extent (h, X_AXIS).length (); @@ -409,9 +432,7 @@ Note_collision_interface::get_clash_groups (Grob *me) if (Note_column::has_interface (se)) { if (!Note_column::dir (se)) - { - se->programming_error ("note-column has no direction"); - } + se->programming_error ("note-column has no direction"); else clash_groups[Note_column::dir (se)].push_back (se); } @@ -428,9 +449,9 @@ Note_collision_interface::get_clash_groups (Grob *me) return clash_groups; } -/** This complicated routine moves note columns around horizontally to - ensure that notes don't clash. - +/* + This complicated routine moves note columns around horizontally to + ensure that notes don't clash. */ SCM Note_collision_interface::automatic_shift (Grob *me, @@ -509,7 +530,7 @@ Note_collision_interface::automatic_shift (Grob *me, /* see input/regression/dot-up-voice-collision.ly - */ + */ for (vsize i = 0; i < clash_groups[UP].size (); i++) { Grob *g = clash_groups[UP][i]; @@ -553,10 +574,8 @@ Note_collision_interface::forced_shift (Grob *me) SCM force = se->get_property ("force-hshift"); if (scm_is_number (force)) - { - tups = scm_cons (scm_cons (se->self_scm (), force), - tups); - } + tups = scm_cons (scm_cons (se->self_scm (), force), + tups); } return tups; } @@ -569,12 +588,15 @@ Note_collision_interface::add_column (Grob *me, Grob *ncol) } ADD_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 @code{horizontal-shift}.", + "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 @code{horizontal-shift}.", /* properties */ "merge-differently-dotted " "merge-differently-headed " - "positioning-done "); + "positioning-done " + "prefer-dotted-right " + );