2 staff-spacing.cc -- implement Staff_spacing
4 source file of the GNU LilyPond music typesetter
6 (c) 2001--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
9 #include "staff-spacing.hh"
14 #include "international.hh"
15 #include "paper-column.hh"
16 #include "separation-item.hh"
18 #include "bar-line.hh"
19 #include "staff-symbol-referencer.hh"
20 #include "note-column.hh"
22 #include "spacing-interface.hh"
23 #include "accidental-placement.hh"
24 #include "pointer-group-interface.hh"
25 #include "directional-element-interface.hh"
27 /* A stem following a bar-line creates an optical illusion similar to the
28 one mentioned in note-spacing.cc. We correct for it here.
30 TODO: should we still correct if there are accidentals/arpeggios before
35 Staff_spacing::optical_correction (Grob *me, Grob *g, Interval bar_height)
37 if (!g || !Note_column::has_interface (g))
40 Grob *stem = Note_column::get_stem (g);
43 if (!bar_height.is_empty () && stem)
45 Direction d = get_grob_direction (stem);
46 if (Stem::is_normal_stem (stem) && d == DOWN)
50 can't look at stem-end-position, since that triggers
51 beam slope computations.
53 Real stem_start = Stem::head_positions (stem) [d];
54 Real stem_end = stem_start +
55 d * robust_scm2double (stem->get_property ("length"), 7);
57 Interval stem_posns (min (stem_start, stem_end),
58 max (stem_end, stem_start));
60 stem_posns.intersect (bar_height);
62 ret = min (abs (stem_posns.length () / 7.0), 1.0);
63 ret *= robust_scm2double (me->get_property ("stem-spacing-correction"), 1);
70 Y-positions that are covered by BAR_GROB, in the case that it is a
73 Staff_spacing::bar_y_positions (Grob *bar_grob)
76 bar_size.set_empty ();
77 if (Bar_line::has_interface (bar_grob))
79 SCM glyph = bar_grob->get_property ("glyph-name");
80 Grob *staff_sym = Staff_symbol_referencer::get_staff_symbol (bar_grob);
82 string glyph_string = scm_is_string (glyph) ? ly_scm2string (glyph) : "";
83 if (glyph_string.substr (0, 1) == "|"
84 || glyph_string.substr (0, 1) == ".")
86 Grob *common = bar_grob->common_refpoint (staff_sym, Y_AXIS);
87 bar_size = bar_grob->extent (common, Y_AXIS);
88 bar_size *= 1.0 / Staff_symbol_referencer::staff_space (bar_grob);
95 Staff_spacing::next_notes_correction (Grob *me,
98 Interval bar_size = bar_y_positions (last_grob);
99 Grob *orig = me->original () ? me->original () : me;
100 vector<Item*> note_columns = Spacing_interface::right_note_columns (orig);
102 Real max_optical = 0.0;
104 for (vsize i = 0; i < note_columns.size (); i++)
105 max_optical = max (max_optical, optical_correction (me, note_columns[i], bar_size));
110 /* We calculate three things here: the ideal distance, the minimum distance
111 (which is the distance at which collisions will occure) and the "fixed"
112 distance, which is the distance at which things start to look really bad.
113 We arrange things so that the fixed distance will be attained when the
114 line is compressed with a force of 1.0 */
116 Staff_spacing::get_spacing (Grob *me, Grob *right_col)
118 Item *me_item = dynamic_cast<Item *> (me);
119 Grob *left_col = me_item->get_column ();
122 Grob *last_grob = Separation_item::extremal_break_aligned_grob (left_col, RIGHT,
129 Should insert a adjustable space here? For excercises, you might want to
130 use a staff without a clef in the beginning.
134 we used to have a warning here, but it generates a lot of
135 spurious error messages.
140 SCM alist = last_grob->get_property ("space-alist");
141 if (!scm_list_p (alist))
144 SCM space_def = scm_sloppy_assq (ly_symbol2scm ("first-note"), alist);
145 if (me_item->break_status_dir () == CENTER)
147 SCM nndef = scm_sloppy_assq (ly_symbol2scm ("next-note"), alist);
148 if (scm_is_pair (nndef))
152 if (!scm_is_pair (space_def))
154 programming_error ("unknown prefatory spacing");
158 space_def = scm_cdr (space_def);
159 Real distance = scm_to_double (scm_cdr (space_def));
160 SCM type = scm_car (space_def);
162 Real fixed = last_ext[RIGHT];
163 Real ideal = fixed + 1.0;
165 if (type == ly_symbol2scm ("fixed-space"))
170 else if (type == ly_symbol2scm ("extra-space"))
171 ideal = fixed + distance;
172 else if (type == ly_symbol2scm ("semi-fixed-space"))
174 fixed += distance / 2;
175 ideal = fixed + distance / 2;
177 else if (type == ly_symbol2scm ("minimum-space"))
178 ideal = last_ext[LEFT] + max (last_ext.length (), distance);
179 else if (type == ly_symbol2scm ("minimum-fixed-space"))
181 fixed = last_ext[LEFT] + max (last_ext.length (), distance);
186 Real optical_correction = next_notes_correction (me, last_grob);
187 Real min_dist = Paper_column::minimum_distance (left_col, right_col);
189 /* ensure that the "fixed" distance will leave a gap of at least 0.3 ss. */
190 Real min_dist_correction = max (0.0, 0.3 + min_dist - fixed);
191 Real correction = max (optical_correction, min_dist_correction);
196 Spring ret (ideal, min_dist);
197 ret.set_inverse_stretch_strength (ideal - fixed);
201 ADD_INTERFACE (Staff_spacing,
202 "This object calculates spacing details from a "
203 " breakable symbol (left) to another object. For example, it takes care "
204 " of optical spacing from a bar lines to a note.",
207 "stem-spacing-correction "