2 rest-collision.cc -- implement Rest_collision
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
8 #include <math.h> // ceil.
11 #include "rest-collision.hh"
12 #include "note-column.hh"
14 #include "note-head.hh"
15 #include "paper-def.hh"
17 #include "group-interface.hh"
18 #include "staff-symbol-referencer.hh"
19 #include "duration.hh"
22 Rest_collision::force_shift_callback (Score_element const*them, Axis a)
26 Score_element * rc = unsmob_element (them->get_elt_pointer ("rest-collision"));
31 Done: destruct pointers, so we do the shift only once.
33 SCM elts = rc->get_elt_pointer ("elements");
34 rc->set_elt_pointer ("elements", SCM_EOL);
43 Rest_collision::add_column (Note_column *p)
45 elt_l_->add_dependency (p);
46 Pointer_group_interface gi (elt_l_);
49 p->add_offset_callback (&Rest_collision::force_shift_callback, Y_AXIS);
50 p->set_elt_pointer ("rest-collision", elt_l_->self_scm_);
54 these 3 have to go, because they're unnecessary complications.
57 to_duration (int type, int dots)
68 elt_l_ should be "duration" independent
71 rhythmic_head2mom (Rhythmic_head* r)
73 return to_duration (r->balltype_i (), r->dot_count ()).length_mom ();
80 col2rhythmic_head (Score_element* c)
82 return dynamic_cast<Rhythmic_head*> (unsmob_element (c->get_elt_pointer ("rest")));
87 TODO: fixme, fucks up if called twice on the same set of rests.
90 Rest_collision::do_shift (Score_element *me, SCM elts)
93 ugh. -> score elt type
95 Link_array<Note_column> rests;
96 Link_array<Note_column> notes;
98 for (SCM s = elts; gh_pair_p (s); s = gh_cdr (s))
100 Score_element * e = unsmob_element (gh_car (s));
101 if (e && unsmob_element (e->get_elt_pointer ("rest")))
102 rests.push (dynamic_cast<Note_column*> (e));
104 notes.push (dynamic_cast<Note_column*> (e));
109 handle rest-rest and rest-note collisions
112 * decide not to print rest if too crowded?
114 * ignore rests under beams.
117 // no rests to collide
119 return SCM_UNDEFINED;
121 // no partners to collide with
122 if (rests.size() + notes.size () < 2)
123 return SCM_UNDEFINED;
125 // meisjes met meisjes
128 Moment m = rhythmic_head2mom (col2rhythmic_head (rests[0]));
130 for (; i < rests.size (); i++)
132 Moment me = rhythmic_head2mom (col2rhythmic_head (rests[i]));
138 If all durations are the same, we'll check if there are more
139 rests than maximum-rest-count.
140 Otherwise (different durations), we'll try to display them all
141 (urg: all 3 of them, currently).
144 SCM s = me->get_elt_property ("maximum-rest-count");
145 if (i == rests.size ()
146 && gh_number_p (s) && gh_scm2int (s) < rests.size ())
148 display_count = gh_scm2int (s);
149 for (; i > display_count; i--)
150 col2rhythmic_head (rests[i-1])
151 ->set_elt_property ("molecule-callback", SCM_BOOL_T);
154 display_count = rests.size ();
157 UGH. Should get dims from table. Should have minimum dist.
159 int dy = display_count > 2 ? 6 : 4;
160 if (display_count > 1)
162 rests[0]->translate_rests (dy);
163 rests[1]->translate_rests (-dy);
166 // meisjes met jongetjes
169 if (rests.size () > 1)
171 warning (_("too many colliding rests"));
173 if (notes.size () > 1)
175 warning (_("too many notes for rest collision"));
177 Note_column * rcol = rests[0];
179 // try to be opposite of noteheads.
180 Direction dir = - notes[0]->dir();
182 Interval restdim = rcol->rest_dim ();
183 if (restdim.empty_b ())
184 return SCM_UNDEFINED;
187 Real staff_space = me->paper_l()->get_var ("interline");
190 staff_space = rcol->rests[0]->staff_space ();
192 Real minimum_dist = gh_scm2double (me->get_elt_property ("minimum-distance")) * staff_space;
195 assumption: ref points are the same.
198 for (int i = 0; i < notes.size(); i++)
200 notedim.unite (notes[i]->extent (Y_AXIS));
203 Interval inter (notedim);
204 inter.intersect (restdim);
207 minimum_dist + dir * (notedim[dir] - restdim[-dir]) >? 0;
211 //int stafflines = 5; // rcol->rests[0]->line_count;
212 int stafflines = Staff_symbol_referencer_interface (me).line_count ();
214 stafflines = stafflines != 0 ? stafflines : 5;
216 // move discretely by half spaces.
217 int discrete_dist = int (ceil (dist / (0.5 *staff_space)));
219 // move by whole spaces inside the staff.
220 if (discrete_dist < stafflines+1)
221 discrete_dist = int (ceil (discrete_dist / 2.0)* 2.0);
223 rcol->translate_rests (dir * discrete_dist);
225 return SCM_UNDEFINED;
229 Rest_collision::set_interface ()
231 elt_l_->set_extent_callback (0, X_AXIS);
232 elt_l_->set_extent_callback (0, Y_AXIS);
233 elt_l_->set_elt_pointer ("elements", SCM_EOL);
236 Rest_collision::Rest_collision (Score_element* c)