X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;ds=sidebyside;f=lily%2Fcollision.cc;h=5c0ae795180a2282a5e0150e3b1567b43854e175;hb=68a168bff1fec7f8011b2afa82d4fc89182c4bf7;hp=2fbb0d80187447ffaa0b6d89722abac13a45ae76;hpb=d8018dfc750f1dee8e1ee78a5d5f51b06d4c8348;p=lilypond.git diff --git a/lily/collision.cc b/lily/collision.cc index 2fbb0d8018..5c0ae79518 100644 --- a/lily/collision.cc +++ b/lily/collision.cc @@ -1,151 +1,232 @@ /* collision.cc -- implement Collision - source file of the LilyPond music typesetter + source file of the GNU LilyPond music typesetter - (c) 1997 Han-Wen Nienhuys + (c) 1997--2001 Han-Wen Nienhuys */ + #include "debug.hh" #include "collision.hh" #include "note-column.hh" -#include "notehead.hh" +#include "rhythmic-head.hh" #include "paper-def.hh" +#include "axis-group-interface.hh" +#include "item.hh" + + +MAKE_SCHEME_CALLBACK (Collision,force_shift_callback,2); -Collision::Collision() +SCM +Collision::force_shift_callback (SCM element_smob, SCM axis) { + Grob *me = unsmob_grob (element_smob); + Axis a = (Axis) gh_scm2int (axis); + assert (a == X_AXIS); + + me = me->parent_l (a); + /* + ugh. the way DONE is done is not clean + */ + if (!unsmob_grob (me->get_grob_property ("done"))) + { + me->set_grob_property ("done", me->self_scm ()); + do_shifts (me); + } + + return gh_double2scm (0.0); } +/* + TODO: make callback of this. + */ void -Collision::add(Note_column* ncol_l) +Collision::do_shifts (Grob* me) { - clash_l_arr_.push(ncol_l); - add_dependency(ncol_l); -} -static -int idx(int dir, bool h_shift_b) -{ - assert(abs (dir) == 1); - int j = dir > 0 ? 0 : 3; - if ( h_shift_b ) - j += dir; - return j; + SCM autos (automatic_shift (me)); + SCM hand (forced_shift (me)); + + Link_array done; + + Real wid + = gh_scm2double (me->get_grob_property ("note-width")); + + for (; gh_pair_p (hand); hand =gh_cdr (hand)) + { + Grob * s = unsmob_grob (gh_caar (hand)); + Real amount = gh_scm2double (gh_cdar (hand)); + + s->translate_axis (amount *wid, X_AXIS); + done.push (s); + } + for (; gh_pair_p (autos); autos =gh_cdr (autos)) + { + Grob * s = unsmob_grob (gh_caar (autos)); + Real amount = gh_scm2double (gh_cdar (autos)); + + if (!done.find_l (s)) + s->translate_axis (amount * wid, X_AXIS); + } } -/** This complicated routine moves note columns around horizontally - (and rests vertically) to ensure that notes don't clash. - - This should be done better, probably. - - This routine is dedicated to Stine Randmael :-) +/** This complicated routine moves note columns around horizontally to + ensure that notes don't clash. + This should be put into Scheme. */ -void -Collision::do_pre_processing() +SCM +Collision::automatic_shift (Grob *me) { - if (clash_l_arr_.size() <= 1) - return; - - /* - [stem up, stem up shifted, stem down shifted, stem down] - */ - Array clash_group_arr_a[4]; - - for (int i=0; i < clash_l_arr_.size(); i++) { - Note_column* c_l = clash_l_arr_[i]; - int d = (c_l->dir_i_); - - clash_group_arr_a[idx(d, c_l->h_shift_b_)].push(c_l); + Drul_array > clash_groups; + Drul_array > shifts; + SCM tups = SCM_EOL; + + SCM s = me->get_grob_property ("elements"); + for (; gh_pair_p (s); s = gh_cdr (s)) + { + SCM car = gh_car (s); + + Grob * se = unsmob_grob (car); + if (Note_column::has_interface (se)) + clash_groups[Note_column::dir (se)].push (se); } - - for (int j=0; j < 4; j++) { - if (clash_group_arr_a[j].size() > 1) { - warning("Too many clashing notecolumns. Ignoring them."); - return; + + + Direction d = UP; + do + { + 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 + = clashes[i]->get_grob_property ("horizontal-shift"); + + if (gh_number_p (sh)) + shift.push (gh_scm2int (sh)); + else + shift.push (0); + } + + for (int i=1; i < shift.size (); i++) + { + if (shift[i-1] == shift[i]) + { + warning (_ ("Too many clashing notecolumns. Ignoring them.")); + return tups; + } } } - int d = 1; - do { - if (!clash_group_arr_a[idx(d, false)].size()){ - clash_group_arr_a[idx(d, false)] = clash_group_arr_a[idx(d, true)]; - clash_group_arr_a[idx(d, true)].set_size(0); + while ((flip (&d))!= UP); + + Drul_array< Array < Slice > > extents; + Drul_array< Array < Real > > offsets; + d = UP; + do + { + for (int i=0; i < clash_groups[d].size (); i++) + { + Slice s (Note_column::head_positions_interval (clash_groups[d][i])); + s[LEFT] --; + s[RIGHT]++; + extents[d].push (s); + offsets[d].push (d * 0.5 * i); } - } while ((d *= -1) != 1); - - - Interval_t y_extent[4]; - Note_column * col_l_a[4]; - Real x_off [4]; - int y_off[4]; - bool rest_b_a[4]; - - for (int j =0 ; j < 4; j++) { - if (clash_group_arr_a[j].size()) - col_l_a[j] = clash_group_arr_a[j][0]; - else - col_l_a[j] = 0; - - if (col_l_a[j]) { - y_extent[j] = col_l_a[j]->head_positions_interval(); + } + while ((flip (&d))!= UP); + + do + { + for (int i=1; i < clash_groups[d].size (); i++) + { + Slice prev =extents[d][i-1]; + prev.intersect (extents[d][i]); + if (prev.length ()> 0 || + (extents[-d].size () && d * (extents[d][i][-d] - extents[-d][0][d]) < 0)) + for (int j = i; j < clash_groups[d].size (); j++) + offsets[d][j] += d * 0.5; } + } + while ((flip (&d))!= UP); + + /* + if the up and down version are close, and can not be merged, move + all of them again. */ + if (extents[UP].size () && extents[DOWN].size ()) + { + Grob *cu_l =clash_groups[UP][0]; + Grob *cd_l =clash_groups[DOWN][0]; + + + /* + TODO. + */ + Grob * nu_l= Note_column::first_head (cu_l); + Grob * nd_l = Note_column::first_head (cd_l); + + int downpos = Note_column::head_positions_interval (cd_l)[BIGGER]; + int uppos = Note_column::head_positions_interval (cu_l)[SMALLER]; + + bool merge = + downpos == uppos + && Rhythmic_head::balltype_i (nu_l) == Rhythmic_head::balltype_i (nd_l); + - rest_b_a[j] = (col_l_a[j]) ? col_l_a[j]->rest_b_ : false; - x_off [j] = 0.0; - y_off[j] = 0; + if (!to_boolean (me->get_grob_property ("merge-differently-dotted"))) + merge = merge && Rhythmic_head::dot_count (nu_l) == Rhythmic_head::dot_count (nd_l); + + /* + notes are close, but can not be merged. Shift + */ + if (abs (uppos - downpos) < 2 && !merge) + do + { + for (int i=0; i < clash_groups[d].size (); i++) + { + offsets[d][i] -= d * 0.5; + } + } + while ((flip (&d))!= UP); } - - do { - x_off[idx(d, true)] = d*0.5; - } while ((d *= -1) != 1); - - do { - int i1 = idx(d, false); - int i2 = idx(d,true); - if (!intersection(y_extent[i1] , - y_extent[i2]).empty_b()) { - if (rest_b_a[i1]) { - y_off[i1] = -y_extent[i1][-d] + y_extent[1][d] + d*4; // ugh - y_extent[i1] += y_off[i1]; - } - } - } while ((d *= -1) != 1); - - do { - int i1 = idx(d, false); - int i2 = idx(-d,false); - - if (d*(y_extent[i1][-d] - y_extent[i2][d] )< 0&& rest_b_a[i1]) { - y_off[i1] = -y_extent[i1][-d] + y_extent[i2][d] +d* 4; // ugh - y_extent[i1] += y_off[i1]; - } - } while ((d *= -1) != 1); - - Interval_t middle( y_extent[0].min(), y_extent[3].max()); - Interval_t open_middle( y_extent[3].max()+1, y_extent[0].min()-1); - do{ - if (!open_middle.contains_b(y_extent[idx(d,true)])) - x_off[idx(d, true)] = d *1.0 ; - } while ((d *= -1) != 1); - - if (!middle.empty_b() && - middle.length() <= 1 && col_l_a[idx(1,0)] && col_l_a[idx(-1,0)] - && !rest_b_a[idx(1,0)] && !rest_b_a[idx(-1,0)]) { - - Notehead * nu_l= col_l_a[idx(1,0)]->head_l_arr_[idx(1,0)]; - Notehead * nd_l = col_l_a[idx(-1,0)]->head_l_arr_[idx(1,0)]; - if (! (nu_l->balltype == nd_l->balltype && nu_l->dots == nd_l->dots)) { - x_off[idx(1,0)] -= 0.5; - x_off[1] -= 0.5; - x_off[2] += 0.5; - x_off[idx(-1,0)] += 0.5; + + do + { + for (int i=0; i < clash_groups[d].size (); i++) + tups = gh_cons (gh_cons (clash_groups[d][i]->self_scm (), gh_double2scm (offsets[d][i])), + tups); + } + while (flip (&d) != UP); + return tups; +} + + +SCM +Collision::forced_shift (Grob *me) +{ + SCM tups = SCM_EOL; + + SCM s = me->get_grob_property ("elements"); + for (; gh_pair_p (s); s = gh_cdr (s)) + { + Grob * se = unsmob_grob (gh_car (s)); + + SCM force = se->remove_grob_property ("force-hshift"); + if (gh_number_p (force)) + { + tups = gh_cons (gh_cons (se->self_scm (), force), + tups); } - } - Real inter_f = paper()->internote(); - Real wid_f = paper()->note_width(); - for (int j=0; j < 4; j++) { - if (col_l_a[j]) - col_l_a[j]->translate(Offset(x_off[j] * wid_f, - y_off[j] * inter_f)); - } + return tups; +} + +void +Collision::add_column (Grob*me,Grob* ncol_l) +{ + ncol_l->add_offset_callback (Collision::force_shift_callback_proc, X_AXIS); + Axis_group_interface::add_element (me, ncol_l); + me->add_dependency (ncol_l); } -IMPLEMENT_STATIC_NAME(Collision);