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 Grob *separation_item = 0;
119 Item *me_item = dynamic_cast<Item *> (me);
121 extract_grob_set (me, "left-items", items);
122 for (vsize i = items.size (); i--;)
124 Grob *cand = items[i];
125 if (cand && Separation_item::has_interface (cand))
126 separation_item = cand;
129 // printf ("doing col %d\n" , Paper_column::get_rank (left_col));
130 if (!separation_item)
132 programming_error ("no sep item");
137 Grob *last_grob = Separation_item::extremal_break_aligned_grob (separation_item, RIGHT,
144 Should insert a adjustable space here? For excercises, you might want to
145 use a staff without a clef in the beginning.
149 we used to have a warning here, but it generates a lot of
150 spurious error messages.
155 SCM alist = last_grob->get_property ("space-alist");
156 if (!scm_list_p (alist))
159 SCM space_def = scm_sloppy_assq (ly_symbol2scm ("first-note"), alist);
160 if (me_item->break_status_dir () == CENTER)
162 SCM nndef = scm_sloppy_assq (ly_symbol2scm ("next-note"), alist);
163 if (scm_is_pair (nndef))
167 if (!scm_is_pair (space_def))
169 programming_error ("unknown prefatory spacing");
173 space_def = scm_cdr (space_def);
174 Real distance = scm_to_double (scm_cdr (space_def));
175 SCM type = scm_car (space_def);
177 Real fixed = last_ext[RIGHT];
178 Real ideal = fixed + 1.0;
180 if (type == ly_symbol2scm ("fixed-space"))
185 else if (type == ly_symbol2scm ("extra-space"))
186 ideal = fixed + distance;
187 else if (type == ly_symbol2scm ("semi-fixed-space"))
189 fixed += distance / 2;
190 ideal = fixed + distance / 2;
192 else if (type == ly_symbol2scm ("minimum-space"))
193 ideal = last_ext[LEFT] + max (last_ext.length (), distance);
194 else if (type == ly_symbol2scm ("minimum-fixed-space"))
196 fixed = last_ext[LEFT] + max (last_ext.length (), distance);
200 Grob *left_col = dynamic_cast<Item*> (me)->get_column ();
201 Real optical_correction = next_notes_correction (me, last_grob);
202 Real min_dist = Paper_column::minimum_distance (left_col, right_col);
204 /* ensure that the "fixed" distance will leave a gap of at least 0.3 ss. */
205 Real min_dist_correction = max (0.0, 0.3 + min_dist - fixed);
206 Real correction = max (optical_correction, min_dist_correction);
211 Spring ret (ideal, min_dist);
212 ret.set_inverse_stretch_strength (ideal - fixed);
216 ADD_INTERFACE (Staff_spacing,
217 "This object calculates spacing details from a "
218 " breakable symbol (left) to another object. For example, it takes care "
219 " of optical spacing from a bar lines to a note.",
222 "stem-spacing-correction "