From 920dccaf627f00ec2d5bbd49ffeb9ad01236da3b Mon Sep 17 00:00:00 2001 From: Joe Neeman Date: Fri, 9 Jun 2006 02:20:21 +0000 Subject: [PATCH] * scm/paper-system.scm (paper-system-annotate): also annotate the estimated pure-Y-extent * scm/define-grobs.scm: add pure-Y-extent and pure-Y-offset functions * lily/system.cc (break_into_pieces): set the estimated height of each child system * lily/stem.cc (pure_height): new pure-Y-extent callback * lily/staff-symbol-referencer.cc (callback): don't destroy the staff-position property * lily/hara-kiri-group-spanner.cc (request_suicide): split consider_suicide into two functions * lily/constrained-breaking.cc (resize): use the new pure callbacks to estimate the height of a system * lily/axis-group-interface.cc (pure_group_height): new side-effect-free VerticalAxisGroup height-callback * lily/align-interface.cc (get_extents_aligned_translates): split align_elements_to_extents into two functions (get_pure_child_y_translation): new function * lily/grob.cc: new functions for pure-Y-extent and pure-Y-offset * lily/item.cc: new functions pure_is_visible and spanned_rank_iv * lily/paper-score.cc: cache break_indices and columns * lily/side-position-interface.cc: new pure-Y-extent callbacks --- ChangeLog | 36 ++++++ lily/align-interface.cc | 73 ++++++++++-- lily/axis-group-interface.cc | 152 +++++++++++++++++++++++- lily/constrained-breaking.cc | 17 ++- lily/grob.cc | 71 ++++++++++- lily/hara-kiri-group-spanner.cc | 87 ++++++++++++-- lily/include/align-interface.hh | 6 + lily/include/axis-group-interface.hh | 7 ++ lily/include/constrained-breaking.hh | 4 +- lily/include/grob.hh | 6 + lily/include/hara-kiri-group-spanner.hh | 2 + lily/include/item.hh | 2 + lily/include/paper-score.hh | 5 + lily/include/side-position-interface.hh | 6 +- lily/include/spanner.hh | 3 +- lily/include/stem.hh | 1 + lily/item.cc | 27 ++++- lily/paper-score.cc | 18 +++ lily/side-position-interface.cc | 44 ++++--- lily/staff-symbol-referencer.cc | 1 - lily/stem.cc | 22 ++++ lily/system.cc | 8 +- scm/define-grob-properties.scm | 5 + scm/define-grobs.scm | 69 ++++++++++- scm/paper-system.scm | 16 ++- 25 files changed, 629 insertions(+), 59 deletions(-) diff --git a/ChangeLog b/ChangeLog index aee68cfa88..fd266fe1fe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,39 @@ +2006-06-08 Joe Neeman + + * scm/paper-system.scm (paper-system-annotate): also annotate the + estimated pure-Y-extent + + * scm/define-grobs.scm: add pure-Y-extent and pure-Y-offset functions + + * lily/system.cc (break_into_pieces): set the estimated height + of each child system + + * lily/stem.cc (pure_height): new pure-Y-extent callback + + * lily/staff-symbol-referencer.cc (callback): don't destroy + the staff-position property + + * lily/hara-kiri-group-spanner.cc (request_suicide): split + consider_suicide into two functions + + * lily/constrained-breaking.cc (resize): use the new pure + callbacks to estimate the height of a system + + * lily/axis-group-interface.cc (pure_group_height): new + side-effect-free VerticalAxisGroup height-callback + + * lily/align-interface.cc (get_extents_aligned_translates): + split align_elements_to_extents into two functions + (get_pure_child_y_translation): new function + + * lily/grob.cc: new functions for pure-Y-extent and pure-Y-offset + + * lily/item.cc: new functions pure_is_visible and spanned_rank_iv + + * lily/paper-score.cc: cache break_indices and columns + + * lily/side-position-interface.cc: new pure-Y-extent callbacks + 2006-06-08 Han-Wen Nienhuys * lily/font-config.cc (init_fontconfig): do the init if diff --git a/lily/align-interface.cc b/lily/align-interface.cc index c315e4ec32..410344dae2 100644 --- a/lily/align-interface.cc +++ b/lily/align-interface.cc @@ -14,6 +14,7 @@ #include "hara-kiri-group-spanner.hh" #include "grob-array.hh" #include "international.hh" +#include "warn.hh" /* TODO: for vertical spacing, should also include a rod & spring @@ -145,8 +146,11 @@ Align_interface::align_to_fixed_distance (Grob *me, Axis a) align_to_fixed_distance (). */ -void -Align_interface::align_elements_to_extents (Grob *me, Axis a) +vector +Align_interface::get_extents_aligned_translates (Grob *me, + vector const &all_grobs, + Axis a, + bool pure, int start, int end) { Spanner *me_spanner = dynamic_cast (me); @@ -156,7 +160,7 @@ Align_interface::align_elements_to_extents (Grob *me, Axis a) { line_break_details = me_spanner->get_bound (LEFT)->get_property ("line-break-system-details"); - if (!me->get_system ()) + if (!me->get_system () && !pure) me->warning (_ ("vertical alignment called before line-breaking.\n" "Only do cross-staff spanners with PianoStaff.")); @@ -171,10 +175,9 @@ Align_interface::align_elements_to_extents (Grob *me, Axis a) vector dims; vector elems; - extract_grob_set (me, "elements", all_grobs); for (vsize i = 0; i < all_grobs.size (); i++) { - Interval y = all_grobs[i]->extent (me, a); + Interval y = all_grobs[i]->maybe_pure_extent (all_grobs[i], a, pure, start, end); if (!y.is_empty ()) { Grob *e = dynamic_cast (all_grobs[i]); @@ -245,24 +248,68 @@ Align_interface::align_elements_to_extents (Grob *me, Axis a) if (translates.size ()) { Real w = translates[0]; + + if (scm_is_number (align)) + center_offset = total.linear_combination (scm_to_double (align)); + for (vsize i = 0, j = 0; j < all_grobs.size (); j++) { if (i < elems.size () && all_grobs[j] == elems[i]) w = translates[i++]; - all_translates.push_back (w); + all_translates.push_back (w - center_offset); } + } + return all_translates; +} - /* - FIXME: uncommenting freaks out the Y-alignment of - line-of-score. - */ - if (scm_is_number (align)) - center_offset = total.linear_combination (scm_to_double (align)); +void +Align_interface::align_elements_to_extents (Grob *me, Axis a) +{ + extract_grob_set (me, "elements", all_grobs); + vector translates = get_extents_aligned_translates (me, all_grobs, a, false, 0, 0); + if (translates.size ()) for (vsize j = 0; j < all_grobs.size (); j++) - all_grobs[j]->translate_axis (all_translates[j] - center_offset, a); + all_grobs[j]->translate_axis (translates[j], a); +} + +Real +Align_interface::get_pure_child_y_translation (Grob *me, Grob *ch, int start, int end) +{ + extract_grob_set (me, "elements", all_grobs); + SCM dy_scm = me->get_property ("forced-distance"); + + if (scm_is_number (dy_scm)) + { + Real dy = scm_to_double (dy_scm) * robust_scm2dir (me->get_property ("stacking-dir"), DOWN); + Real pos = 0; + for (vsize i = 0; i < all_grobs.size (); i++) + { + if (all_grobs[i] == ch) + return pos; + if (!Hara_kiri_group_spanner::has_interface (all_grobs[i]) + || !Hara_kiri_group_spanner::request_suicide (all_grobs[i], start, end)) + pos += dy; + } } + else + { + vector translates = get_extents_aligned_translates (me, all_grobs, Y_AXIS, true, start, end); + + if (translates.size ()) + { + for (vsize i = 0; i < all_grobs.size (); i++) + if (all_grobs[i] == ch) + return translates[i]; + } + else + return 0; + } + + programming_error (_ ("tried to get a translation for something that isn't my child")); + return 0; } + Axis Align_interface::axis (Grob *me) { diff --git a/lily/axis-group-interface.cc b/lily/axis-group-interface.cc index d590813abf..1d509f04d1 100644 --- a/lily/axis-group-interface.cc +++ b/lily/axis-group-interface.cc @@ -8,9 +8,16 @@ #include "axis-group-interface.hh" +#include "align-interface.hh" #include "pointer-group-interface.hh" #include "grob.hh" +#include "grob-array.hh" #include "hara-kiri-group-spanner.hh" +#include "international.hh" +#include "item.hh" +#include "paper-column.hh" +#include "paper-score.hh" +#include "system.hh" #include "warn.hh" void @@ -61,6 +68,89 @@ Axis_group_interface::relative_group_extent (vector const &elts, return r; } +Interval +Axis_group_interface::cached_pure_height (Grob *me, + vector const &elts, + Grob *common, + int start, int end) +{ + Paper_score *ps = get_root_system (me)->paper_score (); + vector breaks = ps->get_break_indices (); + vector cols = ps->get_columns (); + vsize start_index = VPOS; + vsize end_index = VPOS; + + for (vsize i = 0; i < breaks.size (); i++) + { + int r = Paper_column::get_rank (cols[breaks[i]]); + if (start == r) + start_index = i; + if (end == r) + end_index = i; + } + + if (start_index == VPOS || end_index == VPOS) + { + programming_error (_ ("tried to calculate pure-height at a non-breakpoint")); + return Interval (0, 0); + } + + SCM extents = me->get_property ("cached-pure-extents"); + if (!scm_is_vector (extents)) + { + extents = scm_c_make_vector (breaks.size () - 1, SCM_EOL); + for (vsize i = 0; i < breaks.size () - 1; i++) + { + int st = Paper_column::get_rank (cols[breaks[i]]); + int ed = Paper_column::get_rank (cols[breaks[i+1]]); + Interval iv = relative_pure_height (me, elts, common, st, ed, false); + scm_vector_set_x (extents, scm_from_int (i), ly_interval2scm (iv)); + } + me->set_property ("cached-pure-extents", extents); + } + + Interval ext (0, 0); + for (vsize i = start_index; i < end_index; i++) + ext.unite (ly_scm2interval (scm_c_vector_ref (extents, i))); + return ext; +} + +Interval +Axis_group_interface::relative_pure_height (Grob *me, + vector const &elts, + Grob *common, + int start, int end, + bool use_cache) +{ + /* It saves a _lot_ of time if we assume a VerticalAxisGroup is additive + (ie. height (i, k) = height (i, j) + height (j, k) for all i <= j <= k). + Unfortunately, it isn't always true, particularly if there is a + VerticalAlignment somewhere in the descendants. + + Apart from PianoStaff, which has a fixed VerticalAlignment so it doesn't + count, the only VerticalAlignment comes from Score. This makes it + reasonably safe to assume that if our parent is a VerticalAlignment, + we can assume additivity and cache things nicely. */ + Grob *p = me->get_parent (Y_AXIS); + if (use_cache && p && Align_interface::has_interface (p)) + return Axis_group_interface::cached_pure_height (me, elts, common, start, end); + + Interval r; + + for (vsize i = 0; i < elts.size (); i++) + { + Interval_t rank_span = elts[i]->spanned_rank_iv (); + Item *it = dynamic_cast (elts[i]); + if (rank_span[LEFT] <= end && rank_span[RIGHT] >= start && (!it || it->pure_is_visible (start, end))) + { + Interval dims = elts[i]->pure_height (common, start, end); + if (!dims.is_empty ()) + r.unite (dims); + } + } + return r; +} + MAKE_SCHEME_CALLBACK (Axis_group_interface, width, 1); SCM Axis_group_interface::width (SCM smob) @@ -76,6 +166,17 @@ Axis_group_interface::height (SCM smob) Grob *me = unsmob_grob (smob); return generic_group_extent (me, Y_AXIS); } + +MAKE_SCHEME_CALLBACK (Axis_group_interface, pure_height, 3); +SCM +Axis_group_interface::pure_height (SCM smob, SCM start_scm, SCM end_scm) +{ + int start = robust_scm2int (start_scm, 0); + int end = robust_scm2int (end_scm, INT_MAX); + Grob *me = unsmob_grob (smob); + + return pure_group_height (me, start, end); +} SCM Axis_group_interface::generic_group_extent (Grob *me, Axis a) @@ -89,6 +190,51 @@ Axis_group_interface::generic_group_extent (Grob *me, Axis a) return ly_interval2scm (r - my_coord); } +SCM +Axis_group_interface::pure_group_height (Grob *me, int start, int end) +{ + Grob *common = unsmob_grob (me->get_object ("common-refpoint-of-elements")); + + if (!common) + { + extract_grob_set (me, "elements", elts); + + vector relevant_elts; + SCM is_relevant = ly_lily_module_constant ("pure-relevant"); + + for (vsize i = 0; i < elts.size (); i++) + { + if (to_boolean (scm_apply_1 (is_relevant, elts[i]->self_scm (), SCM_EOL))) + relevant_elts.push_back (elts[i]); + + Item *it = dynamic_cast (elts[i]); + Direction d = LEFT; + if (it) + do + { + Item *piece = it->find_prebroken_piece (d); + if (piece && to_boolean (scm_apply_1 (is_relevant, piece->self_scm (), SCM_EOL))) + relevant_elts.push_back (piece); + } + while (flip (&d) != LEFT); + } + + common = common_refpoint_of_array (relevant_elts, me, Y_AXIS); + me->set_object ("common-refpoint-of-elements", common->self_scm ()); + + SCM ga_scm = Grob_array::make_array (); + Grob_array *ga = unsmob_grob_array (ga_scm); + ga->set_array (relevant_elts); + me->set_object ("pure-relevant-elements", ga_scm); + } + + extract_grob_set (me, "pure-relevant-elements", elts); + Real my_coord = me->relative_coordinate (common, Y_AXIS); + Interval r (relative_pure_height (me, elts, common, start, end, true)); + + return ly_interval2scm (r - my_coord); +} + void Axis_group_interface::get_children (Grob *me, vector *found) { @@ -111,4 +257,8 @@ ADD_INTERFACE (Axis_group_interface, "axis-group-interface", /* properties */ "axes " - "elements "); + "elements " + "common-refpoint-of-elements " + "pure-relevant-elements " + "cached-pure-extents " + ); diff --git a/lily/constrained-breaking.cc b/lily/constrained-breaking.cc index 3996856cbd..c9753b1a0a 100644 --- a/lily/constrained-breaking.cc +++ b/lily/constrained-breaking.cc @@ -147,9 +147,9 @@ Constrained_breaking::resize (vsize systems) if (!breaks_.size () && pscore_) { Output_def *l = pscore_->layout (); - Real extent = scm_to_double (l->c_variable ("system-height")); - Real padding = scm_to_double (l->c_variable ("between-system-padding")); - Real space = scm_to_double (l->c_variable ("between-system-space")); + System *sys = pscore_->root_system (); + Real padding = robust_scm2double (l->c_variable ("between-system-padding"), 0); + Real space = robust_scm2double (l->c_variable ("ideal-system-space"), 0); bool ragged_right = to_boolean (pscore_->layout ()->c_variable ("ragged-right")); bool ragged_last = to_boolean (pscore_->layout ()->c_variable ("ragged-last")); @@ -167,8 +167,12 @@ Constrained_breaking::resize (vsize systems) ragged_right); for (vsize i = 0; i < breaks_.size () - 1; i++) { + Real max_ext = 0; for (vsize j = i + 1; j < breaks_.size (); j++) { + int start = Paper_column::get_rank (all_[breaks_[i]]); + int end = Paper_column::get_rank (all_[breaks_[j]]); + Interval extent = sys->pure_height (sys, start, end); bool last = j == breaks_.size () - 1; bool ragged = ragged_right || (last && ragged_last); int k = i*lines_rank_ + j; @@ -176,11 +180,12 @@ Constrained_breaking::resize (vsize systems) if (scm_is_number (pen)) lines_[k].break_penalty_ = scm_to_double (pen); + max_ext = max (max_ext, extent.length ()); lines_[k].force_ = forces[k]; - lines_[k].extent_ = extent; + lines_[k].extent_ = extent.length (); lines_[k].padding_ = padding; lines_[k].space_ = space; - lines_[k].inverse_hooke_ = 3; // FIXME: somewhat arbitrary + lines_[k].inverse_hooke_ = 1; if (ragged && lines_[k].force_ < 0) lines_[k].force_ = infinity_f; if (isinf (lines_[k].force_)) @@ -335,6 +340,6 @@ Constrained_breaking::Constrained_breaking (vector const &start) Real Constrained_breaking::combine_demerits (Real force, Real prev_force) { - return force * force + fabs (prev_force - force); + return force * force + (prev_force - force) * (prev_force - force); } diff --git a/lily/grob.cc b/lily/grob.cc index 15eb1f9212..f79b266b08 100644 --- a/lily/grob.cc +++ b/lily/grob.cc @@ -10,6 +10,7 @@ #include +#include "align-interface.hh" #include "input-smob.hh" #include "international.hh" #include "item.hh" @@ -278,6 +279,37 @@ Grob::relative_coordinate (Grob const *refp, Axis a) const return off; } +Real +Grob::pure_relative_y_coordinate (Grob const *refp, int start, int end) +{ + if (refp == this) + return 0.0; + + SCM pure_off = ly_lily_module_constant ("pure-Y-offset"); + Real off = 0; + + if (dim_cache_[Y_AXIS].offset_) + off = *dim_cache_[Y_AXIS].offset_; + else if (ly_is_procedure (pure_off)) + { + dim_cache_[Y_AXIS].offset_ = new Real (0.0); + off = scm_to_double (scm_apply_3 (pure_off, self_scm (), + scm_from_int (start), scm_from_int (end), + SCM_EOL)); + delete dim_cache_[Y_AXIS].offset_; + dim_cache_[Y_AXIS].offset_ = 0; + } + + /* we simulate positioning-done if we are the child of a VerticalAlignment */ + Grob *p = get_parent (Y_AXIS); + Real trans = 0; + if (Align_interface::has_interface (p)) + trans = Align_interface::get_pure_child_y_translation (p, this, start, end); + + return off + trans + + dim_cache_[Y_AXIS].parent_->pure_relative_y_coordinate (refp, start, end); +} + /* Invoke callbacks to get offset relative to parent. */ Real Grob::get_offset (Axis a) const @@ -305,6 +337,14 @@ Grob::get_offset (Axis a) const return 0.0; } +Real +Grob::maybe_pure_coordinate (Grob const *refp, Axis a, bool pure, int start, int end) +{ + if (pure && a != Y_AXIS) + programming_error ("tried to get pure X-offset"); + return (pure && a == Y_AXIS) ? pure_relative_y_coordinate (refp, start, end) + : relative_coordinate (refp, a); +} /**************************************************************** extents @@ -358,7 +398,6 @@ Grob::extent (Grob *refp, Axis a) const SCM min_ext = internal_get_property (min_ext_sym); if (is_number_pair (min_ext)) real_ext.unite (ly_scm2interval (min_ext)); - ((Grob*)this)->del_property (ext_sym); ((Grob*)this)->dim_cache_[a].extent_ = new Interval (real_ext); } @@ -367,6 +406,36 @@ Grob::extent (Grob *refp, Axis a) const return real_ext; } +Interval +Grob::pure_height (Grob *refp, int start, int end) +{ + SCM pure_height = ly_lily_module_constant ("pure-Y-extent"); + Interval iv (0, 0); + + if (ly_is_procedure (pure_height)) + iv = ly_scm2interval (scm_apply_3 (pure_height, self_scm (), + scm_from_int (start), scm_from_int (end), + SCM_EOL)); + Real offset = pure_relative_y_coordinate (refp, start, end); + + iv.translate (offset); + return iv; +} + +Interval +Grob::maybe_pure_extent (Grob *refp, Axis a, bool pure, int start, int end) +{ + if (pure && a != Y_AXIS) + programming_error ("tried to get pure width"); + return (pure && a == Y_AXIS) ? pure_height (refp, start, end) : extent (refp, a); +} + +Interval_t +Grob::spanned_rank_iv () +{ + return Interval_t (INT_MIN, INT_MAX); +} + /**************************************************************** REFPOINTS ****************************************************************/ diff --git a/lily/hara-kiri-group-spanner.cc b/lily/hara-kiri-group-spanner.cc index 981639c237..4c9cc03963 100644 --- a/lily/hara-kiri-group-spanner.cc +++ b/lily/hara-kiri-group-spanner.cc @@ -25,22 +25,84 @@ Hara_kiri_group_spanner::y_extent (SCM smob) return Axis_group_interface::generic_group_extent (me, Y_AXIS); } -void -Hara_kiri_group_spanner::consider_suicide (Grob *me) +MAKE_SCHEME_CALLBACK (Hara_kiri_group_spanner, pure_height, 3); +SCM +Hara_kiri_group_spanner::pure_height (SCM smob, SCM start_scm, SCM end_scm) { - Spanner *sp = dynamic_cast (me); - if (!to_boolean (me->get_property ("remove-empty"))) - return ; + Grob *me = unsmob_grob (smob); + int start = robust_scm2int (start_scm, 0); + int end = robust_scm2int (end_scm, INT_MAX); - extract_grob_set (me, "items-worth-living", worth); - if (worth.size ()) - return; + if (request_suicide (me, start, end)) + return ly_interval2scm (Interval ()); + return Axis_group_interface::pure_group_height (me, start, end); +} + +/* there is probably a way that doesn't involve re-implementing a binary + search (I would love some proper closures right now) */ +bool find_in_range (SCM vector, int low, int hi, int min, int max) +{ + if (low >= hi) + return false; + + int mid = low + (hi - low) / 2; + int val = scm_to_int (scm_c_vector_ref (vector, mid)); + if (val >= min && val <= max) + return true; + else if (val < min) + return find_in_range (vector, mid+1, hi, min, max); + return find_in_range (vector, low, mid, min, max); +} + +bool +Hara_kiri_group_spanner::request_suicide (Grob *me, int start, int end) +{ + if (!to_boolean (me->get_property ("remove-empty"))) + return false; bool remove_first = to_boolean (me->get_property ("remove-first")); - if (!remove_first - && ((sp->original () && broken_spanner_index (sp) == 0) - || Paper_column::get_rank (sp->get_bound (LEFT)->get_column ()) - == 0)) + if (!remove_first && start <= 0) + return false; + + SCM important = me->get_property ("important-column-ranks"); + if (scm_is_vector (important)) + { + int len = scm_c_vector_length (important); + if (find_in_range (important, 0, len, start, end)) + return false; + } + else /* build the important-columns-cache */ + { + extract_grob_set (me, "items-worth-living", worth); + vector ranks; + + for (vsize i = 0; i < worth.size (); i++) + { + Item *it = dynamic_cast (worth[i]); + if (it) + ranks.push_back (Paper_column::get_rank (it->get_column ())); + } + vector_sort (ranks, default_compare); + uniq (ranks); + + SCM scm_vec = scm_c_make_vector (ranks.size (), SCM_EOL); + for (vsize i = 0; i < ranks.size (); i++) + scm_vector_set_x (scm_vec, scm_from_int (i), scm_from_int (ranks[i])); + me->set_property ("important-column-ranks", scm_vec); + + return request_suicide (me, start, end); + } + + return true; +} + +void +Hara_kiri_group_spanner::consider_suicide (Grob *me) +{ + Spanner *sp = dynamic_cast (me); + int left = sp->get_bound (LEFT)->get_column ()->get_rank (); + int right = sp->get_bound (RIGHT)->get_column ()->get_rank (); + if (!request_suicide (me, left, right)) return; vector childs; @@ -99,6 +161,7 @@ ADD_INTERFACE (Hara_kiri_group_spanner, "hara-kiri-group-interface", /* properties */ "items-worth-living " + "important-column-ranks " "remove-empty " "remove-first " ); diff --git a/lily/include/align-interface.hh b/lily/include/align-interface.hh index b01c744bff..273dbc660c 100644 --- a/lily/include/align-interface.hh +++ b/lily/include/align-interface.hh @@ -11,6 +11,7 @@ #include "lily-proto.hh" #include "lily-guile.hh" +#include "std-vector.hh" struct Align_interface { @@ -18,12 +19,17 @@ struct Align_interface DECLARE_SCHEME_CALLBACK (stretch_after_break, (SCM element)); static void align_to_fixed_distance (Grob *, Axis a); static void align_elements_to_extents (Grob *, Axis a); + static vector get_extents_aligned_translates (Grob *, vector const&, + Axis a, + bool safe, int start, int end); static void set_ordered (Grob *); static Axis axis (Grob *); static void add_element (Grob *, Grob *); static int get_count (Grob *, Grob *); static bool has_interface (Grob *); + + static Real get_pure_child_y_translation (Grob *, Grob *child, int start, int end); }; Grob *find_fixed_alignment_parent (Grob *g); diff --git a/lily/include/axis-group-interface.hh b/lily/include/axis-group-interface.hh index 94e1a256d9..767271ad34 100644 --- a/lily/include/axis-group-interface.hh +++ b/lily/include/axis-group-interface.hh @@ -18,10 +18,17 @@ struct Axis_group_interface { static SCM generic_group_extent (Grob *me, Axis a); + static SCM pure_group_height (Grob *me, int start, int end); DECLARE_SCHEME_CALLBACK (width, (SCM smob)); DECLARE_SCHEME_CALLBACK (height, (SCM smob)); + DECLARE_SCHEME_CALLBACK (pure_height, (SCM smob, SCM start, SCM end)); static Interval relative_group_extent (vector const &list, Grob *common, Axis); + static Interval relative_pure_height (Grob *me, vector const &list, + Grob *common, int start, int end, + bool use_cache); + static Interval cached_pure_height (Grob *me, vector const &list, + Grob *common, int, int); static void add_element (Grob *me, Grob *); static void set_axes (Grob *, Axis, Axis); diff --git a/lily/include/constrained-breaking.hh b/lily/include/constrained-breaking.hh index 8f2a4de2ef..ca662e854e 100644 --- a/lily/include/constrained-breaking.hh +++ b/lily/include/constrained-breaking.hh @@ -17,7 +17,8 @@ struct Line_details { Real force_; Real extent_; /* Y-extent of the system */ Real padding_; /* compulsory space after this system (if we're not last on a page) */ - Real space_; /* spring length (stretches over extent_ but not over padding_) */ + Real bottom_padding_; + Real space_; /* spring length */ Real inverse_hooke_; SCM break_permission_; @@ -32,6 +33,7 @@ struct Line_details { force_ = infinity_f; extent_ = 0; padding_ = 0; + bottom_padding_ = 0; space_ = 0; inverse_hooke_ = 1; break_permission_ = ly_symbol2scm ("allow"); diff --git a/lily/include/grob.hh b/lily/include/grob.hh index 6c3ef612bd..e2bc0157cc 100644 --- a/lily/include/grob.hh +++ b/lily/include/grob.hh @@ -109,16 +109,22 @@ public: /* offsets */ void translate_axis (Real, Axis); Real relative_coordinate (Grob const *refp, Axis) const; + Real pure_relative_y_coordinate (Grob const *refp, int start, int end); + Real maybe_pure_coordinate (Grob const *refp, Axis a, bool pure, int start, int end); /* extents */ Interval extent (Grob *refpoint, Axis) const; void flush_extent_cache (Axis); + Interval pure_height (Grob *refpoint, int start_col, int end_col); + Interval maybe_pure_extent (Grob *refpoint, Axis, bool pure, int start, int end); /* refpoints */ Grob *common_refpoint (Grob const *s, Axis a) const; void set_parent (Grob *e, Axis); Grob *get_parent (Axis a) const; void fixup_refpoint (); + + virtual Interval_t spanned_rank_iv (); }; /* smob utilities */ diff --git a/lily/include/hara-kiri-group-spanner.hh b/lily/include/hara-kiri-group-spanner.hh index 9533216be8..0112b0864f 100644 --- a/lily/include/hara-kiri-group-spanner.hh +++ b/lily/include/hara-kiri-group-spanner.hh @@ -17,9 +17,11 @@ class Hara_kiri_group_spanner public: DECLARE_SCHEME_CALLBACK (force_hara_kiri_callback, (SCM)); DECLARE_SCHEME_CALLBACK (y_extent, (SCM smob)); + DECLARE_SCHEME_CALLBACK (pure_height, (SCM smob, SCM start, SCM end)); DECLARE_SCHEME_CALLBACK (force_hara_kiri_in_y_parent_callback, (SCM)); DECLARE_SCHEME_CALLBACK (after_line_breaking, (SCM)); static bool has_interface (Grob *); + static bool request_suicide (Grob *me, int start, int end); static void consider_suicide (Grob *me); static void add_interesting_item (Grob *me, Grob *n); }; diff --git a/lily/include/item.hh b/lily/include/item.hh index 9d1f2e73f6..7c28a35240 100644 --- a/lily/include/item.hh +++ b/lily/include/item.hh @@ -30,6 +30,7 @@ public: static bool is_non_musical (Grob *); bool is_broken () const; + bool pure_is_visible (int start, int end) const; Direction break_status_dir () const; @@ -38,6 +39,7 @@ public: virtual System *get_system () const; virtual Paper_column *get_column () const; virtual void handle_prebroken_dependencies (); + virtual Interval_t spanned_rank_iv (); static bool has_interface (Grob *); protected: virtual void discretionary_processing (); diff --git a/lily/include/paper-score.hh b/lily/include/paper-score.hh index c165b9aacd..7f79aeb548 100644 --- a/lily/include/paper-score.hh +++ b/lily/include/paper-score.hh @@ -19,6 +19,9 @@ class Paper_score : public Music_output System *system_; SCM systems_; SCM paper_systems_; + + mutable vector cols_; + mutable vector break_indices_; public: Paper_score (Output_def *); @@ -30,6 +33,8 @@ public: void typeset_system (System *); vector calc_breaking (); vector find_break_indices () const; + vector get_break_indices () const; + vector get_columns () const; SCM get_paper_systems (); protected: virtual void process (); diff --git a/lily/include/side-position-interface.hh b/lily/include/side-position-interface.hh index 6c6e483066..ea7655fa62 100644 --- a/lily/include/side-position-interface.hh +++ b/lily/include/side-position-interface.hh @@ -22,12 +22,14 @@ struct Side_position_interface public: DECLARE_SCHEME_CALLBACK (y_aligned_on_support_refpoints, (SCM element)); + DECLARE_SCHEME_CALLBACK (pure_y_aligned_on_support_refpoints, (SCM element, SCM start, SCM end)); DECLARE_SCHEME_CALLBACK (x_aligned_side, (SCM element)); DECLARE_SCHEME_CALLBACK (y_aligned_side, (SCM element)); + DECLARE_SCHEME_CALLBACK (pure_y_aligned_side, (SCM element, SCM start, SCM end)); - static SCM aligned_side (Grob*me, Axis a); + static SCM aligned_side (Grob*me, Axis a, bool pure, int start, int end); - static SCM general_side_position (Grob *, Axis, bool); + static SCM general_side_position (Grob *, Axis, bool, bool pure, int start, int end); static Axis get_axis (Grob *); static void set_axis (Grob *, Axis); static bool has_interface (Grob *); diff --git a/lily/include/spanner.hh b/lily/include/spanner.hh index c64c61d636..074c303036 100644 --- a/lily/include/spanner.hh +++ b/lily/include/spanner.hh @@ -45,8 +45,7 @@ public: void substitute_one_mutable_property (SCM sym, SCM val); bool fast_substitute_grob_array (SCM sym, Grob_array *); - // TODO: make virtual and do this for Items as well. - Interval_t spanned_rank_iv (); + virtual Interval_t spanned_rank_iv (); void set_bound (Direction d, Grob *); Item *get_bound (Direction d) const; diff --git a/lily/include/stem.hh b/lily/include/stem.hh index da024edb35..3d06bca6f6 100644 --- a/lily/include/stem.hh +++ b/lily/include/stem.hh @@ -50,6 +50,7 @@ public: DECLARE_SCHEME_CALLBACK (calc_stem_info, (SCM)); DECLARE_SCHEME_CALLBACK (calc_positioning_done, (SCM)); DECLARE_SCHEME_CALLBACK (width, (SCM smob)); + DECLARE_SCHEME_CALLBACK (pure_height, (SCM, SCM, SCM)); DECLARE_SCHEME_CALLBACK (height, (SCM)); }; #endif diff --git a/lily/item.cc b/lily/item.cc index f4760eb2fd..ff00630b5f 100644 --- a/lily/item.cc +++ b/lily/item.cc @@ -8,6 +8,7 @@ #include "item.hh" +#include "axis-group-interface.hh" #include "paper-score.hh" #include "warn.hh" #include "paper-column.hh" @@ -149,13 +150,37 @@ Item::handle_prebroken_dependencies () SCM vis = get_property ("break-visibility"); if (scm_is_vector (vis)) { - bool visible = to_boolean (scm_vector_ref (vis, scm_from_int (break_status_dir () + 1))); + bool visible = to_boolean (scm_c_vector_ref (vis, break_status_dir () + 1)); if (!visible) suicide (); } } +bool +Item::pure_is_visible (int start, int end) const +{ + SCM vis = get_property ("break-visibility"); + if (scm_is_vector (vis)) + { + int pos = 1; + int pc_rank = Paper_column::get_rank (get_column ()); + if (pc_rank == start) + pos = 2; + else if (pc_rank == end) + pos = 0; + return to_boolean (scm_vector_ref (vis, scm_from_int (pos))); + } + return true; +} + +Interval_t +Item::spanned_rank_iv () +{ + int c = get_column ()->get_rank (); + return Interval_t (c, c); +} + void Item::derived_mark () const { diff --git a/lily/paper-score.cc b/lily/paper-score.cc index 8dfbc38939..ffad13c38b 100644 --- a/lily/paper-score.cc +++ b/lily/paper-score.cc @@ -75,9 +75,27 @@ Paper_score::find_break_indices () const retval.push_back (i); } + cols_ = all; + break_indices_ = retval; + return retval; } +vector +Paper_score::get_break_indices () const +{ + if (break_indices_.empty ()) + find_break_indices (); + return break_indices_; +} + +vector +Paper_score::get_columns () const +{ + if (cols_.empty ()) + find_break_indices (); + return cols_; +} vector Paper_score::calc_breaking () diff --git a/lily/side-position-interface.cc b/lily/side-position-interface.cc index 4964c47572..52e9ba5221 100644 --- a/lily/side-position-interface.cc +++ b/lily/side-position-interface.cc @@ -48,7 +48,8 @@ Side_position_interface::get_direction (Grob *me) /* Put the element next to the support, optionally taking in account the extent of the support. */ SCM -Side_position_interface::general_side_position (Grob *me, Axis a, bool use_extents) +Side_position_interface::general_side_position (Grob *me, Axis a, bool use_extents, + bool pure, int start, int end) { Real ss = Staff_symbol_referencer::staff_space (me); @@ -67,7 +68,7 @@ Side_position_interface::general_side_position (Grob *me, Axis a, bool use_exten if (include_staff) { common = staff_symbol->common_refpoint (common, Y_AXIS); - staff_extents = staff_symbol->extent (common, Y_AXIS); + staff_extents = staff_symbol->maybe_pure_extent (common, Y_AXIS, pure, start, end); if (include_staff) dim.unite (staff_extents); @@ -78,10 +79,10 @@ Side_position_interface::general_side_position (Grob *me, Axis a, bool use_exten Grob *e = support[i]; if (e) if (use_extents) - dim.unite (e->extent (common, a)); + dim.unite (e->maybe_pure_extent (common, a, pure, start, end)); else { - Real x = e->relative_coordinate (common, a); + Real x = e->maybe_pure_coordinate (common, a, pure, start, end); dim.unite (Interval (x, x)); } } @@ -91,7 +92,7 @@ Side_position_interface::general_side_position (Grob *me, Axis a, bool use_exten Direction dir = get_grob_direction (me); - Real off = me->get_parent (a)->relative_coordinate (common, a); + Real off = me->get_parent (a)->maybe_pure_coordinate (common, a, pure, start, end); Real minimum_space = ss * robust_scm2double (me->get_property ("minimum-space"), -1); Real total_off = dim.linear_combination (dir) - off; @@ -118,13 +119,19 @@ Side_position_interface::general_side_position (Grob *me, Axis a, bool use_exten MAKE_SCHEME_CALLBACK (Side_position_interface, y_aligned_on_support_refpoints, 1); - SCM Side_position_interface::y_aligned_on_support_refpoints (SCM smob) { - return general_side_position (unsmob_grob (smob), Y_AXIS, false); + return general_side_position (unsmob_grob (smob), Y_AXIS, false, false, 0, 0); } +MAKE_SCHEME_CALLBACK (Side_position_interface, pure_y_aligned_on_support_refpoints, 3); +SCM +Side_position_interface::pure_y_aligned_on_support_refpoints (SCM smob, SCM start, SCM end) +{ + return general_side_position (unsmob_grob (smob), Y_AXIS, false, + true, scm_to_int (start), scm_to_int (end)); +} /* @@ -135,23 +142,30 @@ MAKE_SCHEME_CALLBACK (Side_position_interface, x_aligned_side, 1); SCM Side_position_interface::x_aligned_side (SCM smob) { - return aligned_side (unsmob_grob (smob), X_AXIS); + return aligned_side (unsmob_grob (smob), X_AXIS, false, 0, 0); } MAKE_SCHEME_CALLBACK (Side_position_interface, y_aligned_side, 1); SCM Side_position_interface::y_aligned_side (SCM smob) { - return aligned_side (unsmob_grob (smob), Y_AXIS); + return aligned_side (unsmob_grob (smob), Y_AXIS, false, 0, 0); +} + +MAKE_SCHEME_CALLBACK (Side_position_interface, pure_y_aligned_side, 3); +SCM +Side_position_interface::pure_y_aligned_side (SCM smob, SCM start, SCM end) +{ + return aligned_side (unsmob_grob (smob), Y_AXIS, true, scm_to_int (start), scm_to_int (end)); } SCM -Side_position_interface::aligned_side (Grob *me, Axis a) +Side_position_interface::aligned_side (Grob *me, Axis a, bool pure, int start, int end) { Direction dir = get_grob_direction (me); - Real o = scm_to_double (general_side_position (me, a, true)); - Interval iv = me->extent (me, a); + Real o = scm_to_double (general_side_position (me, a, true, pure, start, end)); + Interval iv = me->maybe_pure_extent (me, a, pure, start, end); if (!iv.is_empty ()) { @@ -174,8 +188,8 @@ Side_position_interface::aligned_side (Grob *me, Axis a) if (to_boolean (me->get_property ("quantize-position"))) { Grob *common = me->common_refpoint (staff, Y_AXIS); - Real my_off = me->relative_coordinate (common, Y_AXIS); - Real staff_off = staff->relative_coordinate (common, Y_AXIS); + Real my_off = me->get_parent (Y_AXIS)->maybe_pure_coordinate (common, Y_AXIS, pure, start, end); + Real staff_off = staff->maybe_pure_coordinate (common, Y_AXIS, pure, start, end); Real ss = Staff_symbol::staff_space (staff); Real position = 2 * (my_off + o - staff_off) / ss; Real rounded = directed_round (position, dir); @@ -198,7 +212,7 @@ Side_position_interface::aligned_side (Grob *me, Axis a) Grob *common = me->common_refpoint (staff, Y_AXIS); - Interval staff_size = staff->extent (common, Y_AXIS); + Interval staff_size = staff->maybe_pure_extent (common, Y_AXIS, pure, start, end); Real diff = dir*staff_size[dir] + padding - dir * (o + iv[-dir]); o += dir * max (diff, 0.0); } diff --git a/lily/staff-symbol-referencer.cc b/lily/staff-symbol-referencer.cc index cfde343029..87e83fadad 100644 --- a/lily/staff-symbol-referencer.cc +++ b/lily/staff-symbol-referencer.cc @@ -110,7 +110,6 @@ Staff_symbol_referencer::callback (SCM smob) { Real space = Staff_symbol_referencer::staff_space (me); off = scm_to_double (pos) * space / 2.0; - me->set_property ("staff-position", scm_from_int (0)); } return scm_from_double (off); diff --git a/lily/stem.cc b/lily/stem.cc index a25c37f777..05fc5e7417 100644 --- a/lily/stem.cc +++ b/lily/stem.cc @@ -225,6 +225,28 @@ Stem::is_invisible (Grob *me) && scm_to_int (me->get_property ("duration-log")) >= 1); } +MAKE_SCHEME_CALLBACK (Stem, pure_height, 3) +SCM +Stem::pure_height (SCM smob, SCM start, SCM end) +{ + Grob *me = unsmob_grob (smob); + Real ss = Staff_symbol_referencer::staff_space (me); + Real len = scm_to_double (calc_length (smob)) * ss / 2; + Direction dir = get_grob_direction (me); + + Interval iv; + Interval hp = head_positions (me); + if (dir == UP) + iv = Interval (0, len); + else + iv = Interval (-len, 0); + + if (!hp.is_empty ()) + iv.translate (hp[dir] * ss / 2); + + return ly_interval2scm (iv); +} + MAKE_SCHEME_CALLBACK (Stem, calc_stem_end_position, 1) SCM Stem::calc_stem_end_position (SCM smob) diff --git a/lily/system.cc b/lily/system.cc index dda8fdf132..a8a0ff5160 100644 --- a/lily/system.cc +++ b/lily/system.cc @@ -23,7 +23,6 @@ #include "staff-symbol-referencer.hh" #include "tweak-registration.hh" #include "warn.hh" -#include "warn.hh" System::System (System const &src, int count) : Spanner (src, count) @@ -185,6 +184,7 @@ System::get_paper_systems () progress_indication ("["); System *system = dynamic_cast (broken_intos_[i]); + system->post_processing (); scm_vector_set_x (lines, scm_from_int (i), system->get_paper_system ()); @@ -206,6 +206,11 @@ System::break_into_pieces (vector const &breaking) vector c (breaking[i].cols_); pscore_->typeset_system (system); + int st = Paper_column::get_rank (c[0]); + int end = Paper_column::get_rank (c.back ()); + Interval iv (pure_height (this, st, end)); + system->set_property ("pure-Y-extent", ly_interval2scm (iv)); + system->set_bound (LEFT, c[0]); system->set_bound (RIGHT, c.back ()); for (vsize j = 0; j < c.size (); j++) @@ -504,5 +509,6 @@ ADD_INTERFACE (System, "system-interface", /* properties */ "all-elements " "columns " + "pure-Y-extent " "spaceable-staves " ) diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm index 6303c2a6b2..2c84e2d822 100644 --- a/scm/define-grob-properties.scm +++ b/scm/define-grob-properties.scm @@ -484,6 +484,9 @@ sizes (like the dynamic @b{p} and @b{f}) on their baselines.") (apply define-internal-grob-property x)) `( + (pure-relevant-elements ,ly:grob-array? "The subset of elements that are relevant for finding the pure-Y-extent.") + (cached-pure-extents ,vector? "Used by a VerticalAxisGroup to cache the Y-extents of different column ranges.") + (common-refpoint-of-elements ,ly:grob? "Caches the common_refpoint_of_array of the elements grob-set") (axis-group-parent-X ,ly:grob? "Containing X axis group") (axis-group-parent-Y ,ly:grob? "Containing Y axis group") (accidental-grobs ,list? "Alist with (NOTENAME . GROBLIST) entries") @@ -498,6 +501,7 @@ set, which grob to get the direction from .") (dot ,ly:grob? "reference to Dots object.") (dots ,ly:grob-array? "multiple Dots objects.") (figures ,ly:grob-array? "Figured bass objects for continuation line.") + (important-column-ranks ,vector? "Cache of columns that contain items-worth-living.") (glyph-name ,string? "a name of character within font.") (pedal-text ,ly:grob? "Pointer to the text of a mixed-style piano pedal.") (stem ,ly:grob? "pointer to Stem object.") @@ -555,6 +559,7 @@ columns. (positioning-done ,boolean? "Used to signal that a positioning element did its job. This ensures that a positioning is only done once.") + (pure-Y-extent ,number-pair? "The estimated height of a system") (script-stencil ,pair? "Pair (@code{type} . @code{arg}), which diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index 02bc9cc8ad..440cc7162f 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -67,7 +67,7 @@ . ( (axes . (0 1)) (X-extent . ,ly:axis-group-interface::width) - (X-extent . ,ly:axis-group-interface::height) + (Y-extent . ,ly:axis-group-interface::height) (space-alist . ( (clef . (extra-space . 0.5)) (key-signature . (extra-space . 0.0)) @@ -1314,7 +1314,7 @@ (meta . ((class . Spanner) (interfaces . (slur-interface)))))) - (SostenutoPedal + (SostenutoPedal . ( (stencil . ,ly:text-interface::print) (direction . ,RIGHT) @@ -1938,3 +1938,68 @@ (set! all-grob-descriptions (sort all-grob-descriptions alist