From: hanwen Date: Tue, 6 Jan 2004 14:50:35 +0000 (+0000) Subject: * lily/dot-column.cc (dot_config_badness): new function: X-Git-Tag: release/2.1.7~5 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=d59b47f74453d6c807064aaae0562bd4aa25f20e;p=lilypond.git * lily/dot-column.cc (dot_config_badness): new function: select the best scoring dot configuration: dots should go close to the note heads, but be shifted up or down according to conventions. (print_dot_configuration): idem. (shift_one): idem (remove_collision): idem. * input/regression/dots.ly: add more test cases. --- diff --git a/ChangeLog b/ChangeLog index 903521b6ea..5cc5c36b2c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2004-01-06 Han-Wen Nienhuys + + * lily/dot-column.cc (dot_config_badness): new function: + select the best scoring dot configuration: dots should go close to + the note heads, but be shifted up or down according to conventions. + (print_dot_configuration): idem. + (shift_one): idem + (remove_collision): idem. + + * input/regression/dots.ly: add more test cases. + 2004-01-06 Han-Wen Nienhuys * lily/include/scm-hash.hh (class Scheme_hash_table): idem. diff --git a/Documentation/topdocs/NEWS.texi b/Documentation/topdocs/NEWS.texi index 1fc4109a51..a2bfabf60c 100644 --- a/Documentation/topdocs/NEWS.texi +++ b/Documentation/topdocs/NEWS.texi @@ -8,6 +8,8 @@ @chapter New features in 2.1 since 2.0 @itemize +@item Collision resolution for dots in chords has been improved greatly. + @item Spacing following barlines was improved for widely stretched lines. diff --git a/input/regression/dots.ly b/input/regression/dots.ly index 3409e44e17..dd246b5924 100644 --- a/input/regression/dots.ly +++ b/input/regression/dots.ly @@ -1,11 +1,22 @@ -\version "1.9.8" -\header{ -texidoc=" -Noteheads can have dots, and rests can too. Augmentation dots should -never be printed on a staff line, but rather be shifted vertically. They -should go up, but in case of multiple parts, the down stems have down -shifted dots. (Wanske p. 186) In case of chords, all dots should be in -a column. The dots go along as rests are shifted to avoid collisions. +\version "1.9.8" \header{ + + + texidoc=" Noteheads can have dots, and rests +can too. Augmentation dots should never be printed on a staff line, +but rather be shifted vertically. They should go up, but in case of +multiple parts, the down stems have down shifted dots. In case of +chords, all dots should be in a column. The dots go along as rests +are shifted to avoid collisions. + +The priorities, are (ranked in importance): + +@itemize @bullet +@item keeping dots off staff lines +@item keeping dots close to their note heads +@item moving dots in the direction specified by the voice +@item moving dots up +@end itemize + " } @@ -17,7 +28,7 @@ a column. The dots go along as rests are shifted to avoid collisions. d4. g,, \stemDown 4. - + << diff --git a/lily/dot-column.cc b/lily/dot-column.cc index dbc20d40c4..d492a4580d 100644 --- a/lily/dot-column.cc +++ b/lily/dot-column.cc @@ -7,6 +7,7 @@ */ #include +#include #include "dots.hh" #include "dot-column.hh" @@ -35,10 +36,9 @@ Dot_column::force_shift_callback (SCM element_smob, SCM axis) if (!to_boolean (me->get_grob_property ("collision-done"))) { - SCM l = me->get_grob_property ("dots"); me->set_grob_property ("collision-done", SCM_BOOL_T); - do_shifts (me, l); + do_shifts (me); } return gh_double2scm (0.0); } @@ -69,81 +69,208 @@ Dot_column::side_position (SCM element_smob, SCM axis) } -/* - Put the dots in the spaces, close to the heads. - - This is somewhat gruesome; the problem really is - minimize (sum_j dist (head_j, dot_j)) +struct Dot_position +{ + int pos_; + Direction dir_; + Grob *dot_; + bool extremal_head_; - over all configurations. This sounds like a messy optimization - problem to solve. + Dot_position () + { + dot_ = 0; + pos_ =0; + dir_ = CENTER; + } +}; + + +typedef std::map Dot_configuration; + +/* + Value CFG according. + */ -SCM -Dot_column::do_shifts (Grob*me, SCM l) +int +dot_config_badness (Dot_configuration const &cfg) { - Link_array dots; - while (gh_pair_p (l)) + int t = 0; + for (Dot_configuration::const_iterator i (cfg.begin ()); + i != cfg.end (); i++) { - dots.push (unsmob_grob (ly_car (l))); - l = ly_cdr (l); + int p = i->first; + int demerit = sqr (p - i->second.pos_) * 2; + + int dot_move_dir = sign (p - i->second.pos_); + if (i->second.extremal_head_) + { + if (i->second.dir_ + && dot_move_dir != i->second.dir_) + demerit += 3; + else if (dot_move_dir != UP) + demerit += 2; + } + else if (dot_move_dir != UP) + demerit += 1; + + t += demerit; } - - dots.sort (compare_position); - - set taken_posns; - for (int i=0; i < dots.size (); i++) - { - Grob * d = dots[i]; - int p = int (Staff_symbol_referencer::get_position (d)); + return t; +} + +void +print_dot_configuration (Dot_configuration const &cfg) +{ + printf ("dotconf { "); + for (Dot_configuration::const_iterator i (cfg.begin ()); + i != cfg.end (); i++) + printf ("%d, " , i->first); + printf ("} \n"); +} + +/* + Shift K and following (preceding) entries up (down) as necessary to + prevent staffline collisions if D is up (down). - if (Staff_symbol_referencer::on_staffline (d, p) - || taken_posns.find (p) != taken_posns.end ()) + If K is in CFG, then do nothing. +*/ + +Dot_configuration +shift_one (Dot_configuration const &cfg, + int k, Direction d) +{ + Dot_configuration new_cfg; + int offset = 0; + + if (d > 0) + { + for (Dot_configuration::const_iterator i (cfg.begin ()); + i != cfg.end (); i++) { - int pd = p; - int pu = p; - if (Staff_symbol_referencer::on_staffline (d, p)) + int p = i->first; + if (p == k) { - pu ++; - pd --; + if (Staff_symbol_referencer::on_staffline (i->second.dot_, p)) + p += d ; + else + p += 2* d; + + offset = 2*d; + + new_cfg[p] = i->second; } - - Direction dir = to_dir (d->get_grob_property ("direction")); - if (dir != DOWN) - - while (1) + else { - if (dir != DOWN) + if (new_cfg.find (p) == new_cfg.end ()) { - if (taken_posns.find (pu) == taken_posns.end ()) - { - p = pu; - break; - } - pu += 2; + offset =0; } - if (dir != UP) + new_cfg[p + offset] = i->second; + } + } + } + else + { + Dot_configuration::const_iterator i (cfg.end ()); + do + { + i --; + + int p = i->first; + if (p == k) + { + if (Staff_symbol_referencer::on_staffline (i->second.dot_, p)) + p += d ; + else + p += 2* d; + + offset = 2*d; + + new_cfg[p] = i->second; + } + else + { + if (new_cfg.find (p) == new_cfg.end ()) { - if (taken_posns.find (pd) == taken_posns.end ()) - { - p = pd; - break; - } - pd -= 2; + offset =0; } + + new_cfg[p + offset] = i->second; } - Staff_symbol_referencer::set_position (d, p); } - - taken_posns.insert (p); + while (i != cfg.begin ()); } - return SCM_UNSPECIFIED; + return new_cfg; } +/* + Remove the collision in CFG either by shifting up or down, whichever + is best. + */ +void +remove_collision (Dot_configuration &cfg, int p) +{ + bool collide = cfg.find (p) != cfg.end (); + if (collide) + { + Dot_configuration cfg_up = shift_one (cfg, p, UP); + Dot_configuration cfg_down = shift_one (cfg, p, DOWN); + + int b_up = dot_config_badness (cfg_up); + int b_down = dot_config_badness (cfg_down); + + cfg = (b_up < b_down) ? cfg_up : cfg_down; + } +} + +SCM +Dot_column::do_shifts (Grob*me) +{ + + Link_array dots = + Pointer_group_interface__extract_grobs (me, (Grob*)0, "dots"); + + dots.sort (compare_position); + + Dot_configuration cfg; + for (int i =0;i < dots.size (); i++) + { + Dot_position dp; + dp.dot_ = dots[i]; + + Grob * note = dots[i]->get_parent (Y_AXIS); + if (note) + { + Grob *stem = unsmob_grob (note->get_grob_property ("stem")); + if (stem) + dp.extremal_head_ = Stem::first_head (stem) == note; + } + + int p = int (Staff_symbol_referencer::get_position (dp.dot_)); + dp.pos_= p; + + if (dp.extremal_head_) + dp.dir_ = to_dir (dp.dot_->get_grob_property ("direction")); + + remove_collision (cfg, p); + cfg[p] = dp; + if (Staff_symbol_referencer::on_staffline (dp.dot_, p)) + remove_collision (cfg, p); + } + + for (Dot_configuration::const_iterator i (cfg.begin ()); + i != cfg.end (); i++) + { + Staff_symbol_referencer::set_position (i->second.dot_, i->first); + } + + return SCM_UNSPECIFIED; +} void Dot_column::add_head (Grob * me, Grob *rh) diff --git a/lily/include/dot-column.hh b/lily/include/dot-column.hh index a4d8a52553..2e31e03b99 100644 --- a/lily/include/dot-column.hh +++ b/lily/include/dot-column.hh @@ -24,6 +24,6 @@ public: static bool has_interface (Grob*); DECLARE_SCHEME_CALLBACK (force_shift_callback, (SCM ,SCM)); DECLARE_SCHEME_CALLBACK (side_position, (SCM ,SCM)); - static SCM do_shifts (Grob*,SCM dotlist); + static SCM do_shifts (Grob*); }; #endif // DOT_COLUMN_HH