an empty extent, delete it from the list instead. If the extent is
non-empty but there is no skyline available (or pure is true), just
create a flat skyline from the bounding box */
+// TODO(jneem): the pure and non-pure parts seem to share very little
+// code. Split them into 2 functions, perhaps?
static void
get_skylines (Grob *me,
vector<Grob*> *const elements,
{
Box b;
b[a] = extent;
- b[other_axis (a)] = Interval (-infinity_f, infinity_f);
+ b[other_axis (a)] = Interval (0, infinity_f);
skylines.insert (b, 0, other_axis (a));
}
+
+ // This is a hack to get better accuracy on the pure-height of VerticalAlignment.
+ // It's quite common for a treble clef to be the highest element of one system
+ // and for a low note (or lyrics) to be the lowest note on another. The two will
+ // never collide, but the pure-height stuff only works with bounding boxes, so it
+ // doesn't know that. The result is a significant over-estimation of the pure-height,
+ // especially on systems with many staves. To correct for this, we build a skyline
+ // in two parts: the part we did above contains most of the grobs (note-heads, etc.)
+ // while the bit we're about to do only contains the breakable grobs at the beginning
+ // of the system. This way, the tall treble clefs are only compared with the treble
+ // clefs of the other staff and they will be ignored if the staff above is, for example,
+ // lyrics.
+ if (Axis_group_interface::has_interface (g))
+ {
+ Interval begin_of_line_extent = Axis_group_interface::begin_of_line_pure_height (g, start);
+ if (!begin_of_line_extent.is_empty ())
+ {
+ Box b;
+ b[a] = begin_of_line_extent;
+ b[other_axis (a)] = Interval (-infinity_f, -1);
+ skylines.insert (b, 0, other_axis (a));
+ }
+ }
}
if (skylines.is_empty ())
return r;
}
+Interval
+Axis_group_interface::cached_pure_height (Grob *me, int start, int end)
+{
+ SCM adjacent_pure_heights = me->get_property ("adjacent-pure-heights");
-/*
- FIXME: pure extent handling has a lot of ad-hoc caching.
- This should be done with grob property callbacks.
+ if (!scm_is_pair (adjacent_pure_heights)
+ || !scm_is_vector (scm_cdr (adjacent_pure_heights)))
+ return Interval (0, 0);
- --hwn
-*/
+ return combine_pure_heights (me, scm_cdr (adjacent_pure_heights), start, end);
+}
Interval
-Axis_group_interface::cached_pure_height (Grob *me, int start, int end)
+Axis_group_interface::begin_of_line_pure_height (Grob *me, int start)
+{
+ SCM adjacent_pure_heights = me->get_property ("adjacent-pure-heights");
+
+ if (!scm_is_pair (adjacent_pure_heights)
+ || !scm_is_vector (scm_car (adjacent_pure_heights)))
+ return Interval (0, 0);
+
+ return combine_pure_heights (me, scm_car (adjacent_pure_heights), start, start+1);
+}
+
+Interval
+Axis_group_interface::combine_pure_heights (Grob *me, SCM measure_extents, int start, int end)
{
Paper_score *ps = get_root_system (me)->paper_score ();
vector<vsize> breaks = ps->get_break_indices ();
vector<Grob*> cols = ps->get_columns ();
- SCM extents = me->get_property ("adjacent-pure-heights");
-
- if (!scm_is_vector (extents))
- return Interval (0, 0);
-
Interval ext;
for (vsize i = 0; i + 1 < breaks.size (); i++)
{
break;
if (r >= start)
- ext.unite (ly_scm2interval (scm_c_vector_ref (extents, i)));
+ ext.unite (ly_scm2interval (scm_c_vector_ref (measure_extents, i)));
}
return ext;
}
+// adjacent-pure-heights is a pair of vectors, each of which has one element
+// for every measure in the score. The first vector stores, for each measure,
+// the combined height of the elements that are present only when the bar
+// is at the beginning of a line. The second vector stores, for each measure,
+// the combined height of the elements that are present only when the bar
+// is not at the beginning of a line.
+
MAKE_SCHEME_CALLBACK (Axis_group_interface, adjacent_pure_heights, 1)
SCM
Axis_group_interface::adjacent_pure_heights (SCM smob)
vector<vsize> breaks = ps->get_break_indices ();
vector<Grob*> cols = ps->get_columns ();
- SCM ret = scm_c_make_vector (breaks.size () - 1, SCM_EOL);
+ SCM begin_line_heights = scm_c_make_vector (breaks.size () - 1, SCM_EOL);
+ SCM mid_line_heights = scm_c_make_vector (breaks.size () - 1, SCM_EOL);
+
vsize it_index = 0;
for (vsize i = 0; i + 1 < breaks.size (); i++)
{
int start = Paper_column::get_rank (cols[breaks[i]]);
int end = Paper_column::get_rank (cols[breaks[i+1]]);
- Interval iv;
+ Interval begin_line_iv;
+ Interval mid_line_iv;
for (vsize j = it_index; j < items.size (); j++)
{
&& !to_boolean (it->get_property ("cross-staff")))
{
Interval dims = items[j]->pure_height (common, start, end);
+ Interval &target_iv = it->pure_is_visible (start-1, end) ? mid_line_iv : begin_line_iv;
+
if (!dims.is_empty ())
- iv.unite (dims);
+ target_iv.unite (dims);
}
if (rank < end)
&& !to_boolean (spanners[j]->get_property ("cross-staff")))
{
Interval dims = spanners[j]->pure_height (common, start, end);
+
if (!dims.is_empty ())
- iv.unite (dims);
+ mid_line_iv.unite (dims);
}
}
- scm_vector_set_x (ret, scm_from_int (i), ly_interval2scm (iv));
+ scm_vector_set_x (begin_line_heights, scm_from_int (i), ly_interval2scm (begin_line_iv));
+ scm_vector_set_x (mid_line_heights, scm_from_int (i), ly_interval2scm (mid_line_iv));
}
- return ret;
+ return scm_cons (begin_line_heights, mid_line_heights);
}
Interval