From 7d3d28de0ce6e2f018aff599cecd944d1754fe3c Mon Sep 17 00:00:00 2001 From: Mike Solomon Date: Thu, 10 Jan 2013 08:54:12 +0100 Subject: [PATCH] Makes all side-positioning based on skylines instead of boxes. The major work is in side-position-interface.cc, with minor modifications at several places in the code-base to adapt to this. This allows for snugger positioning of horizontally-oriented fingerings. A side-effect of this patch is that side-positioning of all cross-staff grobs delves into the element list of axis-groups in order to better guess position, which results in less collisions (for example, dynamics are less likely to collide with cross-staff beams). --- input/regression/add-stem-support.ly | 25 + .../dynamics-avoid-cross-staff-stem.ly | 11 +- input/regression/finger-chords.ly | 6 +- input/regression/fingering-column.ly | 5 +- input/regression/les-nereides.ly | 8 +- lily/axis-group-interface.cc | 36 +- lily/box-quarantine.cc | 107 ++++ lily/box.cc | 14 + lily/drum-note-engraver.cc | 2 + lily/dynamic-align-engraver.cc | 14 +- lily/fingering-column-engraver.cc | 2 +- lily/fingering-column.cc | 95 ++-- lily/fingering-engraver.cc | 9 + lily/grob-property.cc | 2 +- lily/grob.cc | 7 +- lily/include/axis-group-interface.hh | 3 +- lily/include/box-quarantine.hh | 41 ++ lily/include/box.hh | 2 + lily/include/grob.hh | 8 +- lily/include/multi-measure-rest.hh | 1 + lily/include/self-alignment-interface.hh | 4 - lily/include/side-position-interface.hh | 5 +- lily/include/skyline.hh | 1 + lily/interval-minefield.cc | 2 +- lily/multi-measure-rest.cc | 15 + lily/new-dynamic-engraver.cc | 1 - lily/new-fingering-engraver.cc | 2 +- lily/pointer-group-interface.cc | 9 + lily/script-column.cc | 2 +- lily/self-alignment-interface.cc | 86 ---- lily/side-position-interface.cc | 471 ++++++++---------- lily/skyline.cc | 18 +- lily/stencil-integral.cc | 78 ++- scm/define-grob-properties.scm | 3 + scm/define-grobs.scm | 29 +- scm/lily-library.scm | 9 + scm/output-lib.scm | 22 + 37 files changed, 682 insertions(+), 473 deletions(-) create mode 100644 input/regression/add-stem-support.ly create mode 100644 lily/box-quarantine.cc create mode 100644 lily/include/box-quarantine.hh diff --git a/input/regression/add-stem-support.ly b/input/regression/add-stem-support.ly new file mode 100644 index 0000000000..ab22af643b --- /dev/null +++ b/input/regression/add-stem-support.ly @@ -0,0 +1,25 @@ +\version "2.17.10" + +\header { + texidoc = "@code{add-stem-support} can be removed or implemented +only for beamed notes. +" +} + +music = { + \clef bass + \stemUp + 2..-> + r16 eeses'16 + \set fingeringOrientations = #'(right) + 8-1-4 r + r2 +} + +{ + \music + \override Fingering #'add-stem-support = ##f + \music + \override Fingering #'add-stem-support = #only-if-beamed + \music +} \ No newline at end of file diff --git a/input/regression/dynamics-avoid-cross-staff-stem.ly b/input/regression/dynamics-avoid-cross-staff-stem.ly index e0f4a738be..078d876ad7 100644 --- a/input/regression/dynamics-avoid-cross-staff-stem.ly +++ b/input/regression/dynamics-avoid-cross-staff-stem.ly @@ -1,16 +1,19 @@ -\version "2.16.0" +\version "2.17.10" \header { - texidoc = "LilyPond automatically shifts dynamics that collide with -cross-staff stems when manual beams are used." + texidoc = "Dynamics are correctly nested over/under cross staff stems. +They are, however, not yet factored into horizontal spacing - the fff +collides with other grobs. +" } \new GrandStaff << \new Staff = "PnRH" { \relative g { \stemDown gis8 \p [ \change Staff = "PnLH" \stemUp a, \fff ] + a8 \p [ \change Staff = "PnRH" \stemDown gis'8 \fff ] \change Staff = "PnRH" r4 } } - \new Staff = "PnLH" { \clef "F" { s4 r4 } } + \new Staff = "PnLH" { \clef "F" { s2 r4 } } >> diff --git a/input/regression/finger-chords.ly b/input/regression/finger-chords.ly index 488245c2e6..2c5c6b6972 100644 --- a/input/regression/finger-chords.ly +++ b/input/regression/finger-chords.ly @@ -1,11 +1,11 @@ -\version "2.17.6" +\version "2.17.10" \header { texidoc = "It is possible to associate fingerings uniquely with notes. This makes it possible to add -horizontal fingerings to notes. Fingering clears stems and flags -if @code{'add-stem-support} is set. +horizontal fingerings to notes. Fingering defaults to not clearing +flags and stems unless there is a collision or a beam. " } diff --git a/input/regression/fingering-column.ly b/input/regression/fingering-column.ly index ccf0aafaa0..d4d2551b2e 100644 --- a/input/regression/fingering-column.ly +++ b/input/regression/fingering-column.ly @@ -1,8 +1,9 @@ -\version "2.17.6" +\version "2.17.10" \header { texidoc = "Horizontal @code{Fingering} grobs that collide do not intersect. -Non-intersecting @code{Fingering} grobs are left alone. +Non-intersecting @code{Fingering} grobs are left alone. This is managed +by the @code{FingeringColumn} grob. " } diff --git a/input/regression/les-nereides.ly b/input/regression/les-nereides.ly index c8c47c4bb9..c87772419d 100644 --- a/input/regression/les-nereides.ly +++ b/input/regression/les-nereides.ly @@ -1,4 +1,4 @@ -\version "2.17.6" +\version "2.17.10" \header { composer = "ARTHUR GRAY" @@ -17,7 +17,7 @@ Nastiest piece of competition at http://www.orphee.com/comparison/study.html, see http://www.orphee.com/comparison/gray.pdf -Lines that contain tweaks (10 currently, not counting reverts) are +Lines that contain tweaks (3 currently, not counting reverts) are marked with %tweak possibly more impressive to render without tweaks? @@ -98,10 +98,6 @@ trebleTwo = \new Voice \relative c''{ 2 | %5 s8 cis4. d4 - % fair to count as one tweak? - \override Fingering.add-stem-support = ##t %tweak - \override Fingering.padding = #0.15 - \override Fingering.slur-padding = #0.1 8[( | %6 )] cis'4. d4 diff --git a/lily/axis-group-interface.cc b/lily/axis-group-interface.cc index 707e045c9b..1ed1f7f8fc 100644 --- a/lily/axis-group-interface.cc +++ b/lily/axis-group-interface.cc @@ -51,6 +51,19 @@ Axis_group_interface::get_default_outside_staff_padding () return default_outside_staff_padding_; } +MAKE_SCHEME_CALLBACK (Axis_group_interface, cross_staff, 1); +SCM +Axis_group_interface::cross_staff (SCM smob) +{ + Grob *me = unsmob_grob (smob); + extract_grob_set (me, "elements", elts); + for (vsize i = 0; i < elts.size (); i++) + if (to_boolean (elts[i]->get_property ("cross-staff"))) + return SCM_BOOL_T; + + return SCM_BOOL_F; +} + void Axis_group_interface::add_element (Grob *me, Grob *e) { @@ -99,7 +112,8 @@ Axis_group_interface::relative_maybe_bound_group_extent (vector const &e for (vsize i = 0; i < elts.size (); i++) { Grob *se = elts[i]; - if (!to_boolean (se->get_property ("cross-staff"))) + if (has_interface (se) + || !to_boolean (se->get_property ("cross-staff"))) { Interval dims = (bound && has_interface (se) ? generic_bound_extent (se, common, a) @@ -240,7 +254,8 @@ Axis_group_interface::adjacent_pure_heights (SCM smob) { Grob *g = elts[i]; - if (to_boolean (g->get_property ("cross-staff"))) + if (to_boolean (g->get_property ("cross-staff")) + && !has_interface (g)) continue; bool outside_staff = scm_is_number (g->get_property ("outside-staff-priority")); @@ -392,9 +407,7 @@ SCM Axis_group_interface::calc_skylines (SCM smob) { Grob *me = unsmob_grob (smob); - extract_grob_set (me, Grob_array::unsmob (me->get_object ("vertical-skyline-elements")) ? "vertical-skyline-elements" : "elements", elts); - Skyline_pair skylines = skyline_spacing (me, elts); - + Skyline_pair skylines = skyline_spacing (me); return skylines.smobbed_copy (); } @@ -435,11 +448,13 @@ Axis_group_interface::combine_skylines (SCM smob) SCM Axis_group_interface::generic_group_extent (Grob *me, Axis a) { + extract_grob_set (me, "elements", elts); + /* trigger the callback to do skyline-spacing on the children */ if (a == Y_AXIS) - (void) me->get_property ("vertical-skylines"); + for (vsize i = 0; i < elts.size (); i++) + (void) elts[i]->get_property ("vertical-skylines"); - extract_grob_set (me, "elements", elts); Grob *common = common_refpoint_of_array (elts, me, a); Real my_coord = me->relative_coordinate (common, a); @@ -834,8 +849,10 @@ Axis_group_interface::outside_staff_ancestor (Grob *me) // that there is no room for the cross-staff grob. It also means, of course, that // we don't get the benefits of skyline placement for cross-staff grobs. Skyline_pair -Axis_group_interface::skyline_spacing (Grob *me, vector elements) +Axis_group_interface::skyline_spacing (Grob *me) { + extract_grob_set (me, Grob_array::unsmob (me->get_object ("vertical-skyline-elements")) ? "vertical-skyline-elements" : "elements", fakeelements); + vector elements (fakeelements); for (vsize i = 0; i < elements.size (); i++) /* As a sanity check, we make sure that no grob with an outside staff priority @@ -870,12 +887,13 @@ Axis_group_interface::skyline_spacing (Grob *me, vector elements) vsize i = 0; vector inside_staff_skylines; + for (i = 0; i < elements.size () && !scm_is_number (elements[i]->get_property ("outside-staff-priority")); i++) { Grob *elt = elements[i]; Grob *ancestor = outside_staff_ancestor (elt); - if (!(to_boolean (elt->get_property ("cross-staff")) || ancestor)) + if (!ancestor) add_interior_skylines (elt, x_common, y_common, &inside_staff_skylines); if (ancestor) riders.insert (pair (ancestor, elt)); diff --git a/lily/box-quarantine.cc b/lily/box-quarantine.cc new file mode 100644 index 0000000000..dff8587601 --- /dev/null +++ b/lily/box-quarantine.cc @@ -0,0 +1,107 @@ +/* + This file is part of LilyPond, the GNU music typesetter. + + Copyright (C) 2011--2012 Mike Solomon + Jan Nieuwenhuizen + + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . +*/ + +#include "box-quarantine.hh" +#include + +Box_quarantine::Box_quarantine (Real padding, Axis a) + : padding_ (padding), a_ (a) +{ +} + +void +Box_quarantine::add_box_to_quarantine (Box infected) +{ + Box nbox (infected); + nbox[a_].widen (padding_ / 2); + boxes_to_quarantine_.push_back (nbox); +} + +vector +Box_quarantine::quarantined_boxes () +{ + return boxes_to_quarantine_; +} + +struct Intersection_info +{ + vsize index_; + Real amount_; + int mid_; + Intersection_info (vsize index, Real amount, int mid); +}; + +Intersection_info::Intersection_info (vsize index, Real amount, int mid) + : index_ (index), amount_ (amount), mid_ (mid) +{ +} + +/* + boxes_to_quarantine_ contains a vector of boxes that may + or may not overlap. it iterates through these boxes, + pushing quarantined_boxes_ epsilon over or epsilon under a + collision. when this type of change happens, the loop is marked + as "dirty" and re-iterated. + + TODO: not sure if this loop causes infinite behavior... +*/ + +bool +sort_towards_middle(Intersection_info ii0, Intersection_info ii1) +{ + // ugh...with C++11, we'll just be able to do a factory instead of + // bundling mid with the Intersection_info + int mid = ii0.mid_; + assert ((double)(ii0.index_ - mid) >= 0.0); + assert ((double)(ii1.index_ - mid) >= 0.0); + return fabs (ii0.index_ - mid) < fabs (ii1.index_ - mid); +} + +void +Box_quarantine::solve () +{ + int mid = boxes_to_quarantine_.size () / 2; + Real epsilon = 1.0e-4; + bool dirty = false; + do + { + dirty = false; + vector ii; + for (vsize i = 0; i < boxes_to_quarantine_.size () - 1; i++) + { + Box scratch (boxes_to_quarantine_[i]); + scratch.intersect (boxes_to_quarantine_[i + 1]); + if (!scratch.is_empty ()) + ii.push_back (Intersection_info (i, scratch[a_].length (), mid)); + } + vector_sort (ii, sort_towards_middle); + if (ii.size () > 0) + { + Offset shift (-(epsilon + ii[0].amount_ / 2.0), 0.0); + if (a_ == Y_AXIS) + shift = shift.swapped (); + boxes_to_quarantine_[ii[0].index_].translate (shift); + shift[a_] = -shift[a_]; + boxes_to_quarantine_[ii[0].index_ + 1].translate (shift); + dirty = true; + } + } + while (dirty); +} diff --git a/lily/box.cc b/lily/box.cc index 52af33a142..bc0a975ed0 100644 --- a/lily/box.cc +++ b/lily/box.cc @@ -51,6 +51,13 @@ Box::set_empty () interval_a_[Y_AXIS].set_empty (); } +bool +Box::is_empty () const +{ + return interval_a_[X_AXIS].is_empty () + || interval_a_[Y_AXIS].is_empty (); +} + Box::Box (Interval ix, Interval iy) { x () = ix; @@ -97,6 +104,13 @@ Box::widen (Real x, Real y) interval_a_[Y_AXIS].widen (y); } +void +Box::intersect (Box b) +{ + interval_a_[X_AXIS].intersect (b[X_AXIS]); + interval_a_[Y_AXIS].intersect (b[Y_AXIS]); +} + // for debugging void diff --git a/lily/drum-note-engraver.cc b/lily/drum-note-engraver.cc index 251d2099fe..06d24fdea6 100644 --- a/lily/drum-note-engraver.cc +++ b/lily/drum-note-engraver.cc @@ -128,6 +128,8 @@ Drum_notes_engraver::acknowledge_note_column (Grob_info inf) if (!e->get_parent (X_AXIS) && Side_position_interface::get_axis (e) == Y_AXIS) e->set_parent (inf.grob (), X_AXIS); + + Side_position_interface::add_support (e, inf.grob ()); } } diff --git a/lily/dynamic-align-engraver.cc b/lily/dynamic-align-engraver.cc index 265498658a..37f93cd5c4 100644 --- a/lily/dynamic-align-engraver.cc +++ b/lily/dynamic-align-engraver.cc @@ -34,7 +34,8 @@ class Dynamic_align_engraver : public Engraver { TRANSLATOR_DECLARATIONS (Dynamic_align_engraver); - DECLARE_ACKNOWLEDGER (note_column); + DECLARE_ACKNOWLEDGER (rhythmic_head); + DECLARE_ACKNOWLEDGER (stem); DECLARE_ACKNOWLEDGER (dynamic); DECLARE_ACKNOWLEDGER (footnote_spanner); DECLARE_END_ACKNOWLEDGER (dynamic); @@ -64,7 +65,8 @@ Dynamic_align_engraver::Dynamic_align_engraver () } ADD_ACKNOWLEDGER (Dynamic_align_engraver, dynamic); -ADD_ACKNOWLEDGER (Dynamic_align_engraver, note_column); +ADD_ACKNOWLEDGER (Dynamic_align_engraver, rhythmic_head); +ADD_ACKNOWLEDGER (Dynamic_align_engraver, stem); ADD_ACKNOWLEDGER (Dynamic_align_engraver, footnote_spanner); ADD_END_ACKNOWLEDGER (Dynamic_align_engraver, dynamic); @@ -107,7 +109,13 @@ Dynamic_align_engraver::acknowledge_footnote_spanner (Grob_info info) } void -Dynamic_align_engraver::acknowledge_note_column (Grob_info info) +Dynamic_align_engraver::acknowledge_rhythmic_head (Grob_info info) +{ + support_.push_back (info.grob ()); +} + +void +Dynamic_align_engraver::acknowledge_stem (Grob_info info) { support_.push_back (info.grob ()); } diff --git a/lily/fingering-column-engraver.cc b/lily/fingering-column-engraver.cc index bff3d7c886..1c5b904809 100644 --- a/lily/fingering-column-engraver.cc +++ b/lily/fingering-column-engraver.cc @@ -27,7 +27,7 @@ /** Find potentially colliding scripts, and put them in a - Fingering_column, that will fix the collisions. */ + Fingering_column, that will fix the columns. */ class Fingering_column_engraver : public Engraver { Drul_array fingering_columns_; diff --git a/lily/fingering-column.cc b/lily/fingering-column.cc index d027dfa754..76c7bd3b89 100644 --- a/lily/fingering-column.cc +++ b/lily/fingering-column.cc @@ -19,6 +19,7 @@ #include "grob.hh" #include "fingering-column.hh" +#include "box-quarantine.hh" #include "pointer-group-interface.hh" #include "staff-symbol-referencer.hh" #include "item.hh" @@ -26,19 +27,37 @@ #include +// The sorting algorithm may not preserve the order of the +// original fingerings. We use Fingering_position_info to retain +// this order. + +struct Fingering_position_info { + Box box_; + vsize idx_; + Fingering_position_info (Box, vsize); +}; + +Fingering_position_info::Fingering_position_info (Box box, vsize idx) + : box_ (box), idx_ (idx) +{ +} + +bool +fingering_position_less (Fingering_position_info fpi0, Fingering_position_info fpi1) +{ + return Interval::left_less (fpi0.box_[Y_AXIS], fpi1.box_[Y_AXIS]); +} + MAKE_SCHEME_CALLBACK (Fingering_column, calc_positioning_done, 1); SCM Fingering_column::calc_positioning_done (SCM smob) { Grob *me = unsmob_grob (smob); - Real padding = robust_scm2double (me->get_property ("padding"), 0.0); if (!me->is_live ()) return SCM_BOOL_T; map shifted; - Real ss = Staff_symbol_referencer::staff_space (me); - me->set_property ("positioning-done", SCM_BOOL_T); extract_grob_set (me, "fingerings", const_fingerings); @@ -49,63 +68,39 @@ Fingering_column::calc_positioning_done (SCM smob) return SCM_BOOL_T; } - // order the fingerings from bottom to top vector fingerings; for (vsize i = 0; i < const_fingerings.size (); i++) fingerings.push_back (const_fingerings[i]); - vector_sort (fingerings, pure_position_less); Grob *common[2] = {common_refpoint_of_array (fingerings, me, X_AXIS), common_refpoint_of_array (fingerings, me, Y_AXIS)}; + Real padding = robust_scm2double (me->get_property ("padding"), 0.2); + Box_quarantine bq (padding, Y_AXIS); + vector origs; for (vsize i = 0; i < fingerings.size (); i++) - fingerings[i]->translate_axis (-fingerings[i]->extent (common[Y_AXIS], Y_AXIS).length () / 2, Y_AXIS); - - for (vsize i = min (fingerings.size () - 1, fingerings.size () / 2 + 1); i >= 1; i--) - for (vsize j = i; j--;) - { - Interval ex_i = fingerings[i]->extent (common[X_AXIS], X_AXIS); - Interval ex_j = fingerings[j]->extent (common[X_AXIS], X_AXIS); - Interval ey_i = fingerings[i]->extent (common[Y_AXIS], Y_AXIS); - Interval ey_j = fingerings[j]->extent (common[Y_AXIS], Y_AXIS); - Real tval = min (0.0, (ey_i[DOWN] - ey_j[UP] - padding) / 2); - if (tval != 0.0 && !intersection (ex_i, ex_j).is_empty ()) - { - if (shifted[fingerings[i]] || shifted[fingerings[j]]) - fingerings[j]->translate_axis (tval * 2, Y_AXIS); - else - { - fingerings[i]->translate_axis (-tval, Y_AXIS); - fingerings[j]->translate_axis (tval, Y_AXIS); - } - shifted[fingerings[i]] = true; - shifted[fingerings[j]] = true; - } - } - - for (vsize i = fingerings.size () / 2 - 1; i < fingerings.size () - 1; i++) - for (vsize j = i + 1; j < fingerings.size (); j++) - { - Interval ex_i = fingerings[i]->extent (common[X_AXIS], X_AXIS); - Interval ex_j = fingerings[j]->extent (common[X_AXIS], X_AXIS); - Interval ey_i = fingerings[i]->extent (common[Y_AXIS], Y_AXIS); - Interval ey_j = fingerings[j]->extent (common[Y_AXIS], Y_AXIS); - Real tval = max (0.0, (ey_i[UP] - ey_j[DOWN] + padding) / 2); - if (tval != 0.0 && !intersection (ex_i, ex_j).is_empty ()) - { - if (shifted[fingerings[i]] || shifted[fingerings[j]]) - fingerings[j]->translate_axis (tval * 2, Y_AXIS); - else - { - fingerings[i]->translate_axis (-tval, Y_AXIS); - fingerings[j]->translate_axis (tval, Y_AXIS); - } - shifted[fingerings[i]] = true; - shifted[fingerings[j]] = true; - } - } + { + Interval x_ext = fingerings[i]->extent (common[X_AXIS], X_AXIS); + // center on Y parent + fingerings[i]->translate_axis (-fingerings[i]->extent (fingerings[i], Y_AXIS).length () / 2.0, Y_AXIS); + Interval y_ext = fingerings[i]->extent (fingerings[i], Y_AXIS) + + fingerings[i]->get_parent (Y_AXIS) + ->relative_coordinate (common[Y_AXIS], Y_AXIS); + origs.push_back(Fingering_position_info (Box (x_ext, y_ext), i)); + } + + // order the fingerings from bottom to top + vector_sort (origs, fingering_position_less); + + for (vsize i = 0; i < origs.size (); i++) + bq.add_box_to_quarantine (Box (origs[i].box_)); + + bq.solve (); + vector news (bq.quarantined_boxes ()); + for (vsize i = 0; i < origs.size (); i++) + fingerings[origs[i].idx_]->translate_axis (news[i][Y_AXIS][DOWN] - origs[i].box_[Y_AXIS][DOWN], Y_AXIS); return SCM_BOOL_T; } diff --git a/lily/fingering-engraver.cc b/lily/fingering-engraver.cc index a364947b08..2571ac1d70 100644 --- a/lily/fingering-engraver.cc +++ b/lily/fingering-engraver.cc @@ -41,6 +41,7 @@ protected: DECLARE_TRANSLATOR_LISTENER (fingering); DECLARE_ACKNOWLEDGER (rhythmic_head); DECLARE_ACKNOWLEDGER (stem); + DECLARE_ACKNOWLEDGER (flag); private: void make_script (Direction, Stream_event *, int); @@ -60,6 +61,13 @@ Fingering_engraver::acknowledge_stem (Grob_info inf) Side_position_interface::add_support (fingerings_[i], inf.grob ()); } +void +Fingering_engraver::acknowledge_flag (Grob_info inf) +{ + for (vsize i = 0; i < fingerings_.size (); i++) + Side_position_interface::add_support (fingerings_[i], inf.grob ()); +} + void Fingering_engraver::acknowledge_rhythmic_head (Grob_info inf) { @@ -139,6 +147,7 @@ Fingering_engraver::Fingering_engraver () ADD_ACKNOWLEDGER (Fingering_engraver, rhythmic_head); ADD_ACKNOWLEDGER (Fingering_engraver, stem); +ADD_ACKNOWLEDGER (Fingering_engraver, flag); ADD_TRANSLATOR (Fingering_engraver, /* doc */ diff --git a/lily/grob-property.cc b/lily/grob-property.cc index 3afe182c0e..9120aefdf2 100644 --- a/lily/grob-property.cc +++ b/lily/grob-property.cc @@ -170,7 +170,7 @@ Grob::internal_get_property (SCM sym) const { programming_error (to_string ("cyclic dependency: calculation-in-progress encountered for #'%s (%s)", ly_symbol2string (sym).c_str (), - name ().c_str ())); + name ().c_str ()));//assert (1==0); if (debug_property_callbacks) { message ("backtrace: "); diff --git a/lily/grob.cc b/lily/grob.cc index 031af32636..4c54cbc508 100644 --- a/lily/grob.cc +++ b/lily/grob.cc @@ -81,9 +81,9 @@ Grob::Grob (SCM basicprops) if (get_property_data ("Y-extent") == SCM_EOL) set_property ("Y-extent", Grob::stencil_height_proc); if (get_property_data ("vertical-skylines") == SCM_EOL) - set_property ("vertical-skylines", Grob::simple_vertical_skylines_from_stencil_proc); + set_property ("vertical-skylines", Grob::simple_vertical_skylines_from_extents_proc); if (get_property_data ("horizontal-skylines") == SCM_EOL) - set_property ("horizontal-skylines", Grob::simple_horizontal_skylines_from_stencil_proc); + set_property ("horizontal-skylines", Grob::simple_horizontal_skylines_from_extents_proc); } Grob::Grob (Grob const &s) @@ -485,6 +485,9 @@ Interval Grob::pure_height (Grob *refp, int start, int end) { SCM iv_scm = get_pure_property ("Y-extent", start, end); + // TODO: Why is this Interval (0,0) + // Shouldn't it just be an empty interval? + // 0,0 puts an arbitrary point at 0,0 which will influence spacing Interval iv = robust_scm2interval (iv_scm, Interval (0, 0)); Real offset = pure_relative_y_coordinate (refp, start, end); diff --git a/lily/include/axis-group-interface.hh b/lily/include/axis-group-interface.hh index 4098a19514..1ba26af829 100644 --- a/lily/include/axis-group-interface.hh +++ b/lily/include/axis-group-interface.hh @@ -34,6 +34,7 @@ class Axis_group_interface static Real get_default_outside_staff_padding (); static Interval generic_bound_extent (Grob *me, Grob *common, Axis a); static Interval pure_group_height (Grob *me, int start, int end); + DECLARE_SCHEME_CALLBACK (cross_staff, (SCM smob)); DECLARE_SCHEME_CALLBACK (width, (SCM smob)); DECLARE_SCHEME_CALLBACK (calc_x_common, (SCM smob)); DECLARE_SCHEME_CALLBACK (calc_y_common, (SCM smob)); @@ -62,7 +63,7 @@ class Axis_group_interface static Interval part_of_line_pure_height (Grob *me, bool begin, int, int); static Grob *outside_staff_ancestor (Grob *me); - static Skyline_pair skyline_spacing (Grob *me, vector elements); + static Skyline_pair skyline_spacing (Grob *me); static void add_element (Grob *me, Grob *); static void set_axes (Grob *, Axis, Axis); static bool has_axis (Grob *, Axis); diff --git a/lily/include/box-quarantine.hh b/lily/include/box-quarantine.hh new file mode 100644 index 0000000000..3673a959bd --- /dev/null +++ b/lily/include/box-quarantine.hh @@ -0,0 +1,41 @@ +/* + This file is part of LilyPond, the GNU music typesetter. + + Copyright (C) 2012 Mike Solomon + + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . +*/ + +#ifndef BOX_QUARANTINE_HH +#define BOX_QUARANTINE_HH + +#include "lily-proto.hh" +#include "std-vector.hh" +#include "box.hh" + +class Box_quarantine +{ +public: + Box_quarantine (Real, Axis); + void add_box_to_quarantine (Box); + void solve (); + vector quarantined_boxes (); + +private: + vector boxes_to_quarantine_; + Real padding_; + Axis a_; +}; + +#endif // BOX_QUARANTINE_HH diff --git a/lily/include/box.hh b/lily/include/box.hh index ab0d3f5300..63224f2f88 100644 --- a/lily/include/box.hh +++ b/lily/include/box.hh @@ -21,6 +21,7 @@ public: Interval operator [] (Axis a) const; Interval &operator [] (Axis a); Real area () const; + bool is_empty () const; Offset center () const; @@ -32,6 +33,7 @@ public: void widen (Real x, Real y); void scale (Real r); void unite (Box b); + void intersect (Box b); void print (); Box (); Box (Interval ix, Interval iy); diff --git a/lily/include/grob.hh b/lily/include/grob.hh index 09cd566ad3..a98b19a9f6 100644 --- a/lily/include/grob.hh +++ b/lily/include/grob.hh @@ -71,10 +71,12 @@ public: DECLARE_SCHEME_CALLBACK (y_parent_positioning, (SCM)); DECLARE_SCHEME_CALLBACK (stencil_height, (SCM smob)); DECLARE_SCHEME_CALLBACK (stencil_width, (SCM smob)); - DECLARE_SCHEME_CALLBACK (simple_vertical_skylines_from_stencil, (SCM smob)); + DECLARE_SCHEME_CALLBACK (pure_simple_vertical_skylines_from_extents, (SCM smob, SCM, SCM)); + DECLARE_SCHEME_CALLBACK (simple_vertical_skylines_from_extents, (SCM smob)); DECLARE_SCHEME_CALLBACK (vertical_skylines_from_stencil, (SCM smob)); DECLARE_SCHEME_CALLBACK (vertical_skylines_from_element_stencils, (SCM smob)); - DECLARE_SCHEME_CALLBACK (simple_horizontal_skylines_from_stencil, (SCM smob)); + DECLARE_SCHEME_CALLBACK (pure_simple_horizontal_skylines_from_extents, (SCM smob, SCM, SCM)); + DECLARE_SCHEME_CALLBACK (simple_horizontal_skylines_from_extents, (SCM smob)); DECLARE_SCHEME_CALLBACK (horizontal_skylines_from_stencil, (SCM smob)); DECLARE_SCHEME_CALLBACK (horizontal_skylines_from_element_stencils, (SCM smob)); @@ -161,7 +163,7 @@ public: virtual bool pure_is_visible (int start, int end) const; bool check_cross_staff (Grob *common); static bool less (Grob *g1, Grob *g2); - static SCM internal_simple_skylines_from_stencil (SCM, Axis); + static SCM maybe_pure_internal_simple_skylines_from_extents (Grob *, Axis, bool, int, int, bool, bool); static SCM internal_skylines_from_element_stencils (SCM, Axis); }; diff --git a/lily/include/multi-measure-rest.hh b/lily/include/multi-measure-rest.hh index 55943c4b44..d012a77b07 100644 --- a/lily/include/multi-measure-rest.hh +++ b/lily/include/multi-measure-rest.hh @@ -28,6 +28,7 @@ class Multi_measure_rest public: DECLARE_GROB_INTERFACE (); DECLARE_SCHEME_CALLBACK (print, (SCM)); + DECLARE_SCHEME_CALLBACK (height, (SCM)); DECLARE_SCHEME_CALLBACK (percent, (SCM)); static void add_column (Grob *, Item *); DECLARE_SCHEME_CALLBACK (set_spacing_rods, (SCM)); diff --git a/lily/include/self-alignment-interface.hh b/lily/include/self-alignment-interface.hh index c3c7e9c878..dd69f86630 100644 --- a/lily/include/self-alignment-interface.hh +++ b/lily/include/self-alignment-interface.hh @@ -30,10 +30,8 @@ struct Self_alignment_interface static SCM aligned_on_self (Grob *me, Axis a, bool pure, int start, int end); static SCM centered_on_object (Grob *me, Axis a); static SCM aligned_on_parent (Grob *me, Axis a); - static SCM avoid_colliding_grobs (Grob *me, Axis a, Real offset); static void set_center_parent (Grob *me, Axis a); static void set_align_self (Grob *me, Axis a); - static void avoid_x_collisions (Grob *me); DECLARE_SCHEME_CALLBACK (x_aligned_on_self, (SCM element)); DECLARE_SCHEME_CALLBACK (y_aligned_on_self, (SCM element)); @@ -44,8 +42,6 @@ struct Self_alignment_interface DECLARE_SCHEME_CALLBACK (centered_on_x_parent, (SCM element)); DECLARE_SCHEME_CALLBACK (centered_on_y_parent, (SCM element)); DECLARE_SCHEME_CALLBACK (x_centered_on_y_parent, (SCM element)); - DECLARE_SCHEME_CALLBACK (avoid_x_colliding_grobs, (SCM element, SCM offset)); - DECLARE_SCHEME_CALLBACK (x_colliding_grobs, (SCM element)); DECLARE_SCHEME_CALLBACK (aligned_on_x_parent, (SCM element)); DECLARE_SCHEME_CALLBACK (aligned_on_y_parent, (SCM element)); }; diff --git a/lily/include/side-position-interface.hh b/lily/include/side-position-interface.hh index edb6dc6a7a..e7c1637471 100644 --- a/lily/include/side-position-interface.hh +++ b/lily/include/side-position-interface.hh @@ -42,14 +42,11 @@ public: static SCM aligned_side (Grob *me, Axis a, bool pure, int start, int end, Real *current_off_ptr); - static SCM general_side_position (Grob *, Axis, bool, bool my_extents, - bool pure, int start, int end, Real *current_off); - static SCM skyline_side_position (Grob *me, Axis a, bool pure, int start, int end, Real *current_offset); - static Axis get_axis (Grob *); static void set_axis (Grob *, Axis); DECLARE_GROB_INTERFACE (); static void add_support (Grob *, Grob *); + static void recursive_add_support (Grob *, Grob *); static void add_staff_support (Grob *); }; diff --git a/lily/include/skyline.hh b/lily/include/skyline.hh index c300895fee..9a5473ddd5 100644 --- a/lily/include/skyline.hh +++ b/lily/include/skyline.hh @@ -92,6 +92,7 @@ public: Real max_height_position () const; Real left () const; Real right () const; + Direction direction () const; void set_minimum_height (Real height); void clear (); bool is_empty () const; diff --git a/lily/interval-minefield.cc b/lily/interval-minefield.cc index b0f67afa74..d26e3e0d28 100644 --- a/lily/interval-minefield.cc +++ b/lily/interval-minefield.cc @@ -19,7 +19,7 @@ */ #include "interval-minefield.hh" -#include "grob.hh" + Interval_minefield::Interval_minefield (Interval feasible_placements, Real bulk) { feasible_placements_ = feasible_placements; diff --git a/lily/multi-measure-rest.cc b/lily/multi-measure-rest.cc index 47718a2fec..df06f790df 100644 --- a/lily/multi-measure-rest.cc +++ b/lily/multi-measure-rest.cc @@ -115,6 +115,21 @@ Multi_measure_rest::print (SCM smob) return mol.smobbed_copy (); } +MAKE_SCHEME_CALLBACK (Multi_measure_rest, height, 1); +SCM +Multi_measure_rest::height (SCM smob) +{ + Grob *me = unsmob_grob (smob); + Spanner *sp = dynamic_cast (me); + + Real space = 1000000; // something very large... + + Stencil mol; + mol.add_stencil (symbol_stencil (me, space)); + + return ly_interval2scm (mol.extent (Y_AXIS)); +} + int calc_closest_duration_log (Grob *me, double duration, bool force_round_up, bool paranoid) { diff --git a/lily/new-dynamic-engraver.cc b/lily/new-dynamic-engraver.cc index 749f9aaa16..cd7db644a6 100644 --- a/lily/new-dynamic-engraver.cc +++ b/lily/new-dynamic-engraver.cc @@ -272,7 +272,6 @@ New_dynamic_engraver::acknowledge_note_column (Grob_info info) { script_->set_parent (x_parent, X_AXIS); Self_alignment_interface::set_center_parent (script_, X_AXIS); - Self_alignment_interface::avoid_x_collisions (script_); } if (stem) Pointer_group_interface::add_grob (script_, ly_symbol2scm ("potential-X-colliding-grobs"), stem); diff --git a/lily/new-fingering-engraver.cc b/lily/new-fingering-engraver.cc index 574591a23e..a605f0f4ae 100644 --- a/lily/new-fingering-engraver.cc +++ b/lily/new-fingering-engraver.cc @@ -194,7 +194,7 @@ New_fingering_engraver::position_scripts (SCM orientations, vector *scripts) { for (vsize i = 0; i < scripts->size (); i++) - if (stem_ && to_boolean (scripts->at (i).script_->get_property ("add-stem-support"))) + if (stem_) { Side_position_interface::add_support (scripts->at (i).script_, stem_); if (Grob *flag = unsmob_grob (stem_->get_object ("flag"))) diff --git a/lily/pointer-group-interface.cc b/lily/pointer-group-interface.cc index 045563d457..79888348f9 100644 --- a/lily/pointer-group-interface.cc +++ b/lily/pointer-group-interface.cc @@ -68,11 +68,19 @@ Pointer_group_interface::find_grob (Grob *me, SCM sym, bool (*pred) (Grob *)) return 0; } +// If the grob array is unordered, we assume that duplicates should +// be removed. This makes sense for things like side-position-elements, +// which may be added recursively numerous times and thus will eat up +// computation time when skylines are calculated. +// If the array is ordered, then we don't remove duplicates. + void Pointer_group_interface::add_grob (Grob *me, SCM sym, Grob *p) { Grob_array *arr = get_grob_array (me, sym); arr->add (p); + if (!arr->ordered ()) + arr->remove_duplicates (); } void @@ -81,6 +89,7 @@ Pointer_group_interface::add_unordered_grob (Grob *me, SCM sym, Grob *p) Grob_array *arr = get_grob_array (me, sym); arr->add (p); arr->set_ordered (false); + arr->remove_duplicates (); } static vector empty_array; diff --git a/lily/script-column.cc b/lily/script-column.cc index 0a014a3800..d0486ea4aa 100644 --- a/lily/script-column.cc +++ b/lily/script-column.cc @@ -156,7 +156,7 @@ Script_column::order_grobs (vector grobs) use it as a support for the current grob */ if (!scm_is_number (last_outside_staff)) - Side_position_interface::add_support (g, last); + Side_position_interface::recursive_add_support (g, last); /* if outside_staff_priority is missing or is equal to original outside_staff_priority of previous grob, set new diff --git a/lily/self-alignment-interface.cc b/lily/self-alignment-interface.cc index ff2b5bfd59..59adfc3e6c 100644 --- a/lily/self-alignment-interface.cc +++ b/lily/self-alignment-interface.cc @@ -158,86 +158,6 @@ Self_alignment_interface::aligned_on_parent (Grob *me, Axis a) return scm_from_double (x); } -MAKE_SCHEME_CALLBACK (Self_alignment_interface, avoid_x_colliding_grobs, 2); -SCM -Self_alignment_interface::avoid_x_colliding_grobs (SCM smob, SCM o) -{ - SCM avoided = avoid_colliding_grobs (unsmob_grob (smob), X_AXIS, robust_scm2double (o, 0.0)); - return scm_is_null (avoided) ? o : avoided; -} - -MAKE_SCHEME_CALLBACK (Self_alignment_interface, x_colliding_grobs, 1); -SCM -Self_alignment_interface::x_colliding_grobs (SCM smob) -{ - Grob *me = unsmob_grob (smob); - extract_grob_set (me, "potential-X-colliding-grobs", pot); - vector act; - Direction d = get_grob_direction (me->get_parent (Y_AXIS)); - for (vsize i = 0; i < pot.size (); i++) - if (d == get_grob_direction (pot[i]) - && to_boolean (pot[i]->get_property ("cross-staff"))) - act.push_back (pot[i]); - - SCM grobs_scm = Grob_array::make_array (); - unsmob_grob_array (grobs_scm)->set_array (act); - - return grobs_scm; -} - -SCM -Self_alignment_interface::avoid_colliding_grobs (Grob *me, Axis a, Real offset) -{ - extract_grob_set (me, a == X_AXIS ? "X-colliding-grobs" : "Y-colliding-grobs", colls); - if (!colls.size ()) - return SCM_EOL; - vector ivs; - - Item *refp = dynamic_cast (common_refpoint_of_array (colls, me, a)); - if (!refp) - return SCM_EOL; - - Interval iv = me->extent (me, a) + offset; - for (vsize i = 0; i < colls.size (); i++) - { - int my_vai = Grob::get_vertical_axis_group_index (colls[i]); - Direction dir = get_grob_direction (colls[i]); - // if coll is cross staff but extremal and pointing in the - // direction of the extrema, we don't take it into consideration - if (Grob *beam = unsmob_grob (colls[i]->get_object ("beam"))) - { - Interval_t vais; - extract_grob_set (beam, "normal-stems", stems); - for (vsize j = 0; j < stems.size (); j++) - vais.add_point (Grob::get_vertical_axis_group_index (stems[j])); - // ugh...up and down are different for VerticalAxisGroup order... - if ((my_vai == vais[DOWN] && dir == UP) - || (my_vai == vais[UP] && dir == DOWN)) - continue; - } - ivs.push_back (colls[i]->extent (refp, a)); - } - - Interval_minefield minefield (Interval (iv.center (), iv.center ()), iv.length ()); - for (vsize i = 0; i < ivs.size (); i++) - minefield.add_forbidden_interval (ivs[i]); - minefield.solve (); - Interval pos = minefield.feasible_placements (); - - if (pos[LEFT] == pos[RIGHT]) - return SCM_EOL; - - Direction col_dir = ((abs (pos[LEFT] - iv.center ()) - + robust_scm2double (me->get_property ("collision-bias"), 0.0)) - > abs (pos[RIGHT] - iv.center ())) - ? RIGHT - : LEFT; - - return scm_from_double ((pos[col_dir] - (iv.length () / 2) - + col_dir - * robust_scm2double (me->get_property ("collision-padding"), 0.0))); -} - void Self_alignment_interface::set_center_parent (Grob *me, Axis a) { @@ -246,12 +166,6 @@ Self_alignment_interface::set_center_parent (Grob *me, Axis a) a); } -void -Self_alignment_interface::avoid_x_collisions (Grob *me) -{ - chain_offset_callback (me, avoid_x_colliding_grobs_proc, X_AXIS); -} - void Self_alignment_interface::set_align_self (Grob *me, Axis a) { diff --git a/lily/side-position-interface.cc b/lily/side-position-interface.cc index b515aa3d52..49c6ece55a 100644 --- a/lily/side-position-interface.cc +++ b/lily/side-position-interface.cc @@ -32,6 +32,8 @@ using namespace std; #include "directional-element-interface.hh" #include "grob.hh" #include "grob-array.hh" +#include "international.hh" +#include "item.hh" #include "main.hh" #include "misc.hh" #include "note-head.hh" @@ -51,35 +53,13 @@ Side_position_interface::add_support (Grob *me, Grob *e) Pointer_group_interface::add_unordered_grob (me, ly_symbol2scm ("side-support-elements"), e); } -SCM -finish_offset (Grob *me, Direction dir, Real total_off, Real *current_offset) +void +Side_position_interface::recursive_add_support (Grob *me, Grob *e) { - Real ss = Staff_symbol_referencer::staff_space (me); - Real minimum_space = ss * robust_scm2double (me->get_property ("minimum-space"), -1); - total_off += dir * ss * robust_scm2double (me->get_property ("padding"), 0); - - if (minimum_space >= 0 - && dir - && total_off * dir < minimum_space) - total_off = minimum_space * dir; - - if (current_offset) - total_off = dir * max (dir * total_off, - dir * (*current_offset)); - - /* FIXME: 1000 should relate to paper size. */ - if (fabs (total_off) > 1000) - { - string msg - = String_convert::form_string ("Improbable offset for grob %s: %f", - me->name ().c_str (), total_off); - - programming_error (msg); - if (strict_infinity_checking) - scm_misc_error (__FUNCTION__, "Improbable offset.", SCM_EOL); - } - - return scm_from_double (total_off); + Pointer_group_interface::add_unordered_grob (me, ly_symbol2scm ("side-support-elements"), e); + extract_grob_set (e, "side-support-elements", sse); + for (vsize i = 0; i < sse.size (); i++) + recursive_add_support (me, sse[i]); } set @@ -110,145 +90,167 @@ get_support_set (Grob *me) return support; } -/* Put the element next to the support, optionally taking in - account the extent of the support. - - Does not take into account the extent of ME. +/* + Position next to support, taking into account my own dimensions and padding. */ SCM -Side_position_interface::general_side_position (Grob *me, Axis a, bool use_extents, - bool include_my_extent, - bool pure, int start, int end, - Real *current_offset) +axis_aligned_side_helper (SCM smob, Axis a, bool pure, int start, int end, SCM current_off_scm) { - set support = get_support_set (me); - - Grob *common = common_refpoint_of_array (support, me->get_parent (a), a); - Grob *staff_symbol = Staff_symbol_referencer::get_staff_symbol (me); - bool include_staff - = staff_symbol - && a == Y_AXIS - && scm_is_number (me->get_property ("staff-padding")) - && !to_boolean (me->get_property ("quantize-position")); - - Interval dim; - Interval staff_extents; - if (include_staff) + Real r; + Real *current_off_ptr = 0; + if (scm_is_number (current_off_scm)) { - common = staff_symbol->common_refpoint (common, Y_AXIS); - staff_extents = staff_symbol->maybe_pure_extent (common, Y_AXIS, pure, start, end); - - if (include_staff) - dim.unite (staff_extents); + r = scm_to_double (current_off_scm); + current_off_ptr = &r; } - Direction dir = get_grob_direction (me); - - set::iterator it; - - for (it = support.begin (); it != support.end (); it++) - { - Grob *e = *it; + Grob *me = unsmob_grob (smob); + // We will only ever want widths of spanners after line breaking + // so we can set pure to false + if (dynamic_cast (me) && a == X_AXIS) + pure = false; - // In the case of a stem, we will find a note head as well - // ignoring the stem solves cyclic dependencies if the stem is - // attached to a cross-staff beam. - if (a == Y_AXIS - && Stem::has_interface (e) - && dir == - get_grob_direction (e)) - continue; + return Side_position_interface::aligned_side (me, a, pure, start, end, current_off_ptr); +} - if (e) - { - if (use_extents) - dim.unite (e->maybe_pure_extent (common, a, pure, start, end)); - else - { - Real x = e->maybe_pure_coordinate (common, a, pure, start, end); - dim.unite (Interval (x, x)); - } - } - } +MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Side_position_interface, x_aligned_side, 2, 1, ""); +SCM +Side_position_interface::x_aligned_side (SCM smob, SCM current_off) +{ + // Because horizontal skylines need vertical heights, we'd trigger + // unpure calculations too soon if this were called before line breaking. + // So, we always use pure heights. Given that horizontal skylines are + // almost always used before line breaking anyway, this doesn't cause + // problems. + return axis_aligned_side_helper (smob, X_AXIS, true, 0, 0, current_off); +} - if (dim.is_empty ()) - dim = Interval (0, 0); +MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Side_position_interface, y_aligned_side, 2, 1, ""); +SCM +Side_position_interface::y_aligned_side (SCM smob, SCM current_off) +{ + return axis_aligned_side_helper (smob, Y_AXIS, false, 0, 0, current_off); +} - Real off = me->get_parent (a)->maybe_pure_coordinate (common, a, pure, start, end); +MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Side_position_interface, pure_y_aligned_side, 4, 1, ""); +SCM +Side_position_interface::pure_y_aligned_side (SCM smob, SCM start, SCM end, SCM cur_off) +{ + return axis_aligned_side_helper (smob, Y_AXIS, true, + scm_to_int (start), + scm_to_int (end), + cur_off); +} - Real total_off = dim.linear_combination (dir) - off; - if (include_my_extent) - { - Interval iv = me->maybe_pure_extent (me, a, pure, start, end); - if (!iv.is_empty ()) - { - if (!dir) - { - programming_error ("direction unknown, but aligned-side wanted"); - dir = DOWN; - } - total_off += -iv[-dir]; - } - } +MAKE_SCHEME_CALLBACK (Side_position_interface, calc_cross_staff, 1) +SCM +Side_position_interface::calc_cross_staff (SCM smob) +{ + Grob *me = unsmob_grob (smob); + extract_grob_set (me, "side-support-elements", elts); +// Commented out because of cross staff issues +// Direction for cross staff stems depends on the spacing of staves, +// which depends on the inclusion of cross-staff side position grobs, +// which need the direction for positioning. So the get_grob_direction call +// may lead to circular dependencies. +// #if 0 + Direction my_dir = get_grob_direction (me) ; + + // if a cross-staff grob is pointing in a different direction than + // that of an aligning element, we assume that the alignment + // of said element will not be influenced the cross-staffitude + // of the grob and thus we do not mark the aligning element + // as cross-staff + for (vsize i = 0; i < elts.size (); i++) + if (to_boolean (elts[i]->get_property ("cross-staff")) + && my_dir == get_grob_direction (elts[i])) + return SCM_BOOL_T; +//#endif +#if 0 + for (vsize i = 0; i < elts.size (); i++) + if (to_boolean (elts[i]->get_property ("cross-staff"))) + return SCM_BOOL_T; +#endif + Grob *myvag = Grob::get_vertical_axis_group (me); + for (vsize i = 0; i < elts.size (); i++) + if (myvag != Grob::get_vertical_axis_group (elts[i])) + return SCM_BOOL_T; - return finish_offset (me, dir, total_off, current_offset); + return SCM_BOOL_F; } +// long function - each stage is clearly marked + SCM -Side_position_interface::skyline_side_position (Grob *me, Axis a, - bool pure, int start, int end, - Real *current_offset) -{ +Side_position_interface::aligned_side (Grob *me, Axis a, bool pure, int start, int end, + Real *current_off) +{//printf (" %s\n", me->name ().c_str ()); + Direction dir = get_grob_direction (me); + set support = get_support_set (me); Grob *common[2]; for (Axis ax = X_AXIS; ax < NO_AXES; incr (ax)) - common[ax] = common_refpoint_of_array (support, ax == a ? me->get_parent (ax) : me, ax); + common[ax] = common_refpoint_of_array (support, + (ax == a + ? me->get_parent (ax) + : me), + ax); Grob *staff_symbol = Staff_symbol_referencer::get_staff_symbol (me); - Direction dir = get_grob_direction (me); + + bool include_staff + = staff_symbol + && a == Y_AXIS + && scm_is_number (me->get_property ("staff-padding")) + && !to_boolean (me->get_property ("quantize-position")); + + if (include_staff) + common[Y_AXIS] = staff_symbol->common_refpoint (common[Y_AXIS], Y_AXIS); Skyline my_dim; - Skyline_pair *sp = Skyline_pair::unsmob (me->get_property ("vertical-skylines")); - if (sp && a == Y_AXIS && !pure) + Skyline_pair *skyp = Skyline_pair::unsmob ( + me->get_maybe_pure_property (a == X_AXIS + ? "horizontal-skylines" + : "vertical-skylines", + pure, + start, + end)); + if (skyp) { - Skyline_pair copy = Skyline_pair (*sp); - copy.shift (me->relative_coordinate (common[X_AXIS], X_AXIS)); - copy.raise (me->get_parent (Y_AXIS)->relative_coordinate (common[Y_AXIS], Y_AXIS)); + // for spanner pure heights, we don't know horizontal spacing, + // so a spanner can never have a meaningful x coordiante + // we just give it the parents' coordinate because its + // skyline will likely be of infinite width anyway + // and we don't want to prematurely trigger H spacing + Real xc = a == X_AXIS || (pure && dynamic_cast (me)) + ? me->get_parent (X_AXIS)->relative_coordinate (common[X_AXIS], X_AXIS) + : me->relative_coordinate (common[X_AXIS], X_AXIS); + // same here, for X_AXIS spacing, if it's happening, it should only be + // before line breaking. because there is no thing as "pure" x spacing, + // we assume that it is all pure + Real yc = a == X_AXIS + ? me->pure_relative_y_coordinate (common[Y_AXIS], start, end) + : me->get_parent (Y_AXIS)->maybe_pure_coordinate (common[Y_AXIS], Y_AXIS, pure, start, end); + Skyline_pair copy = Skyline_pair (*skyp); + copy.shift (a == X_AXIS ? yc : xc); + copy.raise (a == X_AXIS ? xc : yc); my_dim = copy[-dir]; } else - { - Box off; - for (Axis ax = X_AXIS; ax < NO_AXES; incr (ax)) - { - if (ax == a) - off[ax] = me->get_parent (ax)->maybe_pure_coordinate (common[ax], ax, pure, start, end) - + me->maybe_pure_extent (me, ax, pure, start, end); - else - off[ax] = me->maybe_pure_extent (common[ax], ax, pure, start, end); - } + me->warning ("cannot find skylines - strange alignment will follow"); - if (off[X_AXIS].is_empty () || off[Y_AXIS].is_empty ()) - return scm_from_double (0.0); - - my_dim = Skyline (off, other_axis (a), -dir); - } - bool include_staff - = staff_symbol - && a == Y_AXIS - && scm_is_number (me->get_property ("staff-padding")) - && !to_boolean (me->get_property ("quantize-position")); vector boxes; vector skyps; - Real min_h = dir == LEFT ? infinity_f : -infinity_f; set::iterator it; + Real max_raise = -dir * infinity_f; + bool aligns_to_cross_staff = false; - map > note_column_map; // for parts of a note column for (it = support.begin (); it != support.end (); it++) { Grob *e = *it; - +//printf (" %s\n", e->name ().c_str ()); // In the case of a stem, we will find a note head as well // ignoring the stem solves cyclic dependencies if the stem is // attached to a cross-staff beam. @@ -259,161 +261,111 @@ Side_position_interface::skyline_side_position (Grob *me, Axis a, if (e) { - if (Note_column::has_interface (e->get_parent (X_AXIS)) - && to_boolean (me->get_property ("add-stem-support"))) - { - note_column_map[e->get_parent (X_AXIS)].push_back (e); - continue; - } - Skyline_pair *sp = Skyline_pair::unsmob (e->get_property ("vertical-skylines")); - if (sp && a == Y_AXIS && !pure) + bool cross_staff = to_boolean (e->get_property ("cross-staff")); + + Skyline_pair *sp = Skyline_pair::unsmob + (e->get_maybe_pure_property (a == X_AXIS + ? "horizontal-skylines" + : "vertical-skylines", + pure || cross_staff, + start, + end)); + + aligns_to_cross_staff |= cross_staff; + if (sp) { + Real xc = pure && dynamic_cast (e) + ? e->get_parent (X_AXIS)->relative_coordinate (common[X_AXIS], X_AXIS) + : e->relative_coordinate (common[X_AXIS], X_AXIS); + // same logic as above + // we assume horizontal spacing is always pure + Real yc = a == X_AXIS + ? e->pure_relative_y_coordinate (common[Y_AXIS], start, end) + : e->maybe_pure_coordinate (common[Y_AXIS], Y_AXIS, pure, start, end); Skyline_pair copy = Skyline_pair (*sp); - copy.shift (e->relative_coordinate (common[X_AXIS], X_AXIS)); - copy.raise (e->relative_coordinate (common[Y_AXIS], Y_AXIS)); + if (a == Y_AXIS + && Stem::has_interface (e) + && to_boolean (me->get_property ("add-stem-support"))) + copy[dir].set_minimum_height (copy[dir].max_height ()); + copy.shift (a == X_AXIS ? yc : xc); + copy.raise (a == X_AXIS ? xc : yc); + max_raise = minmax (dir, max_raise, a == X_AXIS ? xc : yc); skyps.push_back (copy); - continue; } - Box b; - for (Axis ax = X_AXIS; ax < NO_AXES; incr (ax)) - b[ax] = e->maybe_pure_extent (common[ax], ax, pure, start, end); - - if (b[X_AXIS].is_empty () || b[Y_AXIS].is_empty ()) - continue; - - boxes.push_back (b); - min_h = minmax (dir, b[a][-dir], min_h); + else { /* no warning*/ } } } - // this loop ensures that parts of a note column will be in the same box - // pushes scripts and such over stems instead of just over heads - for (map >::iterator i = note_column_map.begin (); i != note_column_map.end (); i++) - { - Box big; - for (vsize j = 0; j < (*i).second.size (); j++) - { - Grob *e = (*i).second[j]; - Box b; - for (Axis ax = X_AXIS; ax < NO_AXES; incr (ax)) - b[ax] = e->maybe_pure_extent (common[ax], ax, pure, start, end); - - if (b[X_AXIS].is_empty () || b[Y_AXIS].is_empty ()) - continue; - - big.unite (b); - } - if (!big[X_AXIS].is_empty () && !big[Y_AXIS].is_empty ()) - boxes.push_back (big); - } - Skyline dim (boxes, other_axis (a), dir); if (skyps.size ()) { Skyline_pair merged (skyps); dim.merge (merged[dir]); } - if (!boxes.size ()) - dim.set_minimum_height (0.0); - else - dim.set_minimum_height (min_h); if (include_staff) { Interval staff_extents; common[Y_AXIS] = staff_symbol->common_refpoint (common[Y_AXIS], Y_AXIS); staff_extents = staff_symbol->maybe_pure_extent (common[Y_AXIS], Y_AXIS, pure, start, end); - dim.set_minimum_height (minmax (dir, min_h, staff_extents[dir])); + dim.set_minimum_height (staff_extents[dir]); } - Real dist = dim.distance (my_dim, 0.1); // 0.1 m4g1c value...fix... - Real total_off = !isinf (dist) ? dir * dist : 0.0; - - return finish_offset (me, dir, total_off, current_offset); -} - -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, false, false, 0, 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, false, - true, scm_to_int (start), scm_to_int (end), 0); -} - -/* - Position next to support, taking into account my own dimensions and padding. -*/ -SCM -axis_aligned_side_helper (SCM smob, Axis a, bool pure, int start, int end, SCM current_off_scm) -{ - Real r; - Real *current_off_ptr = 0; - if (scm_is_number (current_off_scm)) + // this seems kinda kludgy, as there is no apparent logic to it + // however, it is a holdover from the previous code and + // necessary for the InstrumentName grob + // TODO: find a better way to deal with this... + if (dim.is_empty ()) { - r = scm_to_double (current_off_scm); - current_off_ptr = &r; + dim = Skyline (dim.direction ()); + dim.set_minimum_height (0.0); } - return Side_position_interface::aligned_side (unsmob_grob (smob), a, pure, start, end, current_off_ptr); -} + // Ditto - seems kludgy, but this time logic of SystemStartBrackets + if (my_dim.is_empty ()) + { + my_dim = Skyline (my_dim.direction ()); + my_dim.set_minimum_height (isinf (max_raise) ? 0.0 : max_raise); + } -MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Side_position_interface, x_aligned_side, 2, 1, ""); -SCM -Side_position_interface::x_aligned_side (SCM smob, SCM current_off) -{ - return axis_aligned_side_helper (smob, X_AXIS, false, 0, 0, current_off); -} + // Many cross-staff grobs do not have good height estimations. + // We give the grob the best chance of not colliding by shifting + // it to the maximum height in the case of cross-staff alignment. + // This means, in other words, that the old way things were done + // (using boxes instead of skylines) is just reactivated for + // alignment to cross-staff grobs. + if (aligns_to_cross_staff) + dim.set_minimum_height (dim.max_height ()); -MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Side_position_interface, y_aligned_side, 2, 1, ""); -SCM -Side_position_interface::y_aligned_side (SCM smob, SCM current_off) -{ - return axis_aligned_side_helper (smob, Y_AXIS, false, 0, 0, current_off); -} + Real ss = Staff_symbol_referencer::staff_space (me); + Real dist = dim.distance (my_dim, robust_scm2double (me->get_property ("horizon-padding"), 0.0)); + Real total_off = !isinf (dist) ? dir * dist : 0.0; -MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Side_position_interface, pure_y_aligned_side, 4, 1, ""); -SCM -Side_position_interface::pure_y_aligned_side (SCM smob, SCM start, SCM end, SCM cur_off) -{ - return axis_aligned_side_helper (smob, Y_AXIS, true, - scm_to_int (start), - scm_to_int (end), - cur_off); -} + total_off += dir * ss * robust_scm2double (me->get_property ("padding"), 0.0); -MAKE_SCHEME_CALLBACK (Side_position_interface, calc_cross_staff, 1) -SCM -Side_position_interface::calc_cross_staff (SCM smob) -{ - Grob *me = unsmob_grob (smob); - extract_grob_set (me, "side-support-elements", elts); + Real minimum_space = ss * robust_scm2double (me->get_property ("minimum-space"), -1); - for (vsize i = 0; i < elts.size (); i++) - if (to_boolean (elts[i]->get_property ("cross-staff"))) - return SCM_BOOL_T; + if (minimum_space >= 0 + && dir + && total_off * dir < minimum_space) + total_off = minimum_space * dir; - Grob *common = common_refpoint_of_array (elts, me->get_parent (Y_AXIS), Y_AXIS); - return scm_from_bool (common != me->get_parent (Y_AXIS)); -} + if (current_off) + total_off = dir * max (dir * total_off, + dir * (*current_off)); -SCM -Side_position_interface::aligned_side (Grob *me, Axis a, bool pure, int start, int end, - Real *current_off) -{ - Direction dir = get_grob_direction (me); - bool skyline = to_boolean (me->get_property ("use-skylines")); + /* FIXME: 1000 should relate to paper size. */ + if (fabs (total_off) > 1000) + { + string msg + = String_convert::form_string ("Improbable offset for grob %s: %f", + me->name ().c_str (), total_off); - Real o = scm_to_double (skyline && !pure - ? skyline_side_position (me, a, pure, start, end, current_off) - : general_side_position (me, a, true, true, pure, start, end, current_off)); + programming_error (msg); + if (strict_infinity_checking) + scm_misc_error (__FUNCTION__, "Improbable offset.", SCM_EOL); + } /* Maintain a minimum distance to the staff. This is similar to side @@ -429,7 +381,7 @@ Side_position_interface::aligned_side (Grob *me, Axis a, bool pure, int start, i 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 position = 2 * (my_off + total_off - staff_off) / ss; Real rounded = directed_round (position, dir); Grob *head = me->get_parent (X_AXIS); @@ -441,9 +393,9 @@ Side_position_interface::aligned_side (Grob *me, Axis a, bool pure, int start, i && abs (Staff_symbol_referencer::get_position (head)) > abs (position))) { - o += (rounded - position) * 0.5 * ss; + total_off += (rounded - position) * 0.5 * ss; if (Staff_symbol_referencer::on_line (me, int (rounded))) - o += dir * 0.5 * ss; + total_off += dir * 0.5 * ss; } } else if (scm_is_number (me->get_property ("staff-padding")) && dir) @@ -460,12 +412,12 @@ Side_position_interface::aligned_side (Grob *me, Axis a, bool pure, int start, i Real staff_position = staff->maybe_pure_coordinate (common, Y_AXIS, pure, start, end); Interval staff_extent = staff->maybe_pure_extent (staff, a, pure, start, end); Real diff = (dir * staff_extent[dir] + staff_padding - - dir * (o + iv[-dir]) + - dir * (total_off + iv[-dir]) + dir * (staff_position - parent_position)); - o += dir * max (diff, 0.0); + total_off += dir * max (diff, 0.0); } } - return scm_from_double (o); + return scm_from_double (total_off); } void @@ -552,6 +504,7 @@ ADD_INTERFACE (Side_position_interface, "add-stem-support " "direction " "minimum-space " + "horizon-padding " "padding " "quantize-position " "side-axis " diff --git a/lily/skyline.cc b/lily/skyline.cc index 1d6e4d5e78..ed5f390a01 100644 --- a/lily/skyline.cc +++ b/lily/skyline.cc @@ -213,6 +213,7 @@ Skyline::normalize () { bool last_empty = false; list::iterator i; + for (i = buildings_.begin (); i != buildings_.end (); i++) { if (last_empty && i->y_intercept_ == -infinity_f) @@ -330,11 +331,13 @@ single_skyline (Building b, list *const ret) { if (b.end_ > b.start_ + EPS) { - ret->push_back (Building (-infinity_f, -infinity_f, - -infinity_f, b.start_)); + if (b.start_ != -infinity_f) + ret->push_back (Building (-infinity_f, -infinity_f, + -infinity_f, b.start_)); ret->push_back (b); - ret->push_back (Building (b.end_, -infinity_f, - -infinity_f, infinity_f)); + if (b.end_ != infinity_f) + ret->push_back (Building (b.end_, -infinity_f, + -infinity_f, infinity_f)); } else { @@ -553,6 +556,7 @@ Skyline::Skyline (Box const &b, Axis horizon_axis, Direction sky) sky_ = sky; Building front (b, horizon_axis, sky); single_skyline (front, &buildings_); + normalize (); } void @@ -766,6 +770,12 @@ Skyline::max_height () const return sky_ * ret; } +Direction +Skyline::direction () const +{ + return sky_; +} + Real Skyline::left () const { diff --git a/lily/stencil-integral.cc b/lily/stencil-integral.cc index d8509a6286..601893b5cb 100644 --- a/lily/stencil-integral.cc +++ b/lily/stencil-integral.cc @@ -50,10 +50,12 @@ when this transforms a point (x,y), the point is written as matrix: #include "pointer-group-interface.hh" #include "lily-guile.hh" #include "real.hh" +#include "rest.hh" #include "stencil.hh" #include "string-convert.hh" #include "skyline.hh" #include "skyline-pair.hh" +#include "spanner.hh" using namespace std; Real QUANTIZATION_UNIT = 0.2; @@ -192,12 +194,11 @@ make_draw_line_boxes (vector &boxes, vector > &buildings do { Offset inter_l = get_point_in_y_direction (left, perpendicular_slope (slope), thick / 2, d); - Offset inter_r = get_point_in_y_direction (right, perpendicular_slope (slope), thick / 2, d);//printf ("O %4.4f %4.4f\n", inter_l[X_AXIS], inter_r[X_AXIS]);printf ("TRANNY %4.4f %4.4f %4.4f %4.4f %4.4f %4.4f\n", trans.xx, trans.xy, trans.yx, trans.yy, trans.x0, trans.y0); + Offset inter_r = get_point_in_y_direction (right, perpendicular_slope (slope), thick / 2, d); pango_matrix_transform_point (&trans, &inter_l[X_AXIS], &inter_l[Y_AXIS]); pango_matrix_transform_point (&trans, &inter_r[X_AXIS], &inter_r[Y_AXIS]); if ((inter_l[X_AXIS] == inter_r[X_AXIS]) || (inter_l[Y_AXIS] == inter_r[Y_AXIS])) { - //printf ("OO %4.4f %4.4f\n", inter_l[X_AXIS], inter_r[X_AXIS]); Box b; b.add_point (inter_l); b.add_point (inter_r); @@ -964,38 +965,73 @@ stencil_traverser (PangoMatrix trans, SCM expr) } SCM -Grob::internal_simple_skylines_from_stencil (SCM smob, Axis a) +Grob::maybe_pure_internal_simple_skylines_from_extents (Grob *me, Axis a, bool pure, int beg, int end, bool ignore_x, bool ignore_y) { - Grob *me = unsmob_grob (smob); - - if (to_boolean (me->get_property ("cross-staff"))) + vector boxes; + // we don't know how far spanners stretch along the X axis before + // line breaking. better have them take up the whole thing + Interval xex = ignore_x + ? Interval (-infinity_f, infinity_f) + : me->extent (me, X_AXIS); + + // If we're looking at the x exent of a cross staff grob, it could be + // very early on in the computation process. We won't know its height + // until way later, so we give a brute force approximation. + Interval yex = ignore_y + ? Interval (-infinity_f, infinity_f) + : me->maybe_pure_extent (me, Y_AXIS, pure, beg, end); + + // In horizontal spacing, there are grobs like SystemStartBracket + // that take up no vertical spcae. So, if the y extent is empty, + // we use the entire Y extent ot make the X a sort of horizontal wall. + // Ditto for vertical spacing and grobs like BassFigureAlginmentPositioning. + if (a == Y_AXIS && yex.is_empty ()) + yex.set_full (); + + if (a == X_AXIS && xex.is_empty ()) + xex.set_full (); + + if (xex.is_empty () || yex.is_empty ()) return Skyline_pair ().smobbed_copy (); - extract_grob_set (me, "elements", elts); - if (elts.size ()) - return internal_skylines_from_element_stencils (smob, a); + boxes.push_back (Box (xex, yex)); + return Skyline_pair (boxes, a).smobbed_copy (); +} - Stencil *s = unsmob_stencil (me->get_property ("stencil")); - if (!s) - return Skyline_pair ().smobbed_copy (); +MAKE_SCHEME_CALLBACK (Grob, pure_simple_vertical_skylines_from_extents, 3); +SCM +Grob::pure_simple_vertical_skylines_from_extents (SCM smob, SCM begscm, SCM endscm) +{ + Grob *me = unsmob_grob (smob); + int beg = robust_scm2int (begscm, 0); + int end = robust_scm2int (endscm, INT_MAX); + return maybe_pure_internal_simple_skylines_from_extents (me, X_AXIS, true, beg, end, dynamic_cast (me), false); +} - vector boxes; - boxes.push_back (Box (s->extent (X_AXIS), s->extent (Y_AXIS))); - return Skyline_pair (boxes, a).smobbed_copy (); +MAKE_SCHEME_CALLBACK (Grob, simple_vertical_skylines_from_extents, 1); +SCM +Grob::simple_vertical_skylines_from_extents (SCM smob) +{ + Grob *me = unsmob_grob (smob); + return maybe_pure_internal_simple_skylines_from_extents (me, X_AXIS, false, 0, 0, false, false); } -MAKE_SCHEME_CALLBACK (Grob, simple_vertical_skylines_from_stencil, 1); +MAKE_SCHEME_CALLBACK (Grob, pure_simple_horizontal_skylines_from_extents, 3); SCM -Grob::simple_vertical_skylines_from_stencil (SCM smob) +Grob::pure_simple_horizontal_skylines_from_extents (SCM smob, SCM begscm, SCM endscm) { - return internal_simple_skylines_from_stencil (smob, X_AXIS); + Grob *me = unsmob_grob (smob); + int beg = robust_scm2int (begscm, 0); + int end = robust_scm2int (endscm, INT_MAX); + return maybe_pure_internal_simple_skylines_from_extents (me, Y_AXIS, true, beg, end, false, to_boolean (me->get_property ("cross-staff"))); } -MAKE_SCHEME_CALLBACK (Grob, simple_horizontal_skylines_from_stencil, 1); +MAKE_SCHEME_CALLBACK (Grob, simple_horizontal_skylines_from_extents, 1); SCM -Grob::simple_horizontal_skylines_from_stencil (SCM smob) +Grob::simple_horizontal_skylines_from_extents (SCM smob) { - return internal_simple_skylines_from_stencil (smob, Y_AXIS); + Grob *me = unsmob_grob (smob); + return maybe_pure_internal_simple_skylines_from_extents (me, Y_AXIS, false, 0, 0, false, to_boolean (me->get_property ("cross-staff"))); } SCM diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm index 0b5585a71a..c1a3a723cb 100644 --- a/scm/define-grob-properties.scm +++ b/scm/define-grob-properties.scm @@ -489,6 +489,9 @@ units.") slur, the closer it is to this height.") (hide-tied-accidental-after-break ,boolean? "If set, an accidental that appears on a tied note after a line break will not be displayed.") + (horizon-padding ,number? "The amount to pad the axis +along which a @code{Skyline} is built for the +@code{side-position-interface}.") (horizontal-shift ,integer? "An integer that identifies ranking of @code{NoteColumn}s for horizontal shifting. This is used by @rinternals{note-collision-interface}.") diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index 74040cd60d..47db681b6a 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -83,7 +83,6 @@ (side-axis . ,Y) (staff-padding . 0.25) (stencil . ,ly:accidental-interface::print) - (use-skylines . #t) (X-extent . ,ly:accidental-interface::width) (X-offset . ,(ly:make-simple-closure `(,+ @@ -249,6 +248,9 @@ (font-family . roman) (font-size . -2) (non-musical . #t) + ;; w/o padding, bars numbers are not positioned over the staff as + ;; they are slightly to the left. so we add just a bit. + (horizon-padding . 0.05) (outside-staff-priority . 100) (padding . 1.0) (self-alignment-X . ,RIGHT) @@ -611,6 +613,7 @@ (next-note . (extra-space . 1.0)) (right-edge . (extra-space . 0.5)))) (stencil . ,ly:clef::print) + (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil) (Y-offset . ,ly:staff-symbol-referencer::callback) (meta . ((class . Item) (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common) @@ -760,7 +763,6 @@ (slur-padding . 0.3) (staff-padding . 0.1) (vertical-skylines . ,ly:grob::vertical-skylines-from-element-stencils) - (use-skylines . #t) (X-extent . ,ly:axis-group-interface::width) (Y-extent . ,ly:axis-group-interface::height) (Y-offset . ,ly:side-position-interface::y-aligned-side) @@ -793,7 +795,6 @@ (X-offset . ,ly:self-alignment-interface::x-aligned-on-self) (Y-offset . ,ly:self-alignment-interface::y-aligned-on-self) (meta . ((class . Item) - (object-callbacks . ((X-colliding-grobs . ,ly:self-alignment-interface::x-colliding-grobs))) (interfaces . (dynamic-interface dynamic-text-interface font-interface @@ -882,7 +883,7 @@ . ( ;; sync with TextScript (?) - + (add-stem-support . ,only-if-beamed) (avoid-slur . around) (cross-staff . ,script-or-side-position-cross-staff) (direction . ,ly:script-interface::calc-direction) @@ -1411,6 +1412,7 @@ (thick-thickness . 6.6) ;; See Wanske pp. 125 (usable-duration-logs . ,(iota 4 -3)) + (Y-extent . ,ly:multi-measure-rest::height) (Y-offset . ,ly:staff-symbol-referencer::callback) (meta . ((class . Spanner) (interfaces . (font-interface @@ -1437,6 +1439,7 @@ ,(ly:make-simple-closure (list ly:self-alignment-interface::x-centered-on-y-parent))))) (Y-offset . ,ly:side-position-interface::y-aligned-side) + (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil) (meta . ((class . Spanner) (interfaces . (font-interface multi-measure-interface @@ -1459,6 +1462,7 @@ ,(ly:make-simple-closure (list ly:self-alignment-interface::x-aligned-on-self))))) (Y-offset . ,ly:side-position-interface::y-aligned-side) + (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil) (meta . ((class . Spanner) (interfaces . (font-interface multi-measure-interface @@ -1512,6 +1516,7 @@ . ( (axes . (,X ,Y)) (bound-alignment-interfaces . (rhythmic-head-interface stem-interface)) + (cross-staff . ,ly:axis-group-interface::cross-staff) (horizontal-skylines . ,ly:separation-item::calc-skylines) (skyline-vertical-padding . 0.15) (X-extent . ,ly:axis-group-interface::width) @@ -1582,6 +1587,7 @@ ,(ly:make-simple-closure (list ly:self-alignment-interface::centered-on-x-parent))))) (Y-offset . ,ly:side-position-interface::y-aligned-side) + (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil) (meta . ((class . Item) (interfaces . (font-interface octavate-eight-interface @@ -1796,6 +1802,7 @@ (X-extent . ,ly:rest::width) (Y-extent . ,ly:rest::height) (Y-offset . ,ly:rest::y-offset-callback) + (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil) (meta . ((class . Item) (interfaces . (font-interface rest-interface @@ -1825,7 +1832,6 @@ (staff-padding . 0.25) (stencil . ,ly:script-interface::print) - (use-skylines . #t) (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil) (X-offset . ,script-interface::calc-x-offset) (Y-offset . ,ly:side-position-interface::y-aligned-side) @@ -1885,6 +1891,7 @@ (SostenutoPedalLineSpanner . ( (axes . (,Y)) + (cross-staff . ,ly:side-position-interface::calc-cross-staff) (direction . ,DOWN) (minimum-space . 1.0) (outside-staff-priority . 1000) @@ -2128,6 +2135,7 @@ (SustainPedalLineSpanner . ( (axes . (,Y)) + (cross-staff . ,ly:side-position-interface::calc-cross-staff) (direction . ,DOWN) (minimum-space . 1.0) (outside-staff-priority . 1000) @@ -2270,7 +2278,7 @@ (outside-staff-priority . 450) ;; sync with Fingering ? - (padding . 0.5) + (padding . 0.3) (script-priority . 200) (side-axis . ,Y) @@ -2524,6 +2532,7 @@ (UnaCordaPedalLineSpanner . ( (axes . (,Y)) + (cross-staff . ,ly:side-position-interface::calc-cross-staff) (direction . ,DOWN) (minimum-space . 1.0) (outside-staff-priority . 1000) @@ -2777,7 +2786,13 @@ (,ly:axis-group-interface::height . ,ly:axis-group-interface::pure-height) (,ly:beam::rest-collision-callback . ,ly:beam::pure-rest-collision-callback) (,ly:flag::calc-y-offset . ,ly:flag::pure-calc-y-offset) + (,ly:grob::horizontal-skylines-from-stencil . ,ly:grob::pure-simple-horizontal-skylines-from-extents) + (,ly:grob::horizontal-skylines-from-element-stencils . ,ly:grob::pure-simple-horizontal-skylines-from-extents) + (,ly:grob::simple-horizontal-skylines-from-extents . ,ly:grob::pure-simple-horizontal-skylines-from-extents) + (,ly:grob::simple-vertical-skylines-from-extents . ,ly:grob::pure-simple-vertical-skylines-from-extents) (,ly:grob::stencil-height . ,pure-stencil-height) + (,ly:grob::vertical-skylines-from-stencil . ,ly:grob::pure-simple-vertical-skylines-from-extents) + (,ly:grob::vertical-skylines-from-element-stencils . ,ly:grob::pure-simple-vertical-skylines-from-extents) (,ly:hara-kiri-group-spanner::y-extent . ,ly:hara-kiri-group-spanner::pure-height) (,ly:rest-collision::force-shift-callback-rest . ,pure-chain-offset-callback) (,ly:rest::height . ,ly:rest::pure-height) @@ -2794,8 +2809,10 @@ (define pure-functions (list + ly:accidental-interface::horizontal-skylines parenthesize-elements laissez-vibrer::print + ly:multi-measure-rest::height ly:rest::y-offset-callback ly:staff-symbol-referencer::callback ly:staff-symbol::height)) diff --git a/scm/lily-library.scm b/scm/lily-library.scm index cd9fb5b9a2..5519bb8263 100644 --- a/scm/lily-library.scm +++ b/scm/lily-library.scm @@ -677,6 +677,15 @@ right (@var{dir}=+1)." (define-public (reverse-interval iv) (cons (cdr iv) (car iv))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; boolean + +(define (lily-and a b) + (and a b)) + +(define (lily-or a b) + (or a b)) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; coordinates diff --git a/scm/output-lib.scm b/scm/output-lib.scm index c6ed83e6e0..c83fd27ed6 100644 --- a/scm/output-lib.scm +++ b/scm/output-lib.scm @@ -51,6 +51,14 @@ ((ly:grob? cause) (event-cause cause)) (else #f)))) +(define-public (non-event-cause grob) + (let ((cause (ly:grob-property grob 'cause))) + + (cond + ((ly:stream-event? cause) (non-event-cause cause)) + ((ly:grob? cause) cause) + (else #f)))) + (define-public (grob-interpret-markup grob text) (let* ((layout (ly:grob-layout grob)) (defs (ly:output-def-lookup layout 'text-font-defaults)) @@ -184,6 +192,17 @@ (ly:side-position-interface::calc-cross-staff g))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; side-position stuff + +(define-public (only-if-beamed g) + (reduce lily-or + #f + (map (lambda (x) + (ly:grob? (ly:grob-object x 'beam))) + (ly:grob-array->list (ly:grob-object g + 'side-support-elements))))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; note heads @@ -926,6 +945,9 @@ between the two text elements." (define-public ((grob::calc-property-by-copy prop) grob) (ly:event-property (event-cause grob) prop)) +(define-public ((grob::calc-property-by-non-event-cause prop) grob) + (ly:grob-property (non-event-cause grob) prop)) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; fret boards -- 2.39.2