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 Collision::add_column (Score_element
*me
,Note_column
* ncol_l
)
19 ncol_l
->add_offset_callback (force_shift_callback
, X_AXIS
);
20 Axis_group_interface::add_element (me
, ncol_l
);
21 me
->add_dependency (ncol_l
);
25 Collision::force_shift_callback (Score_element
* c
, Axis a
)
29 Score_element
* me
= c
->parent_l (a
);
31 ugh. the way DONE is done is not clean
33 if (!unsmob_element (me
->get_elt_property ("done")))
35 me
->set_elt_property ("done", me
->self_scm_
);
43 TODO: make callback of this.
46 Collision::do_shifts(Score_element
* me
)
48 SCM
autos (automatic_shift (me
));
49 SCM
hand (forced_shift (me
));
51 Link_array
<Score_element
> done
;
53 Real wid
= me
->paper_l ()->get_var ("collision_note_width"); // elt prop
54 for (; gh_pair_p (hand
); hand
=gh_cdr (hand
))
56 Score_element
* s
= unsmob_element (gh_caar (hand
));
57 Real amount
= gh_scm2double (gh_cdar (hand
));
59 s
->translate_axis (amount
*wid
, X_AXIS
);
62 for (; gh_pair_p (autos
); autos
=gh_cdr (autos
))
64 Score_element
* s
= unsmob_element (gh_caar (autos
));
65 Real amount
= gh_scm2double (gh_cdar (autos
));
68 s
->translate_axis (amount
* wid
, X_AXIS
);
72 /** This complicated routine moves note columns around horizontally to
73 ensure that notes don't clash.
75 This should be put into Scheme.
78 Collision::automatic_shift (Score_element
*me
)
80 Drul_array
<Link_array
<Note_column
> > clash_groups
;
81 Drul_array
<Array
<int> > shifts
;
84 SCM s
= me
->get_elt_property ("elements");
85 for (; gh_pair_p (s
); s
= gh_cdr (s
))
89 Score_element
* se
= unsmob_element (car
);
90 if (Note_column
* col
= dynamic_cast<Note_column
*> (se
))
91 clash_groups
[col
->dir ()].push (col
);
98 Array
<int> & shift (shifts
[d
]);
99 Link_array
<Note_column
> & clashes (clash_groups
[d
]);
101 clashes
.sort (Note_column::shift_compare
);
103 for (int i
=0; i
< clashes
.size (); i
++)
106 = clashes
[i
]->get_elt_property ("horizontal-shift");
108 if (gh_number_p (sh
))
109 shift
.push (gh_scm2int (sh
));
114 for (int i
=1; i
< shift
.size (); i
++)
116 if (shift
[i
-1] == shift
[i
])
118 warning (_ ("Too many clashing notecolumns. Ignoring them."));
123 while ((flip (&d
))!= UP
);
125 Drul_array
< Array
< Slice
> > extents
;
126 Drul_array
< Array
< Real
> > offsets
;
130 for (int i
=0; i
< clash_groups
[d
].size (); i
++)
132 Slice
s(Note_column::head_positions_interval (clash_groups
[d
][i
]));
136 offsets
[d
].push (d
* 0.5 * i
);
139 while ((flip (&d
))!= UP
);
143 for (int i
=1; i
< clash_groups
[d
].size (); i
++)
145 Slice prev
=extents
[d
][i
-1];
146 prev
.intersect (extents
[d
][i
]);
147 if (prev
.length ()> 0 ||
148 (extents
[-d
].size () && d
* (extents
[d
][i
][-d
] - extents
[-d
][0][d
]) < 0))
149 for (int j
= i
; j
< clash_groups
[d
].size (); j
++)
150 offsets
[d
][j
] += d
* 0.5;
153 while ((flip (&d
))!= UP
);
156 if the up and down version are close, and can not be merged, move
157 all of them again. */
158 if (extents
[UP
].size () && extents
[DOWN
].size ())
160 Note_column
*cu_l
=clash_groups
[UP
][0];
161 Note_column
*cd_l
=clash_groups
[DOWN
][0];
167 Score_element
* nu_l
= cu_l
->first_head();
168 Score_element
* nd_l
= cd_l
->first_head();
170 int downpos
= Note_column::head_positions_interval (cd_l
)[BIGGER
];
171 int uppos
= Note_column::head_positions_interval (cu_l
)[SMALLER
];
175 && Rhythmic_head::balltype_i (nu_l
) == Rhythmic_head::balltype_i (nd_l
);
178 if (!to_boolean (me
->get_elt_property ("merge-differently-dotted")))
179 merge
= merge
&& Rhythmic_head::dot_count (nu_l
) == Rhythmic_head::dot_count (nd_l
);
182 notes are close, but can not be merged. Shift
184 if (abs(uppos
- downpos
) < 2 && !merge
)
187 for (int i
=0; i
< clash_groups
[d
].size (); i
++)
189 offsets
[d
][i
] -= d
* 0.5;
192 while ((flip (&d
))!= UP
);
197 for (int i
=0; i
< clash_groups
[d
].size (); i
++)
198 tups
= gh_cons (gh_cons (clash_groups
[d
][i
]->self_scm_
, gh_double2scm (offsets
[d
][i
])),
201 while (flip (&d
) != UP
);
207 Collision::forced_shift (Score_element
*me
)
211 SCM s
= me
->get_elt_property ("elements");
212 for (; gh_pair_p (s
); s
= gh_cdr (s
))
214 Score_element
* se
= unsmob_element (gh_car (s
));
216 SCM force
= se
->remove_elt_property ("force-hshift");
217 if (gh_number_p (force
))
219 tups
= gh_cons (gh_cons (se
->self_scm_
, force
),