2 collision.cc -- implement Collision
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
9 #include "collision.hh"
10 #include "note-column.hh"
11 #include "rhythmic-head.hh"
12 #include "paper-def.hh"
13 #include "axis-group-interface.hh"
17 MAKE_SCHEME_CALLBACK(Collision,force_shift_callback,2);
19 Collision::force_shift_callback (SCM element_smob, SCM axis)
21 Score_element *me = unsmob_element (element_smob);
22 Axis a = (Axis) gh_scm2int (axis);
25 me = me->parent_l (a);
27 ugh. the way DONE is done is not clean
29 if (!unsmob_element (me->get_elt_property ("done")))
31 me->set_elt_property ("done", me->self_scm ());
35 return gh_double2scm (0.0);
39 TODO: make callback of this.
42 Collision::do_shifts(Score_element* me)
44 SCM autos (automatic_shift (me));
45 SCM hand (forced_shift (me));
47 Link_array<Score_element> done;
50 = gh_scm2double (me->get_elt_property ("note-width"))
51 * me->paper_l ()->get_var ("staffspace");
53 for (; gh_pair_p (hand); hand =gh_cdr (hand))
55 Score_element * s = unsmob_element (gh_caar (hand));
56 Real amount = gh_scm2double (gh_cdar (hand));
58 s->translate_axis (amount *wid, X_AXIS);
61 for (; gh_pair_p (autos); autos =gh_cdr (autos))
63 Score_element * s = unsmob_element (gh_caar (autos));
64 Real amount = gh_scm2double (gh_cdar (autos));
67 s->translate_axis (amount * wid, X_AXIS);
71 /** This complicated routine moves note columns around horizontally to
72 ensure that notes don't clash.
74 This should be put into Scheme.
77 Collision::automatic_shift (Score_element *me)
79 Drul_array<Link_array<Score_element> > clash_groups;
80 Drul_array<Array<int> > shifts;
83 SCM s = me->get_elt_property ("elements");
84 for (; gh_pair_p (s); s = gh_cdr (s))
88 Score_element * se = unsmob_element (car);
89 if (Note_column::has_interface (se))
90 clash_groups[Note_column::dir (se)].push (se);
97 Array<int> & shift (shifts[d]);
98 Link_array<Score_element> & clashes (clash_groups[d]);
100 clashes.sort (Note_column::shift_compare);
102 for (int i=0; i < clashes.size (); i++)
105 = clashes[i]->get_elt_property ("horizontal-shift");
107 if (gh_number_p (sh))
108 shift.push (gh_scm2int (sh));
113 for (int i=1; i < shift.size (); i++)
115 if (shift[i-1] == shift[i])
117 warning (_ ("Too many clashing notecolumns. Ignoring them."));
122 while ((flip (&d))!= UP);
124 Drul_array< Array < Slice > > extents;
125 Drul_array< Array < Real > > offsets;
129 for (int i=0; i < clash_groups[d].size (); i++)
131 Slice s(Note_column::head_positions_interval (clash_groups[d][i]));
135 offsets[d].push (d * 0.5 * i);
138 while ((flip (&d))!= UP);
142 for (int i=1; i < clash_groups[d].size (); i++)
144 Slice prev =extents[d][i-1];
145 prev.intersect (extents[d][i]);
146 if (prev.length ()> 0 ||
147 (extents[-d].size () && d * (extents[d][i][-d] - extents[-d][0][d]) < 0))
148 for (int j = i; j < clash_groups[d].size (); j++)
149 offsets[d][j] += d * 0.5;
152 while ((flip (&d))!= UP);
155 if the up and down version are close, and can not be merged, move
156 all of them again. */
157 if (extents[UP].size () && extents[DOWN].size ())
159 Score_element *cu_l =clash_groups[UP][0];
160 Score_element *cd_l =clash_groups[DOWN][0];
166 Score_element * nu_l= Note_column::first_head(cu_l);
167 Score_element * nd_l = Note_column::first_head(cd_l);
169 int downpos = Note_column::head_positions_interval (cd_l)[BIGGER];
170 int uppos = Note_column::head_positions_interval (cu_l)[SMALLER];
174 && Rhythmic_head::balltype_i (nu_l) == Rhythmic_head::balltype_i (nd_l);
177 if (!to_boolean (me->get_elt_property ("merge-differently-dotted")))
178 merge = merge && Rhythmic_head::dot_count (nu_l) == Rhythmic_head::dot_count (nd_l);
181 notes are close, but can not be merged. Shift
183 if (abs(uppos - downpos) < 2 && !merge)
186 for (int i=0; i < clash_groups[d].size (); i++)
188 offsets[d][i] -= d * 0.5;
191 while ((flip (&d))!= UP);
196 for (int i=0; i < clash_groups[d].size (); i++)
197 tups = gh_cons (gh_cons (clash_groups[d][i]->self_scm (), gh_double2scm (offsets[d][i])),
200 while (flip (&d) != UP);
206 Collision::forced_shift (Score_element *me)
210 SCM s = me->get_elt_property ("elements");
211 for (; gh_pair_p (s); s = gh_cdr (s))
213 Score_element * se = unsmob_element (gh_car (s));
215 SCM force = se->remove_elt_property ("force-hshift");
216 if (gh_number_p (force))
218 tups = gh_cons (gh_cons (se->self_scm (), force),
229 Collision::add_column (Score_element*me,Score_element* ncol_l)
231 ncol_l->add_offset_callback (Collision::force_shift_callback_proc, X_AXIS);
232 Axis_group_interface::add_element (me, ncol_l);
233 me->add_dependency (ncol_l);