- /*
- handle rest-rest and rest-note collisions
-
- [todo]
- decide not to print rest if too crowded?
- */
-
- // no rests to collide
- if (!rest_l_arr_.size())
- return;
-
- // no partners to collide with
- if (rest_l_arr_.size() + ncol_l_arr_.size() < 2 )
- return;
-
- // meisjes met meisjes
- if (!ncol_l_arr_.size()) {
- int dy = rest_l_arr_.size() > 2 ? 6 : 4;
-
- rest_l_arr_[0]->translate_heads(rest_l_arr_[0]->dir_i_ *dy);
- // top is last element...
- rest_l_arr_.top()->translate_heads(rest_l_arr_.top()->dir_i_* dy);
+ Grob *me = unsmob_grob (smob);
+
+ me->set_property ("positioning-done", SCM_BOOL_T);
+
+ extract_grob_set (me, "elements", elts);
+
+ vector<Grob*> rests;
+ vector<Grob*> notes;
+
+ for (vsize i = 0; i < elts.size (); i++)
+ {
+ Grob *e = elts[i];
+ if (unsmob_grob (e->get_object ("rest")))
+ rests.push_back (e);
+ else
+ notes.push_back (e);
+ }
+
+ /*
+ handle rest-rest and rest-note collisions
+
+ [todo]
+ * decide not to print rest if too crowded?
+ */
+
+ /*
+ no partners to collide with
+ */
+ if (rests.size () + notes.size () < 2)
+ return SCM_BOOL_T;
+
+ Real staff_space = Staff_symbol_referencer::staff_space (me);
+ /*
+ only rests
+ */
+ if (!notes.size ())
+ {
+
+ /*
+ This is incomplete: in case of an uneven number of rests, the
+ center one should be centered on the staff.
+ */
+ Drul_array<vector<Grob*> > ordered_rests;
+ for (vsize i = 0; i < rests.size (); i++)
+ {
+ Grob *r = Note_column::get_rest (rests[i]);
+
+ Direction d = get_grob_direction (r);
+ if (d)
+ ordered_rests[d].push_back (rests[i]);
+ else
+ rests[d]->warning (_ ("cannot resolve rest collision: rest direction not set"));
+ }
+
+ Direction d = LEFT;
+ do
+ vector_sort (ordered_rests[d], Note_column::shift_less);
+ while (flip (&d) != LEFT)
+ ;
+
+ do
+ {
+ if (ordered_rests[d].size () < 1)
+ {
+ if (ordered_rests[-d].size () > 1)
+ ordered_rests[-d][0]->warning (_ ("too many colliding rests"));
+
+ return SCM_BOOL_T;
+ }
+ }
+ while (flip (&d) != LEFT);
+
+ Grob *common = common_refpoint_of_array (ordered_rests[DOWN], me, Y_AXIS);
+ common = common_refpoint_of_array (ordered_rests[UP], common, Y_AXIS);
+
+ Real diff
+ = (ordered_rests[DOWN].back ()->extent (common, Y_AXIS)[UP]
+ - ordered_rests[UP].back ()->extent (common, Y_AXIS)[DOWN]) / staff_space;
+
+ if (diff > 0)
+ {
+ int amount_down = (int) ceil (diff / 2);
+ diff -= amount_down;
+ Note_column::translate_rests (ordered_rests[DOWN].back (),
+ -2 * amount_down);
+ if (diff > 0)
+ Note_column::translate_rests (ordered_rests[UP].back (),
+ 2 * int (ceil (diff)));
+ }
+
+ do
+ {
+ for (vsize i = ordered_rests[d].size () -1; i-- > 0;)
+ {
+ Real last_y = ordered_rests[d][i + 1]->extent (common, Y_AXIS)[d];
+ Real y = ordered_rests[d][i]->extent (common, Y_AXIS)[-d];
+
+ Real diff = d * ((last_y - y) / staff_space);
+ if (diff > 0)
+ Note_column::translate_rests (ordered_rests[d][i], d * (int) ceil (diff) * 2);
+ }
+ }
+ while (flip (&d) != LEFT);