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_property ("rest-collision"));
32 Done: destruct pointers, so we do the shift only once.
34 SCM elts = rc->get_elt_property ("elements");
35 rc->set_elt_property ("elements", SCM_EOL);
44 Rest_collision::add_column (Score_element*me,Note_column *p)
46 me->add_dependency (p);
47 Pointer_group_interface gi (me);
50 p->add_offset_callback (&Rest_collision::force_shift_callback, Y_AXIS);
51 p->set_elt_property ("rest-collision", me->self_scm_);
55 head_characteristic (Score_element * col)
57 Score_element * s = unsmob_element (col->get_elt_property ("rest"));
62 return gh_cons (s->get_elt_property ("duration-log"),
63 gh_int2scm (Rhythmic_head::dot_count (s)));
67 TODO: fixme, fucks up if called twice on the same set of rests.
70 Rest_collision::do_shift (Score_element *me, SCM elts)
73 ugh. -> score elt type
75 Link_array<Note_column> rests;
76 Link_array<Note_column> notes;
78 for (SCM s = elts; gh_pair_p (s); s = gh_cdr (s))
80 Score_element * e = unsmob_element (gh_car (s));
81 if (e && unsmob_element (e->get_elt_property ("rest")))
82 rests.push (dynamic_cast<Note_column*> (e));
84 notes.push (dynamic_cast<Note_column*> (e));
89 handle rest-rest and rest-note collisions
92 * decide not to print rest if too crowded?
94 * ignore rests under beams.
97 // no rests to collide
101 // no partners to collide with
102 if (rests.size() + notes.size () < 2)
103 return SCM_UNDEFINED;
105 // meisjes met meisjes
110 FIXME: col2rhythmic_head and rhythmic_head2mom sucks bigtime.
113 SCM characteristic = head_characteristic (rests[0]);
115 for (; i < rests.size (); i++)
117 if (!gh_equal_p (head_characteristic (rests[i]), characteristic))
122 If all durations are the same, we'll check if there are more
123 rests than maximum-rest-count.
124 Otherwise (different durations), we'll try to display them all
125 (urg: all 3 of them, currently).
128 SCM s = me->get_elt_property ("maximum-rest-count");
129 if (i == rests.size ()
130 && gh_number_p (s) && gh_scm2int (s) < rests.size ())
132 display_count = gh_scm2int (s);
133 for (; i > display_count; i--)
135 Score_element* r = unsmob_element (rests[i-1]->get_elt_property ("rest"));
138 rests[i-1]->suicide ();
142 display_count = rests.size ();
145 UGH. Should get dims from table. Should have minimum dist.
147 int dy = display_count > 2 ? 6 : 4;
148 if (display_count > 1)
150 rests[0]->translate_rests (dy);
151 rests[1]->translate_rests (-dy);
154 // meisjes met jongetjes
157 if (rests.size () > 1)
159 warning (_("too many colliding rests"));
161 if (notes.size () > 1)
163 warning (_("too many notes for rest collision"));
165 Note_column * rcol = rests[0];
167 // try to be opposite of noteheads.
168 Direction dir = - notes[0]->dir();
170 Interval restdim = rcol->rest_dim ();
171 if (restdim.empty_b ())
172 return SCM_UNDEFINED;
175 Real staff_space = me->paper_l()->get_var ("interline");
178 staff_space = rcol->rests[0]->staff_space ();
180 Real minimum_dist = gh_scm2double (me->get_elt_property ("minimum-distance")) * staff_space;
183 assumption: ref points are the same.
186 for (int i = 0; i < notes.size(); i++)
188 notedim.unite (notes[i]->extent (Y_AXIS));
191 Interval inter (notedim);
192 inter.intersect (restdim);
195 minimum_dist + dir * (notedim[dir] - restdim[-dir]) >? 0;
199 //int stafflines = 5; // rcol->rests[0]->line_count;
200 int stafflines = Staff_symbol_referencer::line_count (me);
202 stafflines = stafflines != 0 ? stafflines : 5;
204 // move discretely by half spaces.
205 int discrete_dist = int (ceil (dist / (0.5 *staff_space)));
207 // move by whole spaces inside the staff.
208 if (discrete_dist < stafflines+1)
209 discrete_dist = int (ceil (discrete_dist / 2.0)* 2.0);
211 rcol->translate_rests (dir * discrete_dist);
213 return SCM_UNDEFINED;
217 Rest_collision::set_interface (Score_element*me)
219 me->set_extent_callback (0, X_AXIS);
220 me->set_extent_callback (0, Y_AXIS);
221 me->set_elt_property ("elements", SCM_EOL);