From: Joe Neeman Date: Wed, 4 Jul 2007 09:32:22 +0000 (+1000) Subject: Merge branch 'master' into jneeman X-Git-Tag: release/2.11.28-1~21^2~15 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=b80683cc94b0c22bbe3fccb94a9b2e23787fd10b;hp=7aa8cea7bbf7c0a7ed419173619002f1357f9887;p=lilypond.git Merge branch 'master' into jneeman --- diff --git a/Documentation/user/advanced-notation.itely b/Documentation/user/advanced-notation.itely index e7cd36b3a2..726f66c710 100644 --- a/Documentation/user/advanced-notation.itely +++ b/Documentation/user/advanced-notation.itely @@ -354,15 +354,15 @@ bar lines, c1 \key cis \major \clef alto - \override Score.RehearsalMark #'break-align-symbol = #'key-signature + \override Score.RehearsalMark #'break-align-symbols = #'(key-signature) \mark "on key" cis \key ces \major - \override Score.RehearsalMark #'break-align-symbol = #'clef + \override Score.RehearsalMark #'break-align-symbols = #'(clef) \clef treble \mark "on clef" ces - \override Score.RehearsalMark #'break-align-symbol = #'time-signature + \override Score.RehearsalMark #'break-align-symbols = #'(time-signature) \key d \minor \clef tenor \time 3/4 @@ -371,6 +371,35 @@ bar lines, } @end lilypond +The text marks will, by default, be aligned with the middle of the notation +object, but this can be changed by overriding the +@code{break-align-anchor-alignment} and +@code{break-align-anchor} properties for the appropriate grob. + +@lilypond[fragment,quote,ragged-right,verbatim] +{ + \override Score.RehearsalMark #'break-align-symbols = #'(key-signature) + c1 + \key cis \major + + % the RehearsalMark will be aligned with the left edge of the KeySignature + \once \override Staff.KeySignature #'break-align-anchor-alignment = #LEFT + \mark \default + cis1 + \key ces \major + + % the RehearsalMark will be aligned with the right edge of the KeySignature + \once \override Staff.KeySignature #'break-align-anchor-alignment = #RIGHT + \mark \default + ces1 + + % the RehearsalMark will be aligned with the right edge of the KeySignature + % and then shifted right by an additional 2 units. + \once \override Staff.KeySignature #'break-align = #2 + \mark \default + ces1 +} + Although text marks are normally only printed above the topmost staff, you may alter this to print them on every staff, diff --git a/input/regression/dynamics-hairpin-length.ly b/input/regression/dynamics-hairpin-length.ly index ef00c6418f..c7f280bfc6 100644 --- a/input/regression/dynamics-hairpin-length.ly +++ b/input/regression/dynamics-hairpin-length.ly @@ -1,7 +1,7 @@ \header { texidoc = "Hairpins extend to the extremes of the bound if there - is no adjacent hairpin of dynamic-text. If there is, the hairpin + is no adjacent hairpin or dynamic-text. If there is, the hairpin extends to the center of the column or the bound of the text respectively." diff --git a/input/regression/fill-line-test.ly b/input/regression/fill-line-test.ly index 888390e655..66b9512642 100644 --- a/input/regression/fill-line-test.ly +++ b/input/regression/fill-line-test.ly @@ -3,7 +3,7 @@ \header { texidoc = "The fill-line markup command should align texts in - columns. For examlpe, the characters in the center should form one + columns. For example, the characters in the center should form one column." } diff --git a/input/regression/finger-chords.ly b/input/regression/finger-chords.ly index bf000a7061..3b966ebd72 100644 --- a/input/regression/finger-chords.ly +++ b/input/regression/finger-chords.ly @@ -2,7 +2,7 @@ \version "2.10.0" \header { - texidoc = "With the new chord syntax, it is possible to associate + texidoc = "It is possible to associate fingerings uniquely with notes. This makes it possible to add horizontal fingerings to notes. diff --git a/input/regression/spacing-accidental-stretch.ly b/input/regression/spacing-accidental-stretch.ly index f8f6bb41ae..f862dc8a2f 100644 --- a/input/regression/spacing-accidental-stretch.ly +++ b/input/regression/spacing-accidental-stretch.ly @@ -11,7 +11,7 @@ The accidental does add a little non-stretchable space. \layout { line-width = 18.\cm } -\relative c'' \context GrandStaff { +\relative c'' { #(set-accidental-style 'piano-cautionary) \time 2/4 d16 d d d d d cis d dis dis dis dis diff --git a/input/regression/spacing-bar-arpeggio.ly b/input/regression/spacing-bar-arpeggio.ly index fd84be5a9b..8318b5f24a 100644 --- a/input/regression/spacing-bar-arpeggio.ly +++ b/input/regression/spacing-bar-arpeggio.ly @@ -12,5 +12,5 @@ \override Score.NonMusicalPaperColumn #'layer = #1 s1 - 1\arpeggio + 2\arpeggio } diff --git a/lily/accidental-engraver.cc b/lily/accidental-engraver.cc index 351ab2045a..910c62d282 100644 --- a/lily/accidental-engraver.cc +++ b/lily/accidental-engraver.cc @@ -17,6 +17,7 @@ #include "pitch.hh" #include "protected-scm.hh" #include "rhythmic-head.hh" +#include "separation-item.hh" #include "side-position-interface.hh" #include "stream-event.hh" #include "tie.hh" @@ -64,6 +65,7 @@ protected: void acknowledge_arpeggio (Grob_info); void acknowledge_rhythmic_head (Grob_info); void acknowledge_finger (Grob_info); + void acknowledge_note_column (Grob_info); void stop_translation_timestep (); void process_acknowledged (); @@ -81,6 +83,7 @@ public: vector accidentals_; vector ties_; + vector note_columns_; }; /* @@ -521,6 +524,10 @@ Accidental_engraver::stop_translation_timestep () } } + if (accidental_placement_) + for (vsize i = 0; i < note_columns_.size (); i++) + Separation_item::add_conditional_item (note_columns_[i], accidental_placement_); + accidental_placement_ = 0; accidentals_.clear (); left_objects_.clear (); @@ -558,6 +565,12 @@ Accidental_engraver::acknowledge_tie (Grob_info info) ties_.push_back (dynamic_cast (info.grob ())); } +void +Accidental_engraver::acknowledge_note_column (Grob_info info) +{ + note_columns_.push_back (info.grob ()); +} + void Accidental_engraver::acknowledge_arpeggio (Grob_info info) { @@ -582,6 +595,7 @@ ADD_ACKNOWLEDGER (Accidental_engraver, arpeggio); ADD_ACKNOWLEDGER (Accidental_engraver, finger); ADD_ACKNOWLEDGER (Accidental_engraver, rhythmic_head); ADD_ACKNOWLEDGER (Accidental_engraver, tie); +ADD_ACKNOWLEDGER (Accidental_engraver, note_column); ADD_TRANSLATOR (Accidental_engraver, diff --git a/lily/accidental-placement.cc b/lily/accidental-placement.cc index 8e75206dc8..bb1419977e 100644 --- a/lily/accidental-placement.cc +++ b/lily/accidental-placement.cc @@ -76,54 +76,23 @@ Accidental_placement::split_accidentals (Grob *accs, } vector -Accidental_placement::get_break_reminder_accidentals (vector const &elts, Grob *left) +Accidental_placement::get_relevant_accidentals (vector const &elts, Grob *left) { vector br; vector ra; vector ret; - - if (dynamic_cast (left)->break_status_dir () != RIGHT) - return vector (); + bool right = dynamic_cast (left)->break_status_dir () == RIGHT; for (vsize i = 0; i < elts.size (); i++) { split_accidentals (elts[i], &br, &ra); - ret.insert (ret.end (), br.begin (), br.end ()); - } - return ret; -} - -/* - Accidentals are special, because they appear and disappear after - ties at will. -*/ -Interval -Accidental_placement::get_relevant_accidental_extent (Grob *me, - Item *item_col, - Grob *left_object) -{ - vector br, ra; - vector *which = 0; - - Accidental_placement::split_accidentals (me, &br, &ra); - concat (br, ra); - - if (dynamic_cast (left_object)->break_status_dir () == RIGHT) - which = &br; - else - which = &ra; - - Interval extent; - for (vsize i = 0; i < which->size (); i++) - extent.unite (which->at (i)->extent (item_col, X_AXIS)); + + ret.insert (ret.end (), ra.begin (), ra.end ()); - if (!extent.is_empty ()) - { - Real p = robust_scm2double (me->get_property ("left-padding"), 0.2); - extent[LEFT] -= p; + if (right) + ret.insert (ret.end (), br.begin (), br.end ()); } - - return extent; + return ret; } struct Accidental_placement_entry diff --git a/lily/arpeggio-engraver.cc b/lily/arpeggio-engraver.cc index 0528f71d9f..399823408f 100644 --- a/lily/arpeggio-engraver.cc +++ b/lily/arpeggio-engraver.cc @@ -26,7 +26,6 @@ public: void acknowledge_stem (Grob_info); void acknowledge_rhythmic_head (Grob_info); - void acknowledge_note_column (Grob_info); protected: void process_music (); void stop_translation_timestep (); @@ -73,13 +72,6 @@ Arpeggio_engraver::acknowledge_rhythmic_head (Grob_info info) Side_position_interface::add_support (arpeggio_, info.grob ()); } -void -Arpeggio_engraver::acknowledge_note_column (Grob_info info) -{ - if (arpeggio_) - info.grob ()->set_object ("arpeggio", arpeggio_->self_scm ()); -} - void Arpeggio_engraver::process_music () { @@ -98,7 +90,6 @@ Arpeggio_engraver::stop_translation_timestep () ADD_ACKNOWLEDGER (Arpeggio_engraver, stem); ADD_ACKNOWLEDGER (Arpeggio_engraver, rhythmic_head); -ADD_ACKNOWLEDGER (Arpeggio_engraver, note_column); ADD_TRANSLATOR (Arpeggio_engraver, /* doc */ "Generate an Arpeggio symbol", diff --git a/lily/axis-group-interface.cc b/lily/axis-group-interface.cc index da08f53526..b9641d41c3 100644 --- a/lily/axis-group-interface.cc +++ b/lily/axis-group-interface.cc @@ -478,7 +478,7 @@ add_boxes (Grob *me, Grob *x_common, Grob *y_common, vector *const boxes, S positions, one for above the staff, one for below). In each pass, we loop through the unplaced grobs from left to right. - If the grob overlaps the right-most affected position, we place it + If the grob doesn't overlap the right-most affected position, we place it (and then update the right-most affected position to point to the right edge of the just-placed grob). Otherwise, we skip it until the next pass. */ diff --git a/lily/dot-column.cc b/lily/dot-column.cc index 36c9513797..1698ef51eb 100644 --- a/lily/dot-column.cc +++ b/lily/dot-column.cc @@ -36,6 +36,13 @@ Dot_column::calc_positioning_done (SCM smob) { Grob *me = unsmob_grob (smob); + /* + Trigger note collision resolution first, since that may kill off + dots when merging. + */ + if (Grob *collision = unsmob_grob (me->get_object ("note-collision"))) + (void) collision->get_property ("positioning-done"); + me->set_property ("positioning-done", SCM_BOOL_T); vector dots @@ -45,24 +52,19 @@ Dot_column::calc_positioning_done (SCM smob) Real ss = 0; Grob *commonx = me; - { /* - Trigger note collision resolution first, since that may kill off - dots when merging. - */ - for (vsize i = 0; i < dots.size (); i++) - { - Grob *n = dots[i]->get_parent (Y_AXIS); - commonx = n->common_refpoint (commonx, X_AXIS); - - if (Grob *stem = unsmob_grob (n->get_object("stem"))) - { - commonx = stem->common_refpoint (commonx, X_AXIS); - - if (Stem::first_head (stem) == n) - main_heads.push_back (n); - } - } - } + for (vsize i = 0; i < dots.size (); i++) + { + Grob *n = dots[i]->get_parent (Y_AXIS); + commonx = n->common_refpoint (commonx, X_AXIS); + + if (Grob *stem = unsmob_grob (n->get_object("stem"))) + { + commonx = stem->common_refpoint (commonx, X_AXIS); + + if (Stem::first_head (stem) == n) + main_heads.push_back (n); + } + } vector boxes; set stems; diff --git a/lily/dynamic-engraver.cc b/lily/dynamic-engraver.cc index 18ebeda943..5de7516024 100644 --- a/lily/dynamic-engraver.cc +++ b/lily/dynamic-engraver.cc @@ -344,16 +344,9 @@ Dynamic_engraver::typeset_all () || use_bar) { - Grob *column_bound = 0; - if (use_bar) - { - column_bound = unsmob_grob (get_property ("breakableSeparationItem")); - } - - if (!column_bound) - column_bound = unsmob_grob (use_bar - ? get_property ("currentCommandColumn") - : get_property ("currentMusicalColumn")); + Grob *column_bound = unsmob_grob (use_bar + ? get_property ("currentCommandColumn") + : get_property ("currentMusicalColumn")); finished_cresc_->set_bound (RIGHT, script_ ? script_ diff --git a/lily/grob.cc b/lily/grob.cc index 495fe2437f..34b742e7f5 100644 --- a/lily/grob.cc +++ b/lily/grob.cc @@ -288,16 +288,23 @@ Grob::pure_relative_y_coordinate (Grob const *refp, int start, int end) Real off = 0; if (dim_cache_[Y_AXIS].offset_) - off = *dim_cache_[Y_AXIS].offset_; + { + if (to_boolean (get_property ("pure-Y-offset-in-progress"))) + programming_error ("cyclic chain in pure-Y-offset callbacks"); + + off = *dim_cache_[Y_AXIS].offset_; + } else { SCM proc = get_property_data ("Y-offset"); dim_cache_[Y_AXIS].offset_ = new Real (0.0); + set_property ("pure-Y-offset-in-progress", SCM_BOOL_T); off = robust_scm2double (call_pure_function (proc, scm_list_1 (self_scm ()), start, end), 0.0); + del_property ("pure-Y-offset-in-progress"); delete dim_cache_[Y_AXIS].offset_; dim_cache_[Y_AXIS].offset_ = 0; } @@ -625,6 +632,7 @@ ADD_INTERFACE (Grob, "outside-staff-horizontal-padding " "outside-staff-padding " "outside-staff-priority " + "pure-Y-offset-in-progress " "rotation " "springs-and-rods " "staff-symbol " diff --git a/lily/include/accidental-placement.hh b/lily/include/accidental-placement.hh index f6c17621ed..99281a5b14 100644 --- a/lily/include/accidental-placement.hh +++ b/lily/include/accidental-placement.hh @@ -18,11 +18,7 @@ public: DECLARE_SCHEME_CALLBACK (alignment_callback, (SCM element)); static void add_accidental (Grob *, Grob *); - static vector get_break_reminder_accidentals (vector const &elts, - Grob *left); - static Interval get_relevant_accidental_extent (Grob *me, - Item *item_col, - Grob *acc); + static vector get_relevant_accidentals (vector const &elts, Grob *left); static void split_accidentals (Grob *accs, vector *break_reminder, vector *real_acc); diff --git a/lily/include/note-column.hh b/lily/include/note-column.hh index 8646f120fe..34a30ab5dd 100644 --- a/lily/include/note-column.hh +++ b/lily/include/note-column.hh @@ -30,7 +30,6 @@ public: static Grob *first_head (Grob *me); static Grob *get_rest (Grob *me); static void set_stem (Grob *me, Grob *); - static void set_dotcol (Grob *me, Grob *); static void add_head (Grob *me, Grob *); static bool has_rests (Grob *me); static Grob *dot_column (Grob *me); diff --git a/lily/include/note-spacing.hh b/lily/include/note-spacing.hh index af04260cea..a14c43c8b7 100644 --- a/lily/include/note-spacing.hh +++ b/lily/include/note-spacing.hh @@ -11,17 +11,16 @@ #include "grob-interface.hh" #include "lily-proto.hh" +#include "spring.hh" class Note_spacing { public: DECLARE_GROB_INTERFACE(); - static void get_spacing (Grob *me, Item *, Real, Real, Real *, Real *); + static Spring get_spacing (Grob *me, Item *, Real, Real); static void stem_dir_correction (Grob *me, Item *next_col, Real incr, Real *, Real *); - static Item *right_column (Grob *); - static Item *left_column (Grob *); }; #endif /* NOTE_SPACING_HH */ diff --git a/lily/include/paper-column.hh b/lily/include/paper-column.hh index 0157eb6bb9..9109e4e697 100644 --- a/lily/include/paper-column.hh +++ b/lily/include/paper-column.hh @@ -48,6 +48,7 @@ public: static Moment when_mom (Grob *); static bool is_used (Grob *); static bool is_breakable (Grob *); + static Real minimum_distance (Grob *l, Grob *r); }; #endif // PAPER_COLUMN_HH diff --git a/lily/include/separating-group-spanner.hh b/lily/include/separating-group-spanner.hh deleted file mode 100644 index d48705c859..0000000000 --- a/lily/include/separating-group-spanner.hh +++ /dev/null @@ -1,29 +0,0 @@ -/* - separating-group-spanner.hh -- declare Separating_group_spanner - - source file of the GNU LilyPond music typesetter - - (c) 1998--2007 Han-Wen Nienhuys -*/ - -#ifndef SEPARATING_GROUP_SPANNER_HH -#define SEPARATING_GROUP_SPANNER_HH - -#include "grob-interface.hh" -#include "lily-proto.hh" - -class Separating_group_spanner -{ - static void find_rods (Item *, - vector const &separators, - vsize idx, - Real); -public: - static void add_spacing_unit (Grob *me, Item *); - - DECLARE_GROB_INTERFACE(); - DECLARE_SCHEME_CALLBACK (set_spacing_rods, (SCM)); -}; - -#endif /* SEPARATING_GROUP_SPANNER_HH */ - diff --git a/lily/include/separation-item.hh b/lily/include/separation-item.hh index 1b2471118d..bf9681957e 100644 --- a/lily/include/separation-item.hh +++ b/lily/include/separation-item.hh @@ -22,11 +22,9 @@ struct Separation_item static vector boxes (Grob *me, Grob *left); static Skyline conditional_skyline (Grob *, Grob *); - static Interval width (Grob *); - static Interval relative_width (Grob *, Grob *); static Grob *extremal_break_aligned_grob (Grob *, Direction, Interval *); - static bool set_distance (Drul_array, Real); - static void set_skyline_distance (Drul_array, Real); + static void set_distance (Drul_array, Real); + static bool is_empty (Grob *me); static void add_item (Grob *, Item *); static void add_conditional_item (Grob *, Grob *); }; diff --git a/lily/include/simple-spacer.hh b/lily/include/simple-spacer.hh index ae3206ac5f..90784e4c74 100644 --- a/lily/include/simple-spacer.hh +++ b/lily/include/simple-spacer.hh @@ -11,30 +11,9 @@ #include "std-vector.hh" #include "lily-proto.hh" +#include "spring.hh" #include "smobs.hh" -struct Spring_description -{ - Real ideal_; - Real inverse_hooke_; - Real block_force_; - - Real length (Real force) const; - Spring_description (); - - bool is_sane () const; - - bool operator> (const Spring_description &s) const - { - return block_force_ > s.block_force_; - } - - bool operator< (const Spring_description &s) const - { - return block_force_ < s.block_force_; - } -}; - class Simple_spacer { public: @@ -42,9 +21,9 @@ public: void solve (Real line_len, bool ragged); void add_rod (int l, int r, Real dist); - void add_spring (Real, Real); + void add_spring (Spring const&); Real range_ideal_len (int l, int r) const; - Real range_stiffness (int l, int r) const; + Real range_stiffness (int l, int r, bool stretch) const; Real configuration_length (Real) const; vector spring_positions () const; @@ -59,7 +38,7 @@ private: Real compress_line (); Real rod_force (int l, int r, Real dist); - vector springs_; + vector springs_; Real line_len_; Real force_; bool ragged_; diff --git a/lily/include/spaceable-grob.hh b/lily/include/spaceable-grob.hh index 5625bfd61e..f7ae552f84 100644 --- a/lily/include/spaceable-grob.hh +++ b/lily/include/spaceable-grob.hh @@ -11,13 +11,14 @@ #include "lily-proto.hh" #include "grob-interface.hh" +#include "spring.hh" struct Spaceable_grob { /// set a minimum distance static void add_rod (Grob *me, Grob *to, Real distance); - static void add_spring (Grob *me, Grob *to, Real dist, Real strength); - static void get_spring (Grob *me, Grob *other, Real *dist, Real *inv_strength); + static void add_spring (Grob *me, Grob *to, Spring sp); + static Spring get_spring (Grob *me, Grob *other); DECLARE_GROB_INTERFACE(); static SCM get_minimum_distances (Grob *); diff --git a/lily/include/spacing-interface.hh b/lily/include/spacing-interface.hh index b558ede709..14b8c2bf03 100644 --- a/lily/include/spacing-interface.hh +++ b/lily/include/spacing-interface.hh @@ -8,8 +8,19 @@ #include "grob-interface.hh" #include "lily-proto.hh" +#ifndef SPACING_INTERFACE_HH +#define SPACING_INTERFACE_HH + struct Spacing_interface { + static Real minimum_distance (Grob *me, Grob *right_col); + static vector right_note_columns (Grob *me); + static vector left_note_columns (Grob *me); + static Item* right_column (Grob *me); + static Item* left_column (Grob *me); + static Drul_array skylines (Grob *me, Grob *right_col); + DECLARE_GROB_INTERFACE(); }; +#endif /* SPACING_INTERFACE_HH */ diff --git a/lily/include/spacing-options.hh b/lily/include/spacing-options.hh index 0b2d30b664..c202c7d64d 100644 --- a/lily/include/spacing-options.hh +++ b/lily/include/spacing-options.hh @@ -31,6 +31,6 @@ struct Spacing_options Spacing_options(); void init_from_grob (Grob *me); - Real get_duration_space (Rational d, bool *) const; + Real get_duration_space (Rational d) const; }; #endif /* SPACING_OPTIONS_HH */ diff --git a/lily/include/spacing-spanner.hh b/lily/include/spacing-spanner.hh index 3018cadebc..9193a187d4 100644 --- a/lily/include/spacing-spanner.hh +++ b/lily/include/spacing-spanner.hh @@ -13,6 +13,7 @@ #include "rational.hh" #include "std-vector.hh" #include "grob-interface.hh" +#include "spring.hh" class Spacing_spanner { @@ -23,7 +24,6 @@ private: Paper_column *nextr, Spacing_options const *options); static Real default_bar_spacing (Grob *, Grob *, Grob *, Moment); - static Real get_duration_space (Moment dur, Spacing_options const *, bool *); static Rational effective_shortest_duration (Grob *me, vector const &all); static void breakable_column_spacing (Grob *, Item *l, Item *r, Spacing_options const *); static void prune_loose_columns (Grob *, vector *cols, Spacing_options *); @@ -34,10 +34,8 @@ private: static bool fills_measure (Grob *, Item *, Item *); public: static vector get_columns (Grob *me); - static Real note_spacing (Grob *, Grob *, Grob *, Spacing_options const *, bool *); - static void standard_breakable_column_spacing (Grob *me, Item *l, Item *r, - Real *fixed, Real *space, - Spacing_options const *); + static Real note_spacing (Grob *, Grob *, Grob *, Spacing_options const *); + static Spring standard_breakable_column_spacing (Grob *me, Item *l, Item *r, Spacing_options const *); DECLARE_SCHEME_CALLBACK (set_springs, (SCM)); DECLARE_SCHEME_CALLBACK (calc_common_shortest_duration, (SCM)); diff --git a/lily/include/spring.hh b/lily/include/spring.hh index 11989b3ad0..4022173201 100644 --- a/lily/include/spring.hh +++ b/lily/include/spring.hh @@ -1,5 +1,5 @@ /* - spring.hh -- declare Spring, Column_spring + spring.hh -- declare Spring source file of the GNU LilyPond music typesetter @@ -12,33 +12,44 @@ #include "lily-proto.hh" #include "smobs.hh" -struct Spring_smob +class Spring { - Grob *other_; Real distance_; - bool expand_only_b_; - Real inverse_strength_; + Real min_distance_; - DECLARE_SIMPLE_SMOBS (Spring_smob); -public: - Spring_smob (); -}; -DECLARE_UNSMOB (Spring_smob, spring); + Real inverse_stretch_strength_; + Real inverse_compress_strength_; -struct Spring -{ - Drul_array item_drul_; - Real distance_; - bool expand_only_b_; - - /* - TODO: make 2 strengths: one for stretching, and one for shrinking. - */ - Real inverse_strength_; - void add_to_cols (); - void set_to_cols (); + Real blocking_force_; + + void update_blocking_force (); + + DECLARE_SIMPLE_SMOBS (Spring); +public: Spring (); + Spring (Real distance, Real min_distance); + + Real distance () const {return distance_;} + Real min_distance () const {return min_distance_;} + Real inverse_stretch_strength () const {return inverse_stretch_strength_;} + Real inverse_compress_strength () const {return inverse_compress_strength_;} + Real blocking_force () const {return blocking_force_;} + + Real length (Real f) const; + + void set_distance (Real); + void set_min_distance (Real); + void set_inverse_stretch_strength (Real); + void set_inverse_compress_strength (Real); + void set_blocking_force (Real); + void set_default_strength (); + + void operator*= (Real); + bool operator> (Spring const&) const; }; +DECLARE_UNSMOB (Spring, spring); + +Spring merge_springs (vector const &springs); #endif /* SPRING_HH */ diff --git a/lily/include/staff-spacing.hh b/lily/include/staff-spacing.hh index b4241f2800..9503c610ec 100644 --- a/lily/include/staff-spacing.hh +++ b/lily/include/staff-spacing.hh @@ -11,15 +11,16 @@ #include "lily-proto.hh" #include "grob-interface.hh" +#include "spring.hh" class Staff_spacing { + static Real optical_correction (Grob *, Grob *, Interval); + static Real next_notes_correction (Grob *, Grob *); + public: - static void next_notes_correction (Grob *, Grob *, Real, Real, Real *, Real *); - static void next_note_correction (Grob *, Grob *, Interval, Real, Real, Real*, Real *, int *); DECLARE_GROB_INTERFACE(); - static void get_spacing_params (Grob *, Real *, Real *); - + static Spring get_spacing (Grob *, Grob *right_col); static Interval bar_y_positions (Grob *); }; diff --git a/lily/multi-measure-rest-engraver.cc b/lily/multi-measure-rest-engraver.cc index c8ea549701..cf5f25a613 100644 --- a/lily/multi-measure-rest-engraver.cc +++ b/lily/multi-measure-rest-engraver.cc @@ -148,12 +148,13 @@ void Multi_measure_rest_engraver::stop_translation_timestep () { /* We cannot do this earlier, as breakableSeparationItem is not yet - there. */ + there. + + Actually, we no longer use breakableSeparationItem -- should this be moved? + -- jneem */ if (bar_seen_) { - Grob *cmc = unsmob_grob (get_property ("breakableSeparationItem")); - if (!cmc) - cmc = unsmob_grob (get_property ("currentCommandColumn")); + Grob *cmc = unsmob_grob (get_property ("currentCommandColumn")); /* Ugh, this is a kludge - need this for multi-measure-rest-grace.ly */ last_command_item_ = dynamic_cast (cmc); diff --git a/lily/multi-measure-rest.cc b/lily/multi-measure-rest.cc index 1b66670a7c..279f2d011f 100644 --- a/lily/multi-measure-rest.cc +++ b/lily/multi-measure-rest.cc @@ -79,9 +79,7 @@ Multi_measure_rest::print (SCM smob) { Item *b = sp->get_bound (d); - Interval coldim = (Separation_item::has_interface (b)) - ? Separation_item::relative_width (b, common) - : b->extent (common, X_AXIS); + Interval coldim = b->extent (common, X_AXIS); sp_iv[d] = coldim.is_empty () ? b->relative_coordinate (common, X_AXIS) : coldim[-d]; } diff --git a/lily/note-collision.cc b/lily/note-collision.cc index 6feb71c863..8ee404cb06 100644 --- a/lily/note-collision.cc +++ b/lily/note-collision.cc @@ -434,8 +434,7 @@ Note_collision_interface::get_clash_groups (Grob *me) */ SCM Note_collision_interface::automatic_shift (Grob *me, - Drul_array < vector - > clash_groups) + Drul_array > clash_groups) { Drul_array < vector > shifts; SCM tups = SCM_EOL; diff --git a/lily/note-column.cc b/lily/note-column.cc index 3f57d3e63c..b1c6b9f272 100644 --- a/lily/note-column.cc +++ b/lily/note-column.cc @@ -142,12 +142,6 @@ Note_column::translate_rests (Grob *me, int dy) } } -void -Note_column::set_dotcol (Grob *me, Grob *d) -{ - Axis_group_interface::add_element (me, d); -} - Grob * Note_column::first_head (Grob *me) { diff --git a/lily/note-spacing-engraver.cc b/lily/note-spacing-engraver.cc index 569735f859..68593604de 100644 --- a/lily/note-spacing-engraver.cc +++ b/lily/note-spacing-engraver.cc @@ -104,13 +104,13 @@ Note_spacing_engraver::stop_translation_timestep () { if (last_spacing_ && last_spacing_parent_context_ - && last_spacing_parent_context_ == context ()->get_parent_context ()) + && last_spacing_parent_context_ == context ()->get_parent_context () + && to_boolean (get_property ("hasStaffSpacing"))) { - Grob *sep = unsmob_grob (get_property ("breakableSeparationItem")); - if (sep) - Pointer_group_interface::add_grob (last_spacing_, - ly_symbol2scm ("right-items"), - sep); + Grob *col = unsmob_grob (get_property ("currentCommandColumn")); + Pointer_group_interface::add_grob (last_spacing_, + ly_symbol2scm ("right-items"), + col); } if (spacing_) diff --git a/lily/note-spacing.cc b/lily/note-spacing.cc index 2839309ecb..61af354f4c 100644 --- a/lily/note-spacing.cc +++ b/lily/note-spacing.cc @@ -16,6 +16,7 @@ #include "warn.hh" #include "stem.hh" #include "separation-item.hh" +#include "spacing-interface.hh" #include "staff-spacing.hh" #include "accidental-placement.hh" #include "output-def.hh" @@ -26,224 +27,71 @@ spacing? */ -void +Spring Note_spacing::get_spacing (Grob *me, Item *right_col, - Real base_space, Real increment, Real *space, Real *fixed) + Real base_space, Real increment) { - Drul_array props (me->get_object ("left-items"), - me->get_object ("right-items")); - Direction d = LEFT; - Direction col_dir = right_col->break_status_dir (); - Drul_array extents; + vector note_columns = Spacing_interface::left_note_columns (me); + Real left_head_end = 0; - Interval left_head_wid; - do + for (vsize i = 0; i < note_columns.size (); i++) { - vector const &items (ly_scm2link_array (props [d])); - for (vsize i = items.size (); i--;) - { - Item *it = dynamic_cast (items[i]); - - if (d == RIGHT && it->break_status_dir () != col_dir) - it = it->find_prebroken_piece (col_dir); - - /* - some kind of mismatch, eg. a note column, that is behind a - linebreak. - */ - if (!it) - continue; - - Item *it_col = it->get_column (); - if (d == RIGHT && right_col != it_col) - continue; - - if (Separation_item::has_interface (it)) - { - extents[d].unite (Separation_item::width (it)); - continue; - } - - if (d == LEFT - && Note_column::has_interface (it)) - { - SCM r = it->get_object ("rest"); - Grob *g = unsmob_grob (r); - if (!g) - g = Note_column::first_head (it); - - /* - Ugh. If Stem is switched off, we don't know what the - first note head will be. - */ - if (g) - { - if (g->common_refpoint (it_col, X_AXIS) != it_col) - programming_error ("Note_spacing::get_spacing (): Common refpoint incorrect"); - else - left_head_wid = g->extent (it_col, X_AXIS); - } - } - - extents[d].unite (it->extent (it_col, X_AXIS)); - if (d == RIGHT) - { - Grob *accs = Note_column::accidentals (it); - if (!accs) - accs = Note_column::accidentals (it->get_parent (X_AXIS)); - - if (accs) - { - Interval v - = Accidental_placement::get_relevant_accidental_extent (accs, it_col, me); - - extents[d].unite (v); - } - - if (Grob *arpeggio = Note_column::arpeggio (it)) - extents[d].unite (arpeggio->extent (it_col, X_AXIS)); - } - } - - if (extents[d].is_empty ()) - extents[d] = Interval (0, 0); + SCM r = note_columns[i]->get_object ("rest"); + Grob *g = unsmob_grob (r); + Grob *col = note_columns[i]->get_column (); + + if (!g) + g = Note_column::first_head (note_columns[i]); + + /* + Ugh. If Stem is switched off, we don't know what the + first note head will be. + */ + if (g) + { + if (g->common_refpoint (col, X_AXIS) != col) + programming_error ("Note_spacing::get_spacing (): Common refpoint incorrect"); + else + left_head_end = g->extent (col, X_AXIS)[RIGHT]; + } } - while (flip (&d) != LEFT); /* - We look at the width of the note head, since smaller heads get less space + The main factor that determines the amount of space is the width of the + note head (or the rest). For example, a quarter rest gets almost 0.5 ss + less horizontal space than a note. - eg. a quarter rest gets almost 0.5 ss less horizontal space than a note. - - What is sticking out of the note head (eg. a flag), doesn't get - the full amount of space. - - FIXED also includes the left part of the right object. + The other parts of a note column (eg. flags, accidentals, etc.) don't get + the full amount of space. We give them half the amount of space, but then + adjust things so there are no collisions. */ - *fixed - = (left_head_wid.is_empty () ? increment - : /* - Size of the head: - */ - (left_head_wid[RIGHT]+ - - /* - What's sticking out of the head, eg. a flag: - */ - (extents[LEFT][RIGHT] - left_head_wid[RIGHT]) / 2)) - - /* - What is sticking out on the left side of the right note: - */ - + (extents[RIGHT].is_empty () - ? 0.0 - : ((- extents[RIGHT][LEFT] / 2) - - /* - Add that which sticks out a lot. - */ - + max (0.0, -extents[RIGHT][LEFT] - (base_space - 0.5 * increment)))); + Drul_array skys = Spacing_interface::skylines (me, right_col); + Real min_dist = max (0.0, skys[LEFT].distance (skys[RIGHT])); + Real min_desired_space = left_head_end + (min_dist - left_head_end) / 2; - /* - We don't do complicated stuff: (base_space - increment) is the - normal amount of white, which also determines the amount of - stretch. Upon (extreme) stretching, notes with accidentals should - stretch as much as notes without accidentals. - */ - *space = (base_space - increment) + *fixed; + /* if the right object sticks out a lot, include a bit of extra space. + But only for non-musical-columns; this shouldn't apply to accidentals */ + if (!Paper_column::is_musical (right_col)) + min_desired_space = max (min_desired_space, + left_head_end + LEFT * skys[RIGHT].max_height ()); -#if 0 - /* - The below situation is now handled by the "sticks out a lot" case - above. However we keep around the code for a few releases before - we drop it. - */ - if (!extents[RIGHT].is_empty () - && (Paper_column::is_breakable (right_col))) - { - /* - This is for the situation + Real ideal = base_space - increment + min_desired_space; - rest | 3/4 (eol) + stem_dir_correction (me, right_col, increment, &ideal, &min_desired_space); - Since we only take half of the right-object space above, the - barline will bump into the notes preceding it, if the right - thing is big. We add the rest of the extents here: - */ - - *space += -extents[RIGHT][LEFT] / 2; - *fixed += -extents[RIGHT][LEFT] / 2; - } -#endif - - stem_dir_correction (me, right_col, increment, space, fixed); + Spring ret (ideal, min_dist); + ret.set_inverse_compress_strength (max (0.0, ideal - max (min_dist, min_desired_space))); + ret.set_inverse_stretch_strength (max (0.1, base_space - increment)); + return ret; } -Item * -Note_spacing::left_column (Grob *me) -{ - if (!me->is_live ()) - return 0; - - return dynamic_cast (me)->get_column (); -} - -/* - Compute the column of the right-items. This is a big function, - since RIGHT-ITEMS may span more columns (eg. if a clef if inserted, - this will add a new columns to RIGHT-ITEMS. Here we look at the - columns, and return the left-most. If there are multiple columns, we - prune RIGHT-ITEMS. -*/ -Item * -Note_spacing::right_column (Grob *me) -{ - if (!me->is_live ()) - return 0; - - Grob_array *a = unsmob_grob_array (me->get_object ("right-items")); - Item *mincol = 0; - int min_rank = INT_MAX; - bool prune = false; - for (vsize i = 0; a && i < a->size (); i++) - { - Item *ri = a->item (i); - Item *col = ri->get_column (); - - int rank = Paper_column::get_rank (col); - - if (rank < min_rank) - { - min_rank = rank; - if (mincol) - prune = true; - - mincol = col; - } - } - - if (prune && a) - { - vector &right = a->array_reference (); - for (vsize i = right.size (); i--;) - { - if (dynamic_cast (right[i])->get_column () != mincol) - right.erase (right.begin () + i); - } - } - - if (!mincol) - return 0; - - return mincol; -} /** Correct for optical illusions. See [Wanske] p. 138. The combination up-stem + down-stem should get extra space, the combination down-stem + up-stem less. - TODO: have to check wether the stems are in the same staff. + TODO: have to check whether the stems are in the same staff. */ void Note_spacing::stem_dir_correction (Grob *me, Item *rcolumn, @@ -379,12 +227,7 @@ Note_spacing::stem_dir_correction (Grob *me, Item *rcolumn, if (!head_extent.is_empty ()) note_head_width = head_extent[RIGHT]; - if (st) - { - Real thick = Stem::thickness (st); - - note_head_width -= thick; - } + note_head_width -= Stem::thickness (st); } correction = note_head_width * stem_dirs[LEFT]; diff --git a/lily/paper-column-engraver.cc b/lily/paper-column-engraver.cc index 6ed851243d..1396c1280d 100644 --- a/lily/paper-column-engraver.cc +++ b/lily/paper-column-engraver.cc @@ -9,11 +9,13 @@ #include "paper-column-engraver.hh" #include "system.hh" #include "international.hh" +#include "accidental-placement.hh" #include "axis-group-interface.hh" #include "context.hh" #include "note-spacing.hh" #include "paper-column.hh" #include "pointer-group-interface.hh" +#include "separation-item.hh" #include "staff-spacing.hh" #include "system.hh" #include "warn.hh" @@ -192,12 +194,17 @@ Paper_column_engraver::stop_translation_timestep () for (vsize i = 0; i < items_.size (); i++) { Item *elem = items_[i]; + Grob *col = Item::is_non_musical (elem) ? command_column_ : musical_column_; + if (!elem->get_parent (X_AXIS) || !unsmob_grob (elem->get_object ("axis-group-parent-X"))) { - bool br = Item::is_non_musical (elem); - Axis_group_interface::add_element (br ? command_column_ : musical_column_, elem); + Axis_group_interface::add_element (col, elem); } + else if (Accidental_placement::has_interface (elem)) + Separation_item::add_conditional_item (col, elem); + else + Separation_item::add_item (col, elem); } items_.clear (); diff --git a/lily/paper-column.cc b/lily/paper-column.cc index 1578688925..bb827db18b 100644 --- a/lily/paper-column.cc +++ b/lily/paper-column.cc @@ -22,6 +22,7 @@ #include "system.hh" #include "spring.hh" #include "lookup.hh" +#include "separation-item.hh" #include "string-convert.hh" Grob * @@ -136,6 +137,24 @@ Paper_column::is_breakable (Grob *me) return scm_is_symbol (me->get_property ("line-break-permission")); } +Real +Paper_column::minimum_distance (Grob *left, Grob *right) +{ + Drul_array cols (left, right); + Drul_array skys = Drul_array (Skyline (RIGHT), Skyline (LEFT)); + + Direction d = LEFT; + do + { + Skyline_pair *sp = Skyline_pair::unsmob (cols[d]->get_property ("horizontal-skylines")); + if (sp) + skys[d] = (*sp)[-d]; + } + while (flip (&d) != LEFT); + + return max (0.0, skys[LEFT].distance (skys[RIGHT])); +} + /* Print a vertical line and the rank number, to aid debugging. */ @@ -175,8 +194,9 @@ Paper_column::print (SCM p) for (SCM s = me->get_object ("ideal-distances"); scm_is_pair (s); s = scm_cdr (s)) { - Spring_smob *sp = unsmob_spring (scm_car (s)); - if (!sp->other_->get_system ()) + Spring *sp = unsmob_spring (scm_caar (s)); + if (!unsmob_grob (scm_cdar (s)) + || !unsmob_grob (scm_cdar (s))->get_system ()) continue; j++; @@ -184,7 +204,7 @@ Paper_column::print (SCM p) vector pts; pts.push_back (Offset (0, y)); - Offset p2 (sp->distance_, y); + Offset p2 (sp->distance (), y); pts.push_back (p2); Stencil id_stencil = Lookup::points_to_line_stencil (0.1, pts); @@ -192,9 +212,9 @@ Paper_column::print (SCM p) SCM distance_stc = Text_interface::interpret_markup (me->layout ()->self_scm (), small_letters, - ly_string2scm (String_convert::form_string ("%5.2lf", sp->distance_))); + ly_string2scm (String_convert::form_string ("%5.2lf", sp->distance ()))); - id_stencil.add_stencil (unsmob_stencil (distance_stc)->translated (Offset (sp->distance_/3, y+1))); + id_stencil.add_stencil (unsmob_stencil (distance_stc)->translated (Offset (sp->distance ()/3, y+1))); id_stencil.add_stencil (head.translated (p2)); id_stencil = id_stencil.in_color (0,0,1); l.add_stencil (id_stencil); diff --git a/lily/rhythmic-column-engraver.cc b/lily/rhythmic-column-engraver.cc index fc21e618eb..827a6fb94f 100644 --- a/lily/rhythmic-column-engraver.cc +++ b/lily/rhythmic-column-engraver.cc @@ -46,13 +46,14 @@ class Rhythmic_column_engraver : public Engraver Grob *stem_; Grob *note_column_; Grob *dotcol_; + Grob *arpeggio_; TRANSLATOR_DECLARATIONS (Rhythmic_column_engraver); protected: - DECLARE_ACKNOWLEDGER (dot_column); DECLARE_ACKNOWLEDGER (stem); DECLARE_ACKNOWLEDGER (rhythmic_head); + DECLARE_ACKNOWLEDGER (arpeggio); void process_acknowledged (); void stop_translation_timestep (); }; @@ -62,7 +63,7 @@ Rhythmic_column_engraver::Rhythmic_column_engraver () stem_ = 0; note_column_ = 0; - dotcol_ = 0; + arpeggio_ = 0; } @@ -72,30 +73,29 @@ Rhythmic_column_engraver::process_acknowledged () if (rheads_.size ()) { if (!note_column_) - { - note_column_ = make_item ("NoteColumn", rheads_[0]->self_scm ()); - } + note_column_ = make_item ("NoteColumn", rheads_[0]->self_scm ()); for (vsize i = 0; i < rheads_.size (); i++) - { - if (!rheads_[i]->get_parent (X_AXIS)) - Note_column::add_head (note_column_, rheads_[i]); - } + if (!rheads_[i]->get_parent (X_AXIS)) + Note_column::add_head (note_column_, rheads_[i]); + rheads_.resize (0); } if (note_column_) { - if (dotcol_ - && !dotcol_->get_parent (X_AXIS)) - Note_column::set_dotcol (note_column_, dotcol_); - if (stem_ && !stem_->get_parent (X_AXIS)) { Note_column::set_stem (note_column_, stem_); stem_ = 0; } + + if (arpeggio_) + { + Pointer_group_interface::add_grob (note_column_, ly_symbol2scm ("elements"), arpeggio_); + note_column_->set_object ("arpeggio", arpeggio_->self_scm ()); + } } } @@ -112,22 +112,22 @@ Rhythmic_column_engraver::acknowledge_rhythmic_head (Grob_info i) } void -Rhythmic_column_engraver::acknowledge_dot_column (Grob_info i) +Rhythmic_column_engraver::acknowledge_arpeggio (Grob_info i) { - dotcol_ = i.grob (); + arpeggio_ = i.grob (); } void Rhythmic_column_engraver::stop_translation_timestep () { note_column_ = 0; - dotcol_ = 0; stem_ = 0; + arpeggio_ = 0; } -ADD_ACKNOWLEDGER (Rhythmic_column_engraver, dot_column); ADD_ACKNOWLEDGER (Rhythmic_column_engraver, stem); ADD_ACKNOWLEDGER (Rhythmic_column_engraver, rhythmic_head); +ADD_ACKNOWLEDGER (Rhythmic_column_engraver, arpeggio); ADD_TRANSLATOR (Rhythmic_column_engraver, /* doc */ "Generates NoteColumn, an objects that groups stems, noteheads and rests.", diff --git a/lily/separating-group-spanner.cc b/lily/separating-group-spanner.cc deleted file mode 100644 index 7de9341e39..0000000000 --- a/lily/separating-group-spanner.cc +++ /dev/null @@ -1,101 +0,0 @@ -/* - separating-group-spanner.cc -- implement Separating_group_spanner - - source file of the GNU LilyPond music typesetter - - (c) 1998--2007 Han-Wen Nienhuys -*/ - -#include "separating-group-spanner.hh" - -#include "separation-item.hh" -#include "paper-column.hh" -#include "output-def.hh" -#include "dimensions.hh" -#include "pointer-group-interface.hh" -#include "moment.hh" - -void -Separating_group_spanner::find_rods (Item *r, - vector const &separators, - vsize idx, - Real padding) -{ - - /* - This is an inner loop: look for the first normal (unbroken) Left - grob. This looks like an inner loop (ie. quadratic total), but in - most cases, the interesting L will just be the first entry of - NEXT, making it linear in most of the cases. - */ - for (; idx != VPOS; idx--) - { - Item *l = dynamic_cast (separators[idx]); - Item *lb = l->find_prebroken_piece (RIGHT); - - if (lb) - { - Separation_item::set_distance (Drul_array (lb, r), padding); - } - - if (Separation_item::set_distance (Drul_array (l, r), padding) - /* - This check is because grace notes are set very tight, and - the accidentals of main note may stick out so far to cover - a barline preceding the grace note. - */ - && spanned_time_interval (l, r).length ().main_part_ > Rational (0)) - break; - - /* - this grob doesn't cause a constraint. We look further until we - find one that does. - */ - } -} - -MAKE_SCHEME_CALLBACK (Separating_group_spanner, set_spacing_rods, 1); -SCM -Separating_group_spanner::set_spacing_rods (SCM smob) -{ - Grob *me = unsmob_grob (smob); - - /* - Ugh: padding is added doubly, also for SeparationItem - */ - Real padding = robust_scm2double (me->get_property ("padding"), 0.1); - - extract_grob_set (me, "elements", elts); - for (vsize i = elts.size (); i-- > 1;) - { - Item *r = dynamic_cast (elts[i]); - if (!r) - continue; - - if (Separation_item::width (r).is_empty ()) - continue; - - Item *rb - = dynamic_cast (r->find_prebroken_piece (LEFT)); - - find_rods (r, elts, i - 1, padding); - if (rb) - find_rods (rb, elts, i - 1, padding); - } - - return SCM_UNSPECIFIED; -} - -void -Separating_group_spanner::add_spacing_unit (Grob *me, Item *i) -{ - Pointer_group_interface::add_unordered_grob (me, ly_symbol2scm ("elements"), i); -} - -ADD_INTERFACE (Separating_group_spanner, - "A spanner that calculates spacing constraints (\"rods\") " - "using the @code{separation-item-interface} grobs in @code{elements}.", - - /* properties */ - "elements " - "padding "); diff --git a/lily/separating-line-group-engraver.cc b/lily/separating-line-group-engraver.cc index f493840d95..31bd53a2d5 100644 --- a/lily/separating-line-group-engraver.cc +++ b/lily/separating-line-group-engraver.cc @@ -8,7 +8,6 @@ #include "engraver.hh" -#include "separating-group-spanner.hh" #include "separation-item.hh" #include "paper-column.hh" #include "output-def.hh" @@ -46,18 +45,10 @@ struct Spacings class Separating_line_group_engraver : public Engraver { protected: - Item *break_item_; - Item *musical_item_; - Item *last_musical_item_; - Spacings current_spacings_; Spacings last_spacings_; - Spanner *sep_span_; - DECLARE_ACKNOWLEDGER (item); - void process_music (); - virtual void finalize (); void stop_translation_timestep (); void start_translation_timestep (); public: @@ -66,50 +57,12 @@ public: Separating_line_group_engraver::Separating_line_group_engraver () { - sep_span_ = 0; - break_item_ = 0; - musical_item_ = 0; -} - -void -Separating_line_group_engraver::process_music () -{ - if (!sep_span_) - { - sep_span_ = make_spanner ("SeparatingGroupSpanner", SCM_EOL); - - sep_span_->set_bound (LEFT, unsmob_grob (get_property ("currentCommandColumn"))); - } -} -void -Separating_line_group_engraver::finalize () -{ - if (!sep_span_) - return; - - SCM ccol = get_property ("currentCommandColumn"); - Grob *column = unsmob_grob (ccol); - - sep_span_->set_bound (RIGHT, unsmob_grob (ccol)); - sep_span_ = 0; - - if (last_spacings_.staff_spacing_ - && last_spacings_.staff_spacing_->get_column () == column) - last_spacings_.staff_spacing_->suicide (); } void Separating_line_group_engraver::acknowledge_item (Grob_info i) { Item *it = i.item (); - if (it->get_parent (X_AXIS) - && it->get_parent (X_AXIS) == it->get_parent (Y_AXIS) - && Axis_group_interface::has_axis (it->get_parent (X_AXIS), X_AXIS) - && Axis_group_interface::has_axis (it->get_parent (Y_AXIS), Y_AXIS)) - return; - - if (to_boolean (it->get_property ("no-spacing-rods"))) - return; if (Note_spacing::has_interface (it)) { @@ -117,97 +70,61 @@ Separating_line_group_engraver::acknowledge_item (Grob_info i) return; } - bool ib = Item::is_non_musical (it); - Item *&p_ref_ (ib ? break_item_ - : musical_item_); - - if (!p_ref_) + if (Item::is_non_musical (it) + && !current_spacings_.staff_spacing_ + && to_boolean (get_property ("createSpacing"))) { - p_ref_ = make_item ("SeparationItem", SCM_EOL); + Grob *col = unsmob_grob (get_property ("currentCommandColumn")); - if (ib) - { - p_ref_->set_property ("non-musical", SCM_BOOL_T); - context ()->set_property ("breakableSeparationItem", p_ref_->self_scm ()); - } + current_spacings_.staff_spacing_ = make_item ("StaffSpacing", SCM_EOL); + context ()->set_property ("hasStaffSpacing", SCM_BOOL_T); - if (to_boolean (get_property ("createSpacing")) - && p_ref_ == break_item_) + Pointer_group_interface::add_grob (current_spacings_.staff_spacing_, + ly_symbol2scm ("left-items"), + col); + + if (!last_spacings_.note_spacings_.size () + && last_spacings_.staff_spacing_) { - Item *it = make_item ("StaffSpacing", SCM_EOL); - current_spacings_.staff_spacing_ = it; - Pointer_group_interface::add_grob (it, ly_symbol2scm ("left-items"), - break_item_); - - if (!last_spacings_.note_spacings_.size () - && last_spacings_.staff_spacing_) + SCM ri = last_spacings_.staff_spacing_->get_object ("right-items"); + Grob_array *ga = unsmob_grob_array (ri); + if (!ga) { - SCM ri = last_spacings_.staff_spacing_->get_object ("right-items"); - Grob_array *ga = unsmob_grob_array (ri); - if (!ga) - { - SCM ga_scm = Grob_array::make_array (); - last_spacings_.staff_spacing_->set_object ("right-items", ga_scm); - ga = unsmob_grob_array (ga_scm); - } - - ga->clear (); - ga->add (break_item_); + SCM ga_scm = Grob_array::make_array (); + last_spacings_.staff_spacing_->set_object ("right-items", ga_scm); + ga = unsmob_grob_array (ga_scm); } + + ga->clear (); + ga->add (col); } } - - if (Accidental_placement::has_interface (it)) - Separation_item::add_conditional_item (p_ref_, it); - else - Separation_item::add_item (p_ref_, it); } void Separating_line_group_engraver::start_translation_timestep () { - if (break_item_) - { - context ()->unset_property (ly_symbol2scm ("breakableSeparationItem")); - break_item_ = 0; - } + context ()->unset_property (ly_symbol2scm ("hasStaffSpacing")); } void Separating_line_group_engraver::stop_translation_timestep () { - if (break_item_) - Separating_group_spanner::add_spacing_unit (sep_span_, break_item_); - - if (Item *sp = current_spacings_.staff_spacing_) - { - /* - TODO: should really look at the left-items of following - note-spacing grobs. - */ - if (musical_item_) - Pointer_group_interface::add_grob (sp, ly_symbol2scm ("right-items"), - musical_item_); - } - if (!current_spacings_.is_empty ()) last_spacings_ = current_spacings_; - current_spacings_.clear (); - - if (musical_item_) - Separating_group_spanner::add_spacing_unit (sep_span_, musical_item_); + if (Item *sp = current_spacings_.staff_spacing_) + if (Grob *col = unsmob_grob (get_property ("currentMusicalColumn"))) + Pointer_group_interface::add_grob (sp, ly_symbol2scm ("right-items"), col); - musical_item_ = 0; + current_spacings_.clear (); } ADD_ACKNOWLEDGER (Separating_line_group_engraver, item); ADD_TRANSLATOR (Separating_line_group_engraver, /* doc */ "Generates objects for computing spacing parameters.", - /* create */ - "SeparationItem " - "SeparatingGroupSpanner " - "StaffSpacing", + /* create */ "StaffSpacing", /* read */ "createSpacing", - /* write */ "breakableSeparationItem"); + /* write */ "hasStaffSpacing" + ); diff --git a/lily/separation-item.cc b/lily/separation-item.cc index 8a83e2b7a1..a692fc0b9b 100644 --- a/lily/separation-item.cc +++ b/lily/separation-item.cc @@ -8,6 +8,7 @@ #include "separation-item.hh" +#include "axis-group-interface.hh" #include "lookup.hh" #include "stencil.hh" #include "skyline.hh" @@ -30,7 +31,7 @@ Separation_item::add_conditional_item (Grob *me, Grob *e) } void -Separation_item::set_skyline_distance (Drul_array items, +Separation_item::set_distance (Drul_array items, Real padding) { Drul_array lines (Skyline_pair::unsmob (items[LEFT]->get_property ("horizontal-skylines")), @@ -51,11 +52,10 @@ Separation_item::set_skyline_distance (Drul_array items, } bool -Separation_item::set_distance (Drul_array items, - Real padding) +Separation_item::is_empty (Grob *me) { - set_skyline_distance (items, padding); - return true; + Skyline_pair *sky = Skyline_pair::unsmob (me->get_property ("horizontal-skylines")); + return (!sky || sky->is_empty ()); } /* @@ -97,7 +97,7 @@ Separation_item::boxes (Grob *me, Grob *left) vector elts; if (left) - elts = Accidental_placement::get_break_reminder_accidentals (read_only_elts, left); + elts = Accidental_placement::get_relevant_accidentals (read_only_elts, left); else elts = read_only_elts; @@ -107,41 +107,27 @@ Separation_item::boxes (Grob *me, Grob *left) { Item *il = dynamic_cast (elts[i]); if (pc != il->get_column ()) - { - continue; - } + continue; + if (Axis_group_interface::has_interface (il)) + continue; Interval y (il->pure_height (ycommon, 0, very_large)); Interval x (il->extent (pc, X_AXIS)); Interval extra = robust_scm2interval (elts[i]->get_property ("extra-spacing-width"), - Interval (0, 0)); + Interval (-0.1, 0.1)); x[LEFT] += extra[LEFT]; x[RIGHT] += extra[RIGHT]; if (to_boolean (elts[i]->get_property ("infinite-spacing-height"))) y = Interval (-infinity_f, infinity_f); + if (!x.is_empty () && !y.is_empty ()) out.push_back (Box (x, y)); } return out; } -Interval -Separation_item::width (Grob *me) -{ - SCM sw = me->get_property ("X-extent"); - return ly_scm2interval (sw); -} - -Interval -Separation_item::relative_width (Grob *me, Grob *common) -{ - Interval iv = width (me); - - return dynamic_cast (me)->get_column ()->relative_coordinate (common, X_AXIS) + iv; -} - /* Try to find the break-aligned symbol in SEPARATION_ITEM that is sticking out at direction D. The x size is put in LAST_EXT @@ -201,7 +187,7 @@ Separation_item::print (SCM smob) ADD_INTERFACE (Separation_item, "Item that computes widths to generate spacing rods. " - "This is done in concert with @ref{separating-group-spanner-interface}.", + , "X-extent " "conditional-elements " diff --git a/lily/simple-spacer-scheme.cc b/lily/simple-spacer-scheme.cc index fda38ab503..48f127bfca 100644 --- a/lily/simple-spacer-scheme.cc +++ b/lily/simple-spacer-scheme.cc @@ -44,7 +44,11 @@ LY_DEFINE (ly_solve_spring_rod_problem, "ly:solve-spring-rod-problem", Real ideal = scm_to_double (scm_caar (s)); Real inv_hooke = scm_to_double (scm_cadar (s)); - spacer.add_spring (ideal, inv_hooke); + Spring sp (ideal, 0.0); + sp.set_inverse_compress_strength (inv_hooke); + sp.set_inverse_stretch_strength (inv_hooke); + + spacer.add_spring (sp); } for (SCM s = rods; scm_is_pair (s); s = scm_cdr (s)) diff --git a/lily/simple-spacer.cc b/lily/simple-spacer.cc index 04c35dd4e5..8e0722438e 100644 --- a/lily/simple-spacer.cc +++ b/lily/simple-spacer.cc @@ -80,8 +80,8 @@ Simple_spacer::fits () const Real Simple_spacer::rod_force (int l, int r, Real dist) { - Real c = range_stiffness (l, r); Real d = range_ideal_len (l, r); + Real c = range_stiffness (l, r, dist > d); Real block_stretch = dist - d; return c * block_stretch; } @@ -102,13 +102,13 @@ Simple_spacer::add_rod (int l, int r, Real dist) Real spring_dist = range_ideal_len (l, r); if (spring_dist < dist) for (int i = l; i < r; i++) - springs_[i].ideal_ *= dist / spring_dist; + springs_[i].set_distance (springs_[i].distance () * dist / spring_dist); return; } force_ = max (force_, block_force); for (int i = l; i < r; i++) - springs_[i].block_force_ = max (block_force, springs_[i].block_force_); + springs_[i].set_blocking_force (max (block_force, springs_[i].blocking_force ())); } Real @@ -116,16 +116,17 @@ Simple_spacer::range_ideal_len (int l, int r) const { Real d = 0.; for (int i = l; i < r; i++) - d += springs_[i].ideal_; + d += springs_[i].distance (); return d; } Real -Simple_spacer::range_stiffness (int l, int r) const +Simple_spacer::range_stiffness (int l, int r, bool stretch) const { Real den = 0.0; for (int i = l; i < r; i++) - den += springs_[i].inverse_hooke_; + den += stretch ? springs_[i].inverse_stretch_strength () + : springs_[i].inverse_compress_strength (); return 1 / den; } @@ -144,13 +145,10 @@ void Simple_spacer::solve (Real line_len, bool ragged) { Real conf = configuration_length (force_); - double inv_hooke = 0; - for (vsize i=0; i < springs_.size (); i++) - inv_hooke += springs_[i].inverse_hooke_; ragged_ = ragged; line_len_ = line_len; - if ((inv_hooke > 0) && (conf < line_len_)) + if (conf < line_len_) force_ = expand_line (); else if (conf > line_len_) force_ = compress_line (); @@ -167,7 +165,7 @@ Simple_spacer::expand_line () fits_ = true; for (vsize i=0; i < springs_.size (); i++) - inv_hooke += springs_[i].inverse_hooke_; + inv_hooke += springs_[i].inverse_stretch_strength (); assert (cur_len <= line_len_); return (line_len_ - cur_len) / inv_hooke + force_; @@ -179,39 +177,54 @@ Simple_spacer::compress_line () double inv_hooke = 0; double cur_len = configuration_length (force_); double cur_force = force_; + bool compressed = false; + + /* just because we are in compress_line () doesn't mean that the line + will actually be compressed (as in, a negative force) because + we start out with a stretched line. Here, we check whether we + will be compressed or stretched (so we know which spring constant to use) */ + if (configuration_length (0.0) > line_len_) + { + cur_force = 0.0; + cur_len = configuration_length (0.0); + compressed = true; + } fits_ = true; for (vsize i=0; i < springs_.size (); i++) - inv_hooke += springs_[i].inverse_hooke_; + inv_hooke += compressed + ? springs_[i].inverse_compress_strength () + : springs_[i].inverse_stretch_strength (); assert (line_len_ <= cur_len); - vector sorted_springs = springs_; - sort (sorted_springs.begin (), sorted_springs.end (), greater ()); + vector sorted_springs = springs_; + sort (sorted_springs.begin (), sorted_springs.end (), greater ()); + for (vsize i = 0; i < sorted_springs.size (); i++) { - Spring_description sp = sorted_springs[i]; + Spring sp = sorted_springs[i]; - assert (sp.block_force_ <= cur_force); - if (isinf (sp.block_force_)) + assert (sp.blocking_force () <= cur_force); + if (isinf (sp.blocking_force ())) break; - double block_dist = (cur_force - sp.block_force_) * inv_hooke; + double block_dist = (cur_force - sp.blocking_force ()) * inv_hooke; if (cur_len - block_dist < line_len_) { - cur_force += (line_len_ - cur_len) / inv_hooke; - cur_len = line_len_; + cur_force += (line_len_ - cur_len) / inv_hooke; + cur_len = line_len_; - /* - Paranoia check. + /* + Paranoia check. */ - assert (fabs (configuration_length (cur_force) - cur_len) < 1e-6); - return cur_force; + assert (fabs (configuration_length (cur_force) - cur_len) < 1e-6); + return cur_force; } cur_len -= block_dist; - inv_hooke -= sp.inverse_hooke_; - cur_force = sp.block_force_; + inv_hooke -= sp.inverse_compress_strength (); + cur_force = sp.blocking_force (); } fits_ = false; @@ -219,24 +232,10 @@ Simple_spacer::compress_line () } void -Simple_spacer::add_spring (Real ideal, Real inverse_hooke) +Simple_spacer::add_spring (Spring const &sp) { - Spring_description description; - - description.ideal_ = ideal; - description.inverse_hooke_ = inverse_hooke; - if (!description.is_sane ()) - { - programming_error ("insane spring found, setting to unit"); - - description.inverse_hooke_ = 1.0; - description.ideal_ = 1.0; - } - - description.block_force_ = -description.ideal_ / description.inverse_hooke_; - // block at distance 0 - - springs_.push_back (description); + force_ = max (force_, sp.blocking_force ()); + springs_.push_back (sp); } vector @@ -266,45 +265,6 @@ Simple_spacer::force_penalty (bool ragged) const /****************************************************************/ -Spring_description::Spring_description () -{ - ideal_ = 0.0; - inverse_hooke_ = 0.0; - block_force_ = 0.0; -} - -bool -Spring_description::is_sane () const -{ - return (inverse_hooke_ >= 0) - && ideal_ >= 0 - && !isinf (ideal_) && !isnan (ideal_) - && (inverse_hooke_ == 0.0 || fabs (inverse_hooke_) > 1e-8) - ; -} - -Real -Spring_description::length (Real f) const -{ - return ideal_ + max (f, block_force_) * inverse_hooke_; -} - -/****************************************************************/ - -/* - TODO: should a add penalty for widely varying spring forces (caused - by constraints, eg. - - - . ===== - . | | - .o|o|x ##x - . - - The ## forces the notes apart; we shouldn't allow the O's to touch - this closely. -*/ - struct Rod_description { vsize r_; @@ -332,19 +292,14 @@ struct Column_description { vector rods_; vector end_rods_; /* use these if they end at the last column of the line */ - Real ideal_; - Real inverse_hooke_; - Real end_ideal_; - Real end_inverse_hooke_; + Spring spring_; + Spring end_spring_; + SCM break_permission_; Interval keep_inside_line_; Column_description () { - ideal_ = 0; - inverse_hooke_ = 0; - end_ideal_ = 0; - end_inverse_hooke_ = 0; break_permission_ = SCM_EOL; } }; @@ -383,10 +338,11 @@ get_column_description (vector const &cols, vsize col_index, bool line_st Column_description description; Grob *next_col = next_spaceable_column (cols, col_index); if (next_col) - Spaceable_grob::get_spring (col, next_col, &description.ideal_, &description.inverse_hooke_); + description.spring_ = Spaceable_grob::get_spring (col, next_col); + Grob *end_col = dynamic_cast (cols[col_index+1])->find_prebroken_piece (LEFT); if (end_col) - Spaceable_grob::get_spring (col, end_col, &description.end_ideal_, &description.end_inverse_hooke_); + description.end_spring_ = Spaceable_grob::get_spring (col, end_col); for (SCM s = Spaceable_grob::get_minimum_distances (col); scm_is_pair (s); s = scm_cdr (s)) @@ -447,8 +403,8 @@ get_line_forces (vector const &columns, Simple_spacer spacer; for (vsize i = breaks[b]; i < end - 1; i++) - spacer.add_spring (cols[i].ideal_, cols[i].inverse_hooke_); - spacer.add_spring (cols[end-1].end_ideal_, cols[end-1].end_inverse_hooke_); + spacer.add_spring (cols[i].spring_); + spacer.add_spring (cols[end-1].end_spring_); for (vsize i = breaks[b]; i < end; i++) @@ -508,7 +464,7 @@ get_line_configuration (vector const &columns, for (vsize i = 0; i + 1 < ret.cols_.size (); i++) { cols.push_back (get_column_description (ret.cols_, i, i == 0)); - spacer.add_spring (cols[i].ideal_, cols[i].inverse_hooke_); + spacer.add_spring (cols[i].spring_); } for (vsize i = 0; i < cols.size (); i++) { diff --git a/lily/skyline.cc b/lily/skyline.cc index c935660c6e..de6f7d078b 100644 --- a/lily/skyline.cc +++ b/lily/skyline.cc @@ -530,7 +530,8 @@ Skyline::to_points (Axis horizon_axis) const bool Skyline::is_empty () const { - return buildings_.empty (); + Building b = buildings_.front (); + return b.end_ == infinity_f && b.y_intercept_ == -infinity_f; } Skyline_pair::Skyline_pair () diff --git a/lily/slur-engraver.cc b/lily/slur-engraver.cc index 9900ba713b..57068e6225 100644 --- a/lily/slur-engraver.cc +++ b/lily/slur-engraver.cc @@ -194,7 +194,7 @@ Slur_engraver::process_music () void Slur_engraver::stop_translation_timestep () { - if (Grob *g = unsmob_grob (get_property ("breakableSeparationItem"))) + if (Grob *g = unsmob_grob (get_property ("currentCommandColumn"))) { for (vsize i = 0; i < end_slurs_.size (); i++) Slur::add_extra_encompass (end_slurs_[i], g); diff --git a/lily/spaceable-grob.cc b/lily/spaceable-grob.cc index 806e300cfa..87d30397e3 100644 --- a/lily/spaceable-grob.cc +++ b/lily/spaceable-grob.cc @@ -56,69 +56,34 @@ Spaceable_grob::add_rod (Grob *me, Grob *p, Real d) } void -Spaceable_grob::add_spring (Grob *me, Grob *other, - Real distance, Real inverse_strength) +Spaceable_grob::add_spring (Grob *me, Grob *other, Spring sp) { - if (distance < 0.0 || inverse_strength < 0.0) - { - programming_error ("adding reverse spring, setting to unit"); - distance = 1.0; - inverse_strength = 1.0; - } - - if (isinf (distance) || isnan (distance) - || isnan (inverse_strength)) - { - /* strength == INF is possible. It means fixed distance. */ - programming_error ("insane distance found"); - distance = 1.0; - inverse_strength = 1.0; - } - -#ifndef NDEBUG - SCM mins = me->get_object ("ideal-distances"); - for (SCM s = mins; scm_is_pair (s); s = scm_cdr (s)) - { - Spring_smob *sp = unsmob_spring (scm_car (s)); - if (sp->other_ == other) - { - programming_error ("already have that spring"); - return; - } - } -#endif - - Spring_smob spring; - spring.inverse_strength_ = inverse_strength; - spring.distance_ = distance; - spring.other_ = other; - SCM ideal = me->get_object ("ideal-distances"); - ideal = scm_cons (spring.smobbed_copy (), ideal); + + ideal = scm_cons (scm_cons (sp.smobbed_copy (), other->self_scm ()), ideal); me->set_object ("ideal-distances", ideal); } -void -Spaceable_grob::get_spring (Grob *this_col, Grob *next_col, Real *dist, Real *inv_strength) +Spring +Spaceable_grob::get_spring (Grob *this_col, Grob *next_col) { - Spring_smob *spring = 0; + Spring *spring = 0; for (SCM s = this_col->get_object ("ideal-distances"); !spring && scm_is_pair (s); s = scm_cdr (s)) { - Spring_smob *sp = unsmob_spring (scm_car (s)); - - if (sp && sp->other_ == next_col) - spring = sp; + if (scm_is_pair (scm_car (s)) + && unsmob_grob (scm_cdar (s)) == next_col + && unsmob_spring (scm_caar (s))) + spring = unsmob_spring (scm_caar (s)); } if (!spring) programming_error (_f ("No spring between column %d and next one", Paper_column::get_rank (this_col))); - *dist = (spring) ? spring->distance_ : 5.0; - *inv_strength = (spring) ? spring->inverse_strength_ : 1.0; + return spring ? *spring : Spring (); } diff --git a/lily/spacing-basic.cc b/lily/spacing-basic.cc index e0d9daaa00..bed086a72c 100644 --- a/lily/spacing-basic.cc +++ b/lily/spacing-basic.cc @@ -14,6 +14,8 @@ #include "warn.hh" #include "pointer-group-interface.hh" #include "system.hh" +#include "spacing-interface.hh" +#include "spring.hh" /* LilyPond spaces by taking a simple-minded spacing algorithm, and @@ -24,33 +26,11 @@ The one-size-fits all spacing. It doesn't take into account different spacing wishes from one to the next column. */ -void -Spacing_spanner::standard_breakable_column_spacing (Grob *me, Item *l, Item *r, - Real *fixed, Real *space, - Spacing_options const *options) +Spring +Spacing_spanner::standard_breakable_column_spacing (Grob *me, Item *l, Item *r, Spacing_options const *options) { - *fixed = 0.0; - Direction d = LEFT; - Drul_array cols (l, r); - - do - { - /* - TODO: this is fishy, the extent gets distorted due to wide - \marks, so better not do this. - */ - if (!Paper_column::is_musical (cols[d])) - { - /* - Tied accidentals over barlines cause problems, so lets see - what happens if we do this for non musical columns only. - */ - Interval lext = cols[d]->extent (cols [d], X_AXIS); - if (!lext.is_empty ()) - *fixed += -d * lext[-d]; - } - } - while (flip (&d) != LEFT); + Real min_dist = max (0.0, Paper_column::minimum_distance (l, r)); + Real ideal; if (Paper_column::is_breakable (l) && Paper_column::is_breakable (r)) { @@ -61,7 +41,7 @@ Spacing_spanner::standard_breakable_column_spacing (Grob *me, Item *l, Item *r, Real incr = robust_scm2double (me->get_property ("spacing-increment"), 1); - *space = *fixed + incr * double (mlen.main_part_ / options->global_shortest_) * 0.8; + ideal = min_dist + incr * double (mlen.main_part_ / options->global_shortest_) * 0.8; } else { @@ -73,14 +53,12 @@ Spacing_spanner::standard_breakable_column_spacing (Grob *me, Item *l, Item *r, In this case, Staff_spacing should handle the job, using dt when it is 0 is silly. */ - *space = *fixed + 0.5; + ideal = min_dist + 0.5; } else - { - bool dummy; - *space = *fixed + options->get_duration_space (dt.main_part_, &dummy); - } + ideal = min_dist + options->get_duration_space (dt.main_part_); } + return Spring (ideal, min_dist); } Moment * @@ -106,8 +84,7 @@ get_measure_length (Grob *column) Real Spacing_spanner::note_spacing (Grob *me, Grob *lc, Grob *rc, - Spacing_options const *options, - bool *expand_only) + Spacing_options const *options) { (void) me; @@ -151,8 +128,7 @@ Spacing_spanner::note_spacing (Grob *me, Grob *lc, Grob *rc, Real dist = 0.0; if (delta_t.main_part_ && !lwhen.grace_part_) { - dist = options->get_duration_space (shortest_playing_len.main_part_, - expand_only); + dist = options->get_duration_space (shortest_playing_len.main_part_); dist *= double (delta_t.main_part_ / shortest_playing_len.main_part_); } else if (delta_t.grace_part_) @@ -162,14 +138,13 @@ Spacing_spanner::note_spacing (Grob *me, Grob *lc, Grob *rc, available (namely the space for the global shortest note), and multiply that by grace-space-factor */ - dist = options->get_duration_space (options->global_shortest_, expand_only) / 2.0; + dist = options->get_duration_space (options->global_shortest_) / 2.0; Grob *grace_spacing = unsmob_grob (lc->get_object ("grace-spacing")); if (grace_spacing) { Spacing_options grace_opts; grace_opts.init_from_grob (grace_spacing); - bool bla; - dist = grace_opts.get_duration_space (delta_t.grace_part_, &bla); + dist = grace_opts.get_duration_space (delta_t.grace_part_); } } diff --git a/lily/spacing-determine-loose-columns.cc b/lily/spacing-determine-loose-columns.cc index 920e66bd03..5b13c82264 100644 --- a/lily/spacing-determine-loose-columns.cc +++ b/lily/spacing-determine-loose-columns.cc @@ -14,6 +14,7 @@ #include "paper-column.hh" #include "column-x-positions.hh" #include "pointer-group-interface.hh" +#include "spacing-interface.hh" #include "spacing-spanner.hh" #include "note-spacing.hh" #include "moment.hh" @@ -86,7 +87,7 @@ is_loose_column (Grob *l, Grob *col, Grob *r, Spacing_options const *options) return false; l_neighbor = l_neighbor->get_column (); - r_neighbor = dynamic_cast (Note_spacing::right_column (r_neighbor)); + r_neighbor = dynamic_cast (Spacing_interface::right_column (r_neighbor)); if (l == l_neighbor && r == r_neighbor) return false; @@ -143,8 +144,8 @@ Spacing_spanner::set_distances_for_loose_col (Grob *me, Grob *c, for (vsize k = wishes.size (); k--;) { Grob *sp = wishes[k]; - if (Note_spacing::left_column (sp) != lc - || Note_spacing::right_column (sp) != rc) + if (Spacing_interface::left_column (sp) != lc + || Spacing_interface::right_column (sp) != rc) continue; if (Note_spacing::has_interface (sp)) @@ -153,26 +154,16 @@ Spacing_spanner::set_distances_for_loose_col (Grob *me, Grob *c, The note spacing should be taken from the musical columns. */ - Real space = 0.0; - Real fixed = 0.0; - bool dummy = false; - - Real base = note_spacing (me, lc, rc, options, &dummy); - Note_spacing::get_spacing (sp, rc, base, options->increment_, - &space, &fixed); + Real base = note_spacing (me, lc, rc, options); + Spring spring = Note_spacing::get_spacing (sp, rc, base, options->increment_); - space -= options->increment_; - - dists[d] = max (dists[d], space); + dists[d] = max (dists[d], spring.distance () - options->increment_); } else if (Staff_spacing::has_interface (sp)) { - Real space = 0; - Real fixed_space = 0; - Staff_spacing::get_spacing_params (sp, - &space, &fixed_space); + Spring spring = Staff_spacing::get_spacing (sp, rc); - dists[d] = max (dists[d], fixed_space); + dists[d] = max (dists[d], spring.min_distance ()); } else programming_error ("Subversive spacing wish"); @@ -279,7 +270,7 @@ Spacing_spanner::set_explicit_neighbor_columns (vector const &cols) Item *wish = dynamic_cast (wishes[k]); Item *lc = wish->get_column (); - Grob *right = Note_spacing::right_column (wish); + Grob *right = Spacing_interface::right_column (wish); if (!right) continue; diff --git a/lily/spacing-interface.cc b/lily/spacing-interface.cc new file mode 100644 index 0000000000..dbfe4e43c6 --- /dev/null +++ b/lily/spacing-interface.cc @@ -0,0 +1,176 @@ +/* + spacing-interface.cc -- functionality that is shared between Note_spacing + and Staff_spacing + + source file of the GNU LilyPond music typesetter + + (c) 2007 Joe Neeman +*/ + +#include "spacing-interface.hh" + +#include "grob.hh" +#include "grob-array.hh" +#include "item.hh" +#include "note-column.hh" +#include "pointer-group-interface.hh" +#include "paper-column.hh" +#include "separation-item.hh" +#include "skyline.hh" + +/* return the right-pointing skyline of the left-items and the left-pointing + skyline of the right-items (with the skyline of the left-items in + ret[LEFT]) */ +Drul_array +Spacing_interface::skylines (Grob *me, Grob *right_col) +{ + /* the logic here is a little convoluted. + A {Staff,Note}_spacing doesn't copy left-items when it clones, + so in order to find the separation items, we need to use the original + spacing grob. But once we find the separation items, we need to get back + the broken piece. + */ + + Grob *orig = me->original () ? me->original () : me; + Drul_array break_dirs (dynamic_cast (me)->break_status_dir (), + dynamic_cast (right_col)->break_status_dir ()); + Drul_array skylines = Drul_array (Skyline (RIGHT), Skyline (LEFT)); + Drul_array > items (ly_scm2link_array (orig->get_object ("left-items")), + ly_scm2link_array (orig->get_object ("right-items"))); + + Direction d = LEFT; + do + { + skylines[d].set_minimum_height (0.0); + + for (vsize i = 0; i < items[d].size (); i++) + { + Grob *g = items[d][i]; + if (Item *it = dynamic_cast (g)) + if (Grob *piece = it->find_prebroken_piece (break_dirs[d])) + g = piece; + + if (Separation_item::has_interface (g)) + { + SCM sky_scm = g->get_property ("horizontal-skylines"); + Skyline_pair *sky = Skyline_pair::unsmob (sky_scm); + if (sky) + skylines[d].merge ((*sky)[-d]); + else + programming_error ("separation item has no skyline"); + + if (d == RIGHT && items[LEFT].size ()) + skylines[d].merge (Separation_item::conditional_skyline (items[d][i], items[LEFT][0])); + } + } + } + while (flip (&d) != LEFT); + + return skylines; +} + +Real +Spacing_interface::minimum_distance (Grob *me, Grob *right) +{ + Drul_array skylines = Spacing_interface::skylines (me, right); + + return max (0.0, skylines[LEFT].distance (skylines[RIGHT])); +} + +/* + Compute the column of the right-items. This is a big function, + since RIGHT-ITEMS may span more columns (eg. if a clef is inserted, + this will add a new column to RIGHT-ITEMS. Here we look at the + columns, and return the left-most. If there are multiple columns, we + prune RIGHT-ITEMS. +*/ +Item * +Spacing_interface::right_column (Grob *me) +{ + if (!me->is_live ()) + return 0; + + Grob_array *a = unsmob_grob_array (me->get_object ("right-items")); + Item *mincol = 0; + int min_rank = INT_MAX; + bool prune = false; + for (vsize i = 0; a && i < a->size (); i++) + { + Item *ri = a->item (i); + Item *col = ri->get_column (); + + int rank = Paper_column::get_rank (col); + + if (rank < min_rank) + { + min_rank = rank; + if (mincol) + prune = true; + + mincol = col; + } + } + + if (prune && a) + { + vector &right = a->array_reference (); + for (vsize i = right.size (); i--;) + { + if (dynamic_cast (right[i])->get_column () != mincol) + right.erase (right.begin () + i); + } + } + + return mincol; +} + +Item * +Spacing_interface::left_column (Grob *me) +{ + if (!me->is_live ()) + return 0; + + return dynamic_cast (me)->get_column (); +} + +static vector +get_note_columns (vector const &elts) +{ + vector ret; + + for (vsize i = 0; i < elts.size (); i++) + { + if (Note_column::has_interface (elts[i])) + ret.push_back (dynamic_cast (elts[i])); + else if (Separation_item::has_interface (elts[i])) + { + extract_grob_set (elts[i], "elements", more_elts); + vector ncs = get_note_columns (more_elts); + + ret.insert (ret.end (), ncs.begin (), ncs.end ()); + } + } + + return ret; +} + +vector +Spacing_interface::right_note_columns (Grob *me) +{ + extract_grob_set (me, "right-items", elts); + return get_note_columns (elts); +} + +vector +Spacing_interface::left_note_columns (Grob *me) +{ + extract_grob_set (me, "left-items", elts); + return get_note_columns (elts); +} + +ADD_INTERFACE (Spacing_interface, + "This object calculates the desired and minimum distances between two columns.", + + "left-items " + "right-items " + ); diff --git a/lily/spacing-loose-columns.cc b/lily/spacing-loose-columns.cc index 3a69e26802..a59fa7d0f9 100644 --- a/lily/spacing-loose-columns.cc +++ b/lily/spacing-loose-columns.cc @@ -119,23 +119,19 @@ set_loose_columns (System *which, Column_x_positions const *posns) else programming_error ("Column without spacing object"); - bool expand_only = false; Real base_note_space = 0.0; if (Paper_column::is_musical (next_col) && Paper_column::is_musical (loose_col)) - base_note_space = Spacing_spanner::note_spacing (spacing, loose_col, next_col, - &options, &expand_only); + base_note_space = Spacing_spanner::note_spacing (spacing, loose_col, next_col, + &options); else { - Real fixed, space; - - Spacing_spanner::standard_breakable_column_spacing (spacing, - loose_col, next_col, - &fixed, &space, - &options); - - base_note_space = space; + Spring spring = Spacing_spanner::standard_breakable_column_spacing (spacing, + loose_col, next_col, + &options); + + base_note_space = spring.distance (); } base_note_space = max (base_note_space, diff --git a/lily/spacing-options.cc b/lily/spacing-options.cc index 8c7b7c3ca5..a3e512525b 100644 --- a/lily/spacing-options.cc +++ b/lily/spacing-options.cc @@ -56,8 +56,7 @@ Spacing_options::Spacing_options () Get the measure wide ant for arithmetic spacing. */ Real -Spacing_options::get_duration_space (Rational d, - bool *expand_only) const +Spacing_options::get_duration_space (Rational d) const { Real k = shortest_duration_space_; @@ -92,7 +91,6 @@ Spacing_options::get_duration_space (Rational d, */ Real log = log_2 (global_shortest_); k -= log; - *expand_only = false; return (log_2 (d) + k) * increment_; } diff --git a/lily/spacing-spanner.cc b/lily/spacing-spanner.cc index a61bffb98a..d878c58b7f 100644 --- a/lily/spacing-spanner.cc +++ b/lily/spacing-spanner.cc @@ -11,8 +11,6 @@ #include #include -using namespace std; - #include "spacing-options.hh" #include "international.hh" #include "main.hh" @@ -22,6 +20,7 @@ using namespace std; #include "paper-column.hh" #include "paper-score.hh" #include "pointer-group-interface.hh" +#include "separation-item.hh" #include "spaceable-grob.hh" #include "spacing-interface.hh" #include "staff-spacing.hh" @@ -167,15 +166,10 @@ Spacing_spanner::generate_pair_spacing (Grob *me, { if (Paper_column::is_musical (left_col)) { - bool skip_unbroken_right = false; - if (!Paper_column::is_musical (right_col) && options->float_nonmusical_columns_ && after_right_col && Paper_column::is_musical (after_right_col)) - skip_unbroken_right = true; - - if (skip_unbroken_right) { /* TODO: should generate rods to prevent collisions. @@ -214,6 +208,49 @@ Spacing_spanner::generate_pair_spacing (Grob *me, } } +static void +set_column_rods (vector const &cols, vsize idx, Real padding) +{ + + /* + This is an inner loop: look for the first normal (unbroken) Left + grob. This looks like an inner loop (ie. quadratic total), but in + most cases, the interesting L will just be the first entry of + NEXT, making it linear in most of the cases. + */ + Item *r = dynamic_cast (cols[idx]); + + if (Separation_item::is_empty (r)) + return; + + while (idx--) + { + Item *l = dynamic_cast (cols[idx]); + Item *lb = l->find_prebroken_piece (RIGHT); + + if (Separation_item::is_empty (l) && (!lb || Separation_item::is_empty (lb))) + continue; + + Separation_item::set_distance (Drul_array (l, r), padding); + if (lb) + Separation_item::set_distance (Drul_array (lb, r), padding); + + + /* + This check is because grace notes are set very tight, and + the accidentals of main note may stick out so far to cover + a barline preceding the grace note. + */ + if (spanned_time_interval (l, r).length ().main_part_ > Rational (0)) + break; + + /* + this grob doesn't cause a constraint. We look further until we + find one that does. + */ + } +} + void Spacing_spanner::generate_springs (Grob *me, vector const &cols, @@ -226,15 +263,17 @@ Spacing_spanner::generate_springs (Grob *me, Paper_column *next = (i + 1 < cols.size ()) ? dynamic_cast (cols[i+1]) : 0; if (i > 0) - generate_pair_spacing (me, prev, col, next, options); + { + generate_pair_spacing (me, prev, col, next, options); + set_column_rods (cols, i, 0.1); // FIXME + } prev = col; } } /* - Generate the space between two musical columns LEFT_COL and RIGHT_COL, given - spacing parameters INCR and SHORTEST. + Generate the space between two musical columns LEFT_COL and RIGHT_COL. */ void Spacing_spanner::musical_column_spacing (Grob *me, @@ -242,45 +281,22 @@ Spacing_spanner::musical_column_spacing (Grob *me, Item *right_col, Spacing_options const *options) { - bool expand_only = false; - Real base_note_space = note_spacing (me, left_col, right_col, options, &expand_only); - - Real max_fixed = 0; - Real max_space = 0; - Real compound_note_space = 0.0; - Real compound_fixed_note_space = 0.0; + Real base_note_space = note_spacing (me, left_col, right_col, options); + Spring spring; if (options->stretch_uniformly_) - { - compound_note_space = base_note_space; - - if (!Paper_column::is_musical (right_col)) - { - /* - Crude fix for notes that lead up to barlines and time sigs. - */ - Interval lext = right_col->extent (right_col, X_AXIS); - if (!lext.is_empty ()) - compound_note_space += -lext[LEFT]; - } - } + spring = Spring (base_note_space, 0.0); else { - int wish_count = 0; - + vector springs; extract_grob_set (left_col, "right-neighbors", neighbors); - /* - We adjust the space following a note only if the next note - happens after the current note (this is set in the grob - property SPACING-SEQUENCE. - */ for (vsize i = 0; i < neighbors.size (); i++) { Grob *wish = neighbors[i]; - Item *wish_rcol = Note_spacing::right_column (wish); - if (Note_spacing::left_column (wish) != left_col + Item *wish_rcol = Spacing_interface::right_column (wish); + if (Spacing_interface::left_column (wish) != left_col || (wish_rcol != right_col && wish_rcol != right_col->original ())) continue; @@ -288,32 +304,10 @@ Spacing_spanner::musical_column_spacing (Grob *me, This is probably a waste of time in the case of polyphonic music. */ if (Note_spacing::has_interface (wish)) - { - Real space = 0.0; - Real fixed = 0.0; - - Note_spacing::get_spacing (wish, right_col, base_note_space, options->increment_, &space, &fixed); - - - max_space = max (max_space, space); - max_fixed = max (max_fixed, fixed); - - compound_note_space += space; - compound_fixed_note_space += fixed; - wish_count++; - } + springs.push_back (Note_spacing::get_spacing (wish, right_col, base_note_space, options->increment_)); } - if (Paper_column::when_mom (right_col).grace_part_ - && !Paper_column::when_mom (left_col).grace_part_) - { - /* - Ugh. 0.8 is arbitrary. - */ - compound_note_space *= 0.8; - } - - if (compound_note_space < 0 || wish_count == 0) + if (springs.empty ()) { if (!Paper_column::is_musical (right_col)) @@ -324,9 +318,8 @@ Spacing_spanner::musical_column_spacing (Grob *me, spacing, because the width of s^"text" output is also taken into account here. */ - compound_fixed_note_space = options->increment_; - compound_note_space = max (base_note_space, - options->increment_); + spring = Spring (max (base_note_space, options->increment_), + options->increment_); } else { @@ -334,44 +327,30 @@ Spacing_spanner::musical_column_spacing (Grob *me, Fixed should be 0.0. If there are no spacing wishes, we're likely dealing with polyphonic spacing of hemiolas. - We used to have compound_fixed_note_space = options->increment_ + We used to have min_distance_ = options->increment_ but this can lead to numeric instability problems when we do - inverse_strength = (compound_note_space - compound_fixed_note_space) + inverse_strength = (distance_ - min_distance_) */ - - compound_note_space = base_note_space; - compound_fixed_note_space = 0.0; + spring = Spring (base_note_space, 0.0); } } - else if (to_boolean (me->get_property ("average-spacing-wishes"))) - { - compound_note_space /= wish_count; - compound_fixed_note_space /= wish_count; - } else - { - compound_fixed_note_space = max_fixed; - compound_note_space = max_space; - } + spring = merge_springs (springs); + } + if (Paper_column::when_mom (right_col).grace_part_ + && !Paper_column::when_mom (left_col).grace_part_) + { /* - Whatever we do, the fixed space is smaller than the real - space. - - TODO: this criterion is discontinuous in the derivative. - Maybe it should be continuous? + Ugh. 0.8 is arbitrary. */ - compound_fixed_note_space = min (compound_fixed_note_space, - compound_note_space); + spring *= 0.8; } - Real inverse_strength = 1.0; - Real distance = 1.0; - /* TODO: make sure that the space doesn't exceed the right margin. */ @@ -386,16 +365,11 @@ Spacing_spanner::musical_column_spacing (Grob *me, pack as much bars of music as possible into a line, but the line will then be stretched to fill the whole linewidth. */ - inverse_strength = 1.0; - distance = compound_fixed_note_space; - } - else - { - inverse_strength = (compound_note_space - compound_fixed_note_space); - distance = compound_note_space; + spring.set_distance (spring.min_distance ()); + spring.set_inverse_stretch_strength (1.0); } - Spaceable_grob::add_spring (left_col, right_col, distance, inverse_strength); + Spaceable_grob::add_spring (left_col, right_col, spring); } /* @@ -441,12 +415,8 @@ void Spacing_spanner::breakable_column_spacing (Grob *me, Item *l, Item *r, Spacing_options const *options) { - Real compound_fixed = 0.0; - Real compound_space = 0.0; - Real max_fixed = 0.0; - Real max_space = 0.0; - - int wish_count = 0; + vector springs; + Spring spring; Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l); @@ -461,74 +431,46 @@ Spacing_spanner::breakable_column_spacing (Grob *me, Item *l, Item *r, if (!spacing_grob || !Staff_spacing::has_interface (spacing_grob)) continue; - Real space = 0.; - Real fixed_space = 0.; - /* column for the left one settings should be ok due automatic pointer munging. */ assert (spacing_grob->get_column () == l); - Staff_spacing::get_spacing_params (spacing_grob, - &space, &fixed_space); - - if (Paper_column::when_mom (r).grace_part_) - { - /* - Correct for grace notes. - - Ugh. The 0.8 is arbitrary. - */ - space *= 0.8; - } - - max_space = max (max_space, space); - max_fixed = max (max_fixed, fixed_space); - - compound_space += space; - compound_fixed += fixed_space; - wish_count++; + springs.push_back (Staff_spacing::get_spacing (spacing_grob, r)); } } - if (compound_space <= 0.0 || !wish_count) - { - standard_breakable_column_spacing (me, l, r, &compound_fixed, &compound_space, - options); - wish_count = 1; - } + if (springs.empty ()) + spring = standard_breakable_column_spacing (me, l, r, options); else + spring = merge_springs (springs); + + if (Paper_column::when_mom (r).grace_part_) { - if (to_boolean (me->get_property ("average-spacing-wishes"))) - { - compound_space /= wish_count; - compound_fixed /= wish_count; - } - else - { - compound_fixed = max_fixed; - compound_space = max_space; - } - + /* + Correct for grace notes. + + Ugh. The 0.8 is arbitrary. + */ + spring *= 0.8; } if (Paper_column::is_musical (r) && l->break_status_dir () == CENTER && fills_measure (me, l, r)) { - compound_space += 1.0; + spring.set_distance (spring.distance () + 1.0); + spring.set_default_strength (); } if (options->stretch_uniformly_ && l->break_status_dir () != RIGHT) - compound_fixed = 0.0; - - assert (!isinf (compound_space)); - compound_space = max (compound_space, compound_fixed); + { + spring.set_min_distance (0.0); + spring.set_default_strength (); + } - Real inverse_strength = (compound_space - compound_fixed); - Real distance = compound_space; - Spaceable_grob::add_spring (l, r, distance, inverse_strength); + Spaceable_grob::add_spring (l, r, spring); } ADD_INTERFACE (Spacing_spanner, diff --git a/lily/spring-smob.cc b/lily/spring-smob.cc index a57f5029f2..5639a1cd07 100644 --- a/lily/spring-smob.cc +++ b/lily/spring-smob.cc @@ -10,18 +10,10 @@ #include "warn.hh" #include "ly-smobs.icc" -Spring_smob::Spring_smob () -{ - distance_ = 0.; - inverse_strength_ = 1.0; - expand_only_b_ = false; - other_ = 0; -} - -IMPLEMENT_SIMPLE_SMOBS (Spring_smob); +IMPLEMENT_SIMPLE_SMOBS (Spring); SCM -Spring_smob::mark_smob (SCM x) +Spring::mark_smob (SCM x) { (void)x; @@ -29,14 +21,14 @@ Spring_smob::mark_smob (SCM x) } int -Spring_smob::print_smob (SCM, SCM p, scm_print_state *) +Spring::print_smob (SCM, SCM p, scm_print_state *) { scm_puts ("#", p); return 1; } SCM -Spring_smob::equal_p (SCM a, SCM b) +Spring::equal_p (SCM a, SCM b) { return a == b? SCM_BOOL_T : SCM_BOOL_F; } diff --git a/lily/spring.cc b/lily/spring.cc new file mode 100644 index 0000000000..679ccfa29d --- /dev/null +++ b/lily/spring.cc @@ -0,0 +1,156 @@ +/* + spring.cc -- declare Spring + + source file of the GNU LilyPond music typesetter + + (c) 2007 Joe Neeman +*/ + +#include "spring.hh" + +Spring::Spring () +{ + distance_ = 1.0; + min_distance_ = 1.0; + inverse_stretch_strength_ = 1.0; + inverse_compress_strength_ = 1.0; + + update_blocking_force (); +} + +Spring::Spring (Real dist, Real min_dist) +{ + distance_ = 1.0; + min_distance_ = 1.0; + + set_distance (dist); + set_min_distance (min_dist); + set_default_strength (); + update_blocking_force (); +} + +void +Spring::update_blocking_force () +{ + if (distance_ == min_distance_) + blocking_force_ = 0.0; + else + blocking_force_ = (min_distance_ - distance_) / inverse_compress_strength_; +} + +/* scale a spring, but in a way that doesn't violate min_distance */ +void +Spring::operator*= (Real r) +{ + distance_ = max (min_distance_, distance_ * r); + inverse_compress_strength_ = distance_ - min_distance_; + inverse_stretch_strength_ *= 0.8; +} + +bool +Spring::operator> (Spring const &other) const +{ + return blocking_force_ > other.blocking_force_; +} + +/* merge springs, basically by averaging them, but leave a little headroom + above the largest minimum distance so that things don't get too cramped */ +Spring +merge_springs (vector const &springs) +{ + Real avg_distance = 0; + Real min_distance = 0; + Real avg_stretch = 0; + + for (vsize i = 0; i < springs.size (); i++) + { + avg_distance += springs[i].distance (); + avg_stretch += springs[i].inverse_stretch_strength (); + min_distance = max (springs[i].min_distance (), min_distance); + } + + avg_stretch /= springs.size (); + avg_distance /= springs.size (); + avg_distance = max (min_distance + 0.3, avg_distance); + + Spring ret = Spring (avg_distance, min_distance); + ret.set_inverse_stretch_strength (avg_stretch); + + return ret; +} + +void +Spring::set_distance (Real d) +{ + if (d < 0 || isinf (d) || isnan (d)) + programming_error ("insane spring distance requested, ignoring it"); + else + { + min_distance_ = min (min_distance_, d); + distance_ = d; + update_blocking_force (); + } +} + +void +Spring::set_min_distance (Real d) +{ + if (d < 0 || isinf (d) || isnan (d)) + programming_error ("insane spring min_distance requested, ignoring it"); + else + { + min_distance_ = d; + distance_ = max (distance_, min_distance_); + update_blocking_force (); + } +} + +void +Spring::set_inverse_stretch_strength (Real f) +{ + if (isinf (f) || isnan (f) || f < 0) + programming_error ("insane spring constant"); + else + inverse_stretch_strength_ = f; +} + +void +Spring::set_inverse_compress_strength (Real f) +{ + if (isinf (f) || isnan (f) || f < 0) + programming_error ("insane spring constant"); + else + inverse_compress_strength_ = f; + + update_blocking_force (); +} + +void +Spring::set_blocking_force (Real f) +{ + if (isinf (f) || isnan (f)) + { + programming_error ("insane blocking force"); + return; + } + + blocking_force_ = -infinity_f; + min_distance_ = length (f); + distance_ = max (distance_, min_distance_); + update_blocking_force (); +} + +void +Spring::set_default_strength () +{ + inverse_compress_strength_ = distance_ - min_distance_; + inverse_stretch_strength_ = distance_ - min_distance_; +} + +Real +Spring::length (Real f) const +{ + Real force = max (f, blocking_force_); + Real inv_k = force < 0.0 ? inverse_compress_strength_ : inverse_stretch_strength_; + return distance_ + force * inv_k; +} diff --git a/lily/staff-spacing.cc b/lily/staff-spacing.cc index 79e7028644..8a8822a803 100644 --- a/lily/staff-spacing.cc +++ b/lily/staff-spacing.cc @@ -11,6 +11,7 @@ #include using namespace std; +#include "international.hh" #include "paper-column.hh" #include "separation-item.hh" #include "warn.hh" @@ -18,74 +19,28 @@ using namespace std; #include "staff-symbol-referencer.hh" #include "note-column.hh" #include "stem.hh" +#include "spacing-interface.hh" #include "accidental-placement.hh" #include "pointer-group-interface.hh" #include "directional-element-interface.hh" -/* - Insert some more space for the next note, in case it has a stem in - the wrong direction +/* A stem following a bar-line creates an optical illusion similar to the + one mentioned in note-spacing.cc. We correct for it here. + + TODO: should we still correct if there are accidentals/arpeggios before + the stem? */ -void -Staff_spacing::next_note_correction (Grob *me, - Grob *g, - Interval bar_size, - Real current_space, Real current_fixed, - Real *space, - Real *fix, - int *wish_count) + +Real +Staff_spacing::optical_correction (Grob *me, Grob *g, Interval bar_height) { - (void) current_fixed; if (!g || !Note_column::has_interface (g)) - return ; + return 0; - Item *col = dynamic_cast (g)->get_column (); - Real left_stickout_correction = max (0., (- g->extent (col, X_AXIS)[LEFT])); - - /* staff space -> positions */ - bar_size *= 2; - - /* - Duh. If this gets out of hand, we should invent something more generic. - */ - Grob *accs = Note_column::accidentals (g); - if (accs) - { - Interval v; - if (Accidental_placement::has_interface (accs)) - v = Accidental_placement::get_relevant_accidental_extent (accs, col, me); - else - v = accs->extent (col, X_AXIS); - - left_stickout_correction = max (left_stickout_correction, (- v[LEFT])); - } - Grob *arpeggio = unsmob_grob (g->get_object ("arpeggio")); - if (arpeggio) - left_stickout_correction = max (left_stickout_correction, - arpeggio->extent (col, X_AXIS)[LEFT]); - - - /* - Let's decrease the space a little if the problem is not located - after a barline. - */ - if (bar_size.is_empty ()) - left_stickout_correction *= 0.75; - - /* - We want 0.3 ss before the sticking-out object. - - current_fixed/2 is our guess at (right side of left object + 0.3) - */ - left_stickout_correction += current_fixed/2 - current_space; - left_stickout_correction = max (left_stickout_correction, 0.0); - - - Real optical_corr = 0.0; Grob *stem = Note_column::get_stem (g); - if (!bar_size.is_empty () - && !arpeggio - && !accs - && stem) + Real ret = 0.0; + + if (!bar_height.is_empty () && stem) { Direction d = get_grob_direction (stem); if (Stem::is_normal_stem (stem) && d == DOWN) @@ -102,28 +57,15 @@ Staff_spacing::next_note_correction (Grob *me, Interval stem_posns (min (stem_start, stem_end), max (stem_end, stem_start)); - stem_posns.intersect (bar_size); + stem_posns.intersect (bar_height); - optical_corr = min (abs (stem_posns.length () / 7.0), 1.0); - optical_corr *= robust_scm2double (me->get_property ("stem-spacing-correction"), 1); + ret = min (abs (stem_posns.length () / 7.0), 1.0); + ret *= robust_scm2double (me->get_property ("stem-spacing-correction"), 1); } } - - - Real correction = optical_corr + left_stickout_correction; - if (correction) - { - (*wish_count) ++; - - /* - This minute adjustments don't make sense for widely spaced scores. - Hence, we need to keep the stretchable (that is, space - fix) - distance equal. - */ - *space += correction; - *fix += correction; - } + return ret; } + /* Y-positions that are covered by BAR_GROB, in the case that it is a barline. */ @@ -149,95 +91,35 @@ Staff_spacing::bar_y_positions (Grob *bar_grob) return bar_size; } -/* - Do corrections for the following notes. - - This is slightly convoluted, since the staffspacing grob gets - pointers to the separation-items, not the note-columns or - note-spacings. -*/ - -void -Staff_spacing::next_notes_correction (Grob *me, Grob *last_grob, - Real current_space, Real current_fixed, - Real *compound_space, Real *compound_fixed - ) +Real +Staff_spacing::next_notes_correction (Grob *me, + Grob *last_grob) { Interval bar_size = bar_y_positions (last_grob); + Grob *orig = me->original () ? me->original () : me; + vector note_columns = Spacing_interface::right_note_columns (orig); - extract_grob_set (me, "right-items", right_items); + Real max_optical = 0.0; - *compound_fixed = 0.0; - *compound_space = 0.0; - int wish_count = 0; + for (vsize i = 0; i < note_columns.size (); i++) + max_optical = max (max_optical, optical_correction (me, note_columns[i], bar_size)); - for (vsize i = right_items.size (); i--;) - { - Grob *g = right_items[i]; - if (Note_column::has_interface (right_items[i])) - { - Grob *g = right_items[i]; - - Real space = 0.0; - Real fixed = 0.0; - - next_note_correction (me, g, bar_size, - current_space, current_fixed, - &space, &fixed, &wish_count); - - *compound_space += space; - *compound_fixed += fixed; - } - else - { - extract_grob_set (g, "elements", elts); - for (vsize j = elts.size (); j--;) - { - Real space = 0.0; - Real fixed = 0.0; - next_note_correction (me, elts[j], bar_size, - current_space, current_fixed, - &space, &fixed, - &wish_count); - *compound_fixed += fixed; - *compound_space += space; - } - } - } - - if (wish_count > 1) - { - *compound_space /= wish_count; - *compound_fixed /= wish_count; - } + return max_optical; } -void -Staff_spacing::get_spacing_params (Grob *me, Real *space, Real *fixed) +/* We calculate three things here: the ideal distance, the minimum distance + (which is the distance at which collisions will occure) and the "fixed" + distance, which is the distance at which things start to look really bad. + We arrange things so that the fixed distance will be attained when the + line is compressed with a force of 1.0 */ +Spring +Staff_spacing::get_spacing (Grob *me, Grob *right_col) { - *space = 1.0; - *fixed = 1.0; - - Grob *separation_item = 0; Item *me_item = dynamic_cast (me); - - extract_grob_set (me, "left-items", items); - for (vsize i = items.size (); i--;) - { - Grob *cand = items[i]; - if (cand && Separation_item::has_interface (cand)) - separation_item = cand; - } - - // printf ("doing col %d\n" , Paper_column::get_rank (left_col)); - if (!separation_item) - { - programming_error ("no sep item"); - return; - } + Grob *left_col = me_item->get_column (); Interval last_ext; - Grob *last_grob = Separation_item::extremal_break_aligned_grob (separation_item, RIGHT, + Grob *last_grob = Separation_item::extremal_break_aligned_grob (left_col, RIGHT, &last_ext); if (!last_grob) { @@ -252,15 +134,12 @@ Staff_spacing::get_spacing_params (Grob *me, Real *space, Real *fixed) we used to have a warning here, but it generates a lot of spurious error messages. */ - return; + return Spring (); } - *fixed = last_ext[RIGHT]; - *space = *fixed + 1.0; - SCM alist = last_grob->get_property ("space-alist"); if (!scm_list_p (alist)) - return; + return Spring (); SCM space_def = scm_sloppy_assq (ly_symbol2scm ("first-note"), alist); if (me_item->break_status_dir () == CENTER) @@ -273,41 +152,50 @@ Staff_spacing::get_spacing_params (Grob *me, Real *space, Real *fixed) if (!scm_is_pair (space_def)) { programming_error ("unknown prefatory spacing"); - return; + return Spring (); } space_def = scm_cdr (space_def); Real distance = scm_to_double (scm_cdr (space_def)); SCM type = scm_car (space_def); - *fixed = last_ext[RIGHT]; + Real fixed = last_ext[RIGHT]; + Real ideal = fixed + 1.0; + if (type == ly_symbol2scm ("fixed-space")) { - *fixed += distance; - *space = *fixed; + fixed += distance; + ideal = fixed; } else if (type == ly_symbol2scm ("extra-space")) - *space = *fixed + distance; + ideal = fixed + distance; else if (type == ly_symbol2scm ("semi-fixed-space")) { - *fixed += distance / 2; - *space = *fixed + distance / 2; + fixed += distance / 2; + ideal = fixed + distance / 2; } else if (type == ly_symbol2scm ("minimum-space")) - *space = last_ext[LEFT] + max (last_ext.length (), distance); + ideal = last_ext[LEFT] + max (last_ext.length (), distance); else if (type == ly_symbol2scm ("minimum-fixed-space")) { - *space = last_ext[LEFT] + max (last_ext.length (), distance); - *fixed = *space; + fixed = last_ext[LEFT] + max (last_ext.length (), distance); + ideal = fixed; } - Real correction_fixed = 0.0; - Real correction_space = 0.0; - next_notes_correction (me, last_grob, - *space, *fixed, - &correction_space, &correction_fixed ); - *space += correction_space; - *fixed += correction_fixed; + + Real optical_correction = next_notes_correction (me, last_grob); + Real min_dist = Paper_column::minimum_distance (left_col, right_col); + + /* ensure that the "fixed" distance will leave a gap of at least 0.3 ss. */ + Real min_dist_correction = max (0.0, 0.3 + min_dist - fixed); + Real correction = max (optical_correction, min_dist_correction); + + fixed += correction; + ideal += correction; + + Spring ret (ideal, min_dist); + ret.set_inverse_stretch_strength (ideal - fixed); + return ret; } ADD_INTERFACE (Staff_spacing, @@ -317,6 +205,4 @@ ADD_INTERFACE (Staff_spacing, /* properties */ "stem-spacing-correction " - "left-items " - "right-items " ); diff --git a/lily/system.cc b/lily/system.cc index eb6d05a881..e8af537be1 100644 --- a/lily/system.cc +++ b/lily/system.cc @@ -19,7 +19,6 @@ #include "paper-score.hh" #include "paper-system.hh" #include "pointer-group-interface.hh" -#include "spacing-interface.hh" #include "staff-symbol-referencer.hh" #include "warn.hh" #include "lookup.hh" diff --git a/lily/tie-engraver.cc b/lily/tie-engraver.cc index bdcd3dbb36..cf525dc7b9 100644 --- a/lily/tie-engraver.cc +++ b/lily/tie-engraver.cc @@ -179,14 +179,9 @@ Tie_engraver::stop_translation_timestep () if (!wait) heads_to_tie_.clear (); - Grob *sep = unsmob_grob (get_property ("breakableSeparationItem")); for (vsize i = 0; i < ties_.size (); i++) - { - if (sep) - ties_[i]->set_object ("separation-item", sep->self_scm ()); - typeset_tie (ties_[i]); - } + ties_.clear (); tie_column_ = 0; } diff --git a/lily/tie-formatting-problem.cc b/lily/tie-formatting-problem.cc index 3105d784f1..3a8ed37a62 100644 --- a/lily/tie-formatting-problem.cc +++ b/lily/tie-formatting-problem.cc @@ -316,18 +316,9 @@ Tie_formatting_problem::from_ties (vector const &ties) { Item *it = dynamic_cast (ties[i])->get_bound (d); if (it->break_status_dir ()) - { - Item *sep - = dynamic_cast (unsmob_grob (ties[i]->get_object ("separation-item"))); - if (sep && sep->get_column () == it->get_column ()) - it = sep; + it = it->get_column (); - bounds.push_back (it); - } - else - { - bounds.push_back (it); - } + bounds.push_back (it); } set_chord_outline (bounds, d); diff --git a/ly/engraver-init.ly b/ly/engraver-init.ly index 7e8383b7f7..b564ad1445 100644 --- a/ly/engraver-init.ly +++ b/ly/engraver-init.ly @@ -416,7 +416,6 @@ printing of a single line of lyrics." % \consists "Note_spacing_engraver" voltaOnThisStaff = ##f \override VerticalAxisGroup #'minimum-Y-extent = #'(0 . 2) - \override SeparatingGroupSpanner #'padding = #0.8 \override VerticalAxisGroup #'remove-first = ##t \override VerticalAxisGroup #'remove-empty = ##t } diff --git a/scm/define-context-properties.scm b/scm/define-context-properties.scm index 1d0b28cf6c..05127f86d1 100644 --- a/scm/define-context-properties.scm +++ b/scm/define-context-properties.scm @@ -536,6 +536,8 @@ event types that should be duplicated for @code{\\quote} commands.") (instrumentSupport ,grob-list? "list of grobs to attach instrument name to.") (tieMelismaBusy ,boolean? "Signal whether a tie is present.") + (hasStaffSpacing ,boolean? "True if the currentCommandColumn contains items that will +affect spacing") ))) (define-public all-translation-properties diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm index c4dc73d095..0cdcf8f825 100644 --- a/scm/define-grob-properties.scm +++ b/scm/define-grob-properties.scm @@ -637,6 +637,7 @@ where this is set in.") (normal-stems ,ly:grob-array? "Array of visible stems.") (note-heads ,ly:grob-array? "List of note head grobs") (note-head ,ly:grob? "A single note head") + (pure-Y-offset-in-progress ,boolean? "A debugging aid for catching cyclic dependencies.") (right-items ,ly:grob-array? "") (right-neighbors ,ly:grob-array? "see left-neighbors") (separation-item ,ly:grob? "A separation item.") diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index c3315a3b42..6159e81f94 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -825,8 +825,7 @@ (direction . ,UP) (self-alignment-X . ,CENTER) (meta . ((class . Item) - (interfaces . (system-start-text-interface - side-position-interface + (interfaces . (side-position-interface font-interface)))))) (KeyCancellation @@ -1114,6 +1113,7 @@ (axes . (0)) (before-line-breaking . ,ly:paper-column::before-line-breaking) (X-extent . ,ly:axis-group-interface::width) + (horizontal-skylines . ,ly:separation-item::calc-skylines) ;; (stencil . ,ly:paper-column::print) (non-musical . #t) @@ -1126,6 +1126,7 @@ (meta . ((class . Paper_column) (interfaces . (paper-column-interface axis-group-interface + separation-item-interface spaceable-grob-interface)))))) (NoteCollision @@ -1143,8 +1144,10 @@ (axes . (0 1)) (X-extent . ,ly:axis-group-interface::width) (Y-extent . ,ly:axis-group-interface::height) + (horizontal-skylines . ,ly:separation-item::calc-skylines) (meta . ((class . Item) (interfaces . (axis-group-interface + separation-item-interface note-column-interface)))))) (NoteHead @@ -1171,7 +1174,7 @@ ;; If you ever change this back, please document! --hwn (knee-spacing-correction . 1.0) (meta . ((class . Item) - (interfaces . ( + (interfaces . (spacing-interface note-spacing-interface)))))) (NoteName @@ -1227,6 +1230,7 @@ (axes . (0)) (allow-loose-spacing . #t) (before-line-breaking . ,ly:paper-column::before-line-breaking) + (horizontal-skylines . ,ly:separation-item::calc-skylines) ;; (stencil . ,ly:paper-column::print) (X-extent . ,ly:axis-group-interface::width) @@ -1234,6 +1238,7 @@ ;; (font-size . -6) (font-name . "sans") (Y-extent . #f) (meta . ((class . Paper_column) (interfaces . (paper-column-interface + separation-item-interface axis-group-interface spaceable-grob-interface)))))) @@ -1329,6 +1334,7 @@ (list ly:self-alignment-interface::x-aligned-on-self))))) (Y-offset . ,ly:side-position-interface::y-aligned-side) + (extra-spacing-width . (+inf.0 . -inf.0)) (self-alignment-X . 0) (direction . ,UP) (non-musical . #t) @@ -1446,14 +1452,6 @@ (interfaces . ( separation-item-interface)))))) - (SeparatingGroupSpanner - . ( - (springs-and-rods . ,ly:separating-group-spanner::set-spacing-rods) - (meta . ((class . Spanner) - (interfaces . (only-prebreak-interface - - separating-group-spanner-interface)))))) - (Slur . ((details . ,default-slur-details) (control-points . ,ly:slur::calc-control-points) @@ -1560,7 +1558,8 @@ (non-musical . #t) (stem-spacing-correction . 0.4) (meta . ((class . Item) - (interfaces . (staff-spacing-interface)))))) + (interfaces . (spacing-interface + staff-spacing-interface)))))) (StaffSymbol diff --git a/scm/safe-lily.scm b/scm/safe-lily.scm index 12657af88a..8309ec390f 100644 --- a/scm/safe-lily.scm +++ b/scm/safe-lily.scm @@ -177,7 +177,6 @@ ly:piano-pedal-bracket::print ly:rest::print ly:script-interface::print - ly:separating-group-spanner::set-spacing-rods ly:slur::height ly:slur::print ly:spacing-spanner::set-springs