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>
9 #include <math.h> // ceil.
12 #include "rest-collision.hh"
13 #include "note-column.hh"
15 #include "rhythmic-head.hh"
16 #include "paper-def.hh"
18 #include "group-interface.hh"
19 #include "staff-symbol-referencer.hh"
20 #include "duration.hh"
23 Rest_collision::force_shift_callback (Score_element *them, Axis a)
27 Score_element * rc = unsmob_element (them->get_elt_pointer ("rest-collision"));
32 Done: destruct pointers, so we do the shift only once.
34 SCM elts = rc->get_elt_pointer ("elements");
35 rc->set_elt_pointer ("elements", SCM_EOL);
44 Rest_collision::add_column (Note_column *p)
46 elt_l_->add_dependency (p);
47 Pointer_group_interface gi (elt_l_);
50 p->add_offset_callback (&Rest_collision::force_shift_callback, Y_AXIS);
51 p->set_elt_pointer ("rest-collision", elt_l_->self_scm_);
55 these 3 have to go, because they're unnecessary complications.
58 to_duration (int type, int dots)
69 elt_l_ should be "duration" independent
72 rhythmic_head2mom (Rhythmic_head* r)
74 return to_duration (r->balltype_i (), r->dot_count ()).length_mom ();
81 col2rhythmic_head (Score_element* c)
83 return dynamic_cast<Rhythmic_head*> (unsmob_element (c->get_elt_pointer ("rest")));
88 TODO: fixme, fucks up if called twice on the same set of rests.
91 Rest_collision::do_shift (Score_element *me, SCM elts)
94 ugh. -> score elt type
96 Link_array<Note_column> rests;
97 Link_array<Note_column> notes;
99 for (SCM s = elts; gh_pair_p (s); s = gh_cdr (s))
101 Score_element * e = unsmob_element (gh_car (s));
102 if (e && unsmob_element (e->get_elt_pointer ("rest")))
103 rests.push (dynamic_cast<Note_column*> (e));
105 notes.push (dynamic_cast<Note_column*> (e));
110 handle rest-rest and rest-note collisions
113 * decide not to print rest if too crowded?
115 * ignore rests under beams.
118 // no rests to collide
120 return SCM_UNDEFINED;
122 // no partners to collide with
123 if (rests.size() + notes.size () < 2)
124 return SCM_UNDEFINED;
126 // meisjes met meisjes
129 Moment m = rhythmic_head2mom (col2rhythmic_head (rests[0]));
131 for (; i < rests.size (); i++)
133 Moment me = rhythmic_head2mom (col2rhythmic_head (rests[i]));
139 If all durations are the same, we'll check if there are more
140 rests than maximum-rest-count.
141 Otherwise (different durations), we'll try to display them all
142 (urg: all 3 of them, currently).
145 SCM s = me->get_elt_property ("maximum-rest-count");
146 if (i == rests.size ()
147 && gh_number_p (s) && gh_scm2int (s) < rests.size ())
149 display_count = gh_scm2int (s);
150 for (; i > display_count; i--)
151 col2rhythmic_head (rests[i-1])
152 ->set_elt_property ("molecule-callback", SCM_BOOL_T);
155 display_count = rests.size ();
158 UGH. Should get dims from table. Should have minimum dist.
160 int dy = display_count > 2 ? 6 : 4;
161 if (display_count > 1)
163 rests[0]->translate_rests (dy);
164 rests[1]->translate_rests (-dy);
167 // meisjes met jongetjes
170 if (rests.size () > 1)
172 warning (_("too many colliding rests"));
174 if (notes.size () > 1)
176 warning (_("too many notes for rest collision"));
178 Note_column * rcol = rests[0];
180 // try to be opposite of noteheads.
181 Direction dir = - notes[0]->dir();
183 Interval restdim = rcol->rest_dim ();
184 if (restdim.empty_b ())
185 return SCM_UNDEFINED;
188 Real staff_space = me->paper_l()->get_var ("interline");
191 staff_space = rcol->rests[0]->staff_space ();
193 Real minimum_dist = gh_scm2double (me->get_elt_property ("minimum-distance")) * staff_space;
196 assumption: ref points are the same.
199 for (int i = 0; i < notes.size(); i++)
201 notedim.unite (notes[i]->extent (Y_AXIS));
204 Interval inter (notedim);
205 inter.intersect (restdim);
208 minimum_dist + dir * (notedim[dir] - restdim[-dir]) >? 0;
212 //int stafflines = 5; // rcol->rests[0]->line_count;
213 int stafflines = Staff_symbol_referencer_interface (me).line_count ();
215 stafflines = stafflines != 0 ? stafflines : 5;
217 // move discretely by half spaces.
218 int discrete_dist = int (ceil (dist / (0.5 *staff_space)));
220 // move by whole spaces inside the staff.
221 if (discrete_dist < stafflines+1)
222 discrete_dist = int (ceil (discrete_dist / 2.0)* 2.0);
224 rcol->translate_rests (dir * discrete_dist);
226 return SCM_UNDEFINED;
230 Rest_collision::set_interface ()
232 elt_l_->set_extent_callback (0, X_AXIS);
233 elt_l_->set_extent_callback (0, Y_AXIS);
234 elt_l_->set_elt_pointer ("elements", SCM_EOL);
237 Rest_collision::Rest_collision (Score_element* c)