+ for (vsize i = 0; i < ascs.size (); i++)
+ {
+ int parity = 1;
+ for (vsize j = 0; j < ascs[i].size ();)
+ {
+ Accidental_placement_entry *a = 0;
+ if (parity)
+ {
+ a = ascs[i].back ();
+ ascs[i].pop_back ();
+ }
+ else
+ a = ascs[i][j++];
+
+ apes->push_back (a);
+ parity = !parity;
+ }
+ }
+
+ reverse (*apes);
+}
+
+static vector<Accidental_placement_entry *>
+build_apes (SCM accs)
+{
+ vector<Accidental_placement_entry *> apes;
+ for (SCM s = accs; scm_is_pair (s); s = scm_cdr (s))
+ {
+ Accidental_placement_entry *ape = new Accidental_placement_entry;
+
+ for (SCM t = scm_cdar (s); scm_is_pair (t); t = scm_cdr (t))
+ ape->grobs_.push_back (unsmob<Grob> (scm_car (t)));
+
+ apes.push_back (ape);
+ }
+
+ return apes;
+}
+
+static void
+set_ape_skylines (Accidental_placement_entry *ape,
+ Grob **common, Real padding)
+{
+ vector<Grob *> accs (ape->grobs_);
+ vector_sort (accs, &acc_less);
+
+ /* We know that each accidental has the same note name and we assume that
+ accidentals in different octaves won't collide. If two or more
+ accidentals are in the same octave:
+ 1) if they are the same accidental, print them in overstrike
+ 2) otherwise, shift one to the left so they don't overlap. */
+ int last_octave = 0;
+ Real offset = 0;
+ Real last_offset = 0;
+ Rational last_alteration (0);
+ for (vsize i = accs.size (); i--;)
+ {
+ Grob *a = accs[i];
+ Pitch *p = accidental_pitch (a);
+
+ if (!p)
+ continue;
+
+ if (i == accs.size () - 1 || p->get_octave () != last_octave)
+ {
+ last_offset = 0;
+ offset = a->extent (a, X_AXIS)[LEFT] - padding;
+ }
+ else if (p->get_alteration () == last_alteration)
+ a->translate_axis (last_offset, X_AXIS);
+ else /* Our alteration is different from the last one */
+ {
+ Real this_offset = offset - a->extent (a, X_AXIS)[RIGHT];
+ a->translate_axis (this_offset, X_AXIS);
+
+ last_offset = this_offset;
+ offset -= a->extent (a, X_AXIS).length () + padding;
+ }
+
+ if (Skyline_pair *sky = unsmob<Skyline_pair> (a->get_property ("horizontal-skylines")))
+ {
+ Skyline_pair copy (*sky);
+ copy.raise (a->relative_coordinate (common[X_AXIS], X_AXIS));
+ copy.shift (a->relative_coordinate (common[Y_AXIS], Y_AXIS));
+ ape->horizontal_skylines_.merge (copy);
+ }
+
+ last_octave = p->get_octave ();
+ last_alteration = p->get_alteration ();
+ }
+}
+
+static vector<Grob *>
+extract_heads_and_stems (vector<Accidental_placement_entry *> const &apes)
+{
+ vector<Grob *> note_cols;
+ vector<Grob *> ret;
+
+ for (vsize i = apes.size (); i--;)
+ {
+ Accidental_placement_entry *ape = apes[i];
+ for (vsize j = ape->grobs_.size (); j--;)
+ {
+ Grob *acc = ape->grobs_[j];
+ Grob *head = acc->get_parent (Y_AXIS);
+ Grob *col = head->get_parent (X_AXIS);
+
+ if (has_interface<Note_column> (col))
+ note_cols.push_back (col);
+ else
+ ret.push_back (head);
+ }
+ }
+
+ /*
+ This is a little kludgy: in case there are note columns without
+ accidentals, we get them from the Note_collision objects.
+ */
+ for (vsize i = note_cols.size (); i--;)
+ {
+ Grob *c = note_cols[i]->get_parent (X_AXIS);
+ if (has_interface<Note_collision_interface> (c))
+ {
+ extract_grob_set (c, "elements", columns);
+ concat (note_cols, columns);
+ }
+ }
+
+ /* Now that we have all of the columns, grab all of the note-heads */
+ for (vsize i = note_cols.size (); i--;)
+ concat (ret, extract_grob_array (note_cols[i], "note-heads"));
+
+ /* Now that we have all of the heads, grab all of the stems */
+ for (vsize i = ret.size (); i--;)
+ if (Grob *s = Rhythmic_head::get_stem (ret[i]))
+ ret.push_back (s);
+
+ uniquify (ret);
+ return ret;
+}
+
+static Grob *
+common_refpoint_of_accidentals (vector<Accidental_placement_entry *> const &apes, Axis a)
+{
+ Grob *ret = 0;
+
+ for (vsize i = apes.size (); i--;)
+ for (vsize j = apes[i]->grobs_.size (); j--;)
+ {
+ if (!ret)
+ ret = apes[i]->grobs_[j];
+ else
+ ret = ret->common_refpoint (apes[i]->grobs_[j], a);
+ }
+
+ return ret;
+}
+
+static Skyline
+build_heads_skyline (vector<Grob *> const &heads_and_stems,
+ Grob **common)
+{
+ vector<Box> head_extents;
+ for (vsize i = heads_and_stems.size (); i--;)
+ head_extents.push_back (Box (heads_and_stems[i]->extent (common[X_AXIS], X_AXIS),
+ heads_and_stems[i]->pure_y_extent (common[Y_AXIS], 0, INT_MAX)));
+
+ return Skyline (head_extents, Y_AXIS, LEFT);
+}
+
+/*
+ Position the apes, starting from the right, so that they don't collide.
+ Return the total width.
+*/
+static Interval
+position_apes (Grob *me,
+ vector<Accidental_placement_entry *> const &apes,
+ Skyline const &heads_skyline)
+{
+ Real padding = robust_scm2double (me->get_property ("padding"), 0.2);
+ Skyline left_skyline = heads_skyline;
+ left_skyline.raise (-robust_scm2double (me->get_property ("right-padding"), 0));
+
+ /*
+ Add accs entries right-to-left.
+ */
+ Interval width;
+ Real last_offset = 0.0;
+ for (vsize i = apes.size (); i-- > 0;)