+Grob *
+System::get_vertical_alignment ()
+{
+ extract_grob_set (this, "elements", elts);
+ Grob *ret = 0;
+ for (vsize i = 0; i < elts.size (); i++)
+ if (Align_interface::has_interface (elts[i]))
+ {
+ if (ret)
+ programming_error ("found multiple vertical alignments in this system");
+ ret = elts[i];
+ }
+
+ if (!ret)
+ programming_error ("didn't find a vertical alignment in this system");
+ return ret;
+}
+
+// Finds the furthest staff in the given direction whose x-extent
+// overlaps with the given interval.
+Grob *
+System::get_extremal_staff (Direction dir, Interval const &iv)
+{
+ Grob *align = get_vertical_alignment ();
+ if (!align)
+ return 0;
+
+ extract_grob_set (align, "elements", elts);
+ vsize start = (dir == UP) ? 0 : elts.size () - 1;
+ vsize end = (dir == UP) ? elts.size () : VPOS;
+ for (vsize i = start; i != end; i += dir)
+ {
+ if (Hara_kiri_group_spanner::has_interface (elts[i]))
+ Hara_kiri_group_spanner::consider_suicide (elts[i]);
+
+ Interval intersection = elts[i]->extent (this, X_AXIS);
+ intersection.intersect (iv);
+ if (elts[i]->is_live () && !intersection.is_empty ())
+ return elts[i];
+ }
+ return 0;
+}
+
+Interval
+System::part_of_line_pure_height (vsize start, vsize end, bool begin)
+{
+ Grob *alignment = get_vertical_alignment ();
+ if (!alignment)
+ {
+ programming_error("system does not have a vertical alignment");
+ return Interval();
+ }
+ extract_grob_set (alignment, "elements", staves);
+ vector<Real> offsets = Align_interface::get_minimum_translations (alignment, staves, Y_AXIS, true, start, end);
+
+ Interval ret;
+ for (vsize i = 0; i < staves.size (); ++i)
+ {
+ Interval iv = begin?
+ Axis_group_interface::begin_of_line_pure_height (staves[i], start) :
+ Axis_group_interface::rest_of_line_pure_height (staves[i], start, end);
+ if (i<offsets.size())
+ iv.translate (offsets[i]);
+ ret.unite (iv);
+ }
+
+ extract_grob_set (this, "elements", elts);
+ for (vsize i = 0; i < elts.size (); ++i)
+ {
+ Grob *g = elts[i];
+ if (!dynamic_cast<Paper_column *> (g) && !Axis_group_interface::has_interface (g))
+ {
+ Interval iv = g->pure_height (this, start, end);
+ Item *it = dynamic_cast<Item*> (g);
+ Grob *col = it ? it->get_column () : 0;
+ bool item_at_beginning = col && (Paper_column::get_rank (col) == (int) start);
+
+ if (g->is_live () && begin == item_at_beginning)
+ ret.unite (iv);
+ }
+ }
+ return ret;
+}
+
+Interval
+System::begin_of_line_pure_height (vsize start, vsize end)
+{
+ return part_of_line_pure_height (start, end, true);
+}
+
+Interval
+System::rest_of_line_pure_height (vsize start, vsize end)
+{
+ return part_of_line_pure_height (start, end, false);
+}
+