Fixes Issue 1504, allowing feather beam line breaking.
[lilypond/patrick.git] / lily / staff-spacing.cc
blobff064b5c0f6a83455b4b9fd43de4f33046c17b89
1 /*
2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2001--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
20 #include "staff-spacing.hh"
22 #include <cstdio>
23 using namespace std;
25 #include "international.hh"
26 #include "paper-column.hh"
27 #include "separation-item.hh"
28 #include "warn.hh"
29 #include "bar-line.hh"
30 #include "staff-symbol-referencer.hh"
31 #include "note-column.hh"
32 #include "stem.hh"
33 #include "spacing-interface.hh"
34 #include "accidental-placement.hh"
35 #include "pointer-group-interface.hh"
36 #include "directional-element-interface.hh"
38 /* A stem following a bar-line creates an optical illusion similar to the
39 one mentioned in note-spacing.cc. We correct for it here.
41 TODO: should we still correct if there are accidentals/arpeggios before
42 the stem?
45 Real
46 Staff_spacing::optical_correction (Grob *me, Grob *g, Interval bar_height)
48 if (!g || !Note_column::has_interface (g))
49 return 0;
51 Grob *stem = Note_column::get_stem (g);
52 Real ret = 0.0;
54 if (!bar_height.is_empty () && stem)
56 Direction d = get_grob_direction (stem);
57 if (Stem::is_normal_stem (stem) && d == DOWN)
61 can't look at stem-end-position, since that triggers
62 beam slope computations.
64 Real stem_start = Stem::head_positions (stem) [d];
65 Real stem_end = stem_start +
66 d * robust_scm2double (stem->get_property ("length"), 7);
68 Interval stem_posns (min (stem_start, stem_end),
69 max (stem_end, stem_start));
71 stem_posns.intersect (bar_height);
73 ret = min (abs (stem_posns.length () / 7.0), 1.0);
74 ret *= robust_scm2double (me->get_property ("stem-spacing-correction"), 1);
77 return ret;
81 Y-positions that are covered by BAR_GROB, in the case that it is a
82 barline. */
83 Interval
84 Staff_spacing::bar_y_positions (Grob *bar_grob)
86 Interval bar_size;
87 bar_size.set_empty ();
88 if (Bar_line::has_interface (bar_grob))
90 SCM glyph = bar_grob->get_property ("glyph-name");
91 Grob *staff_sym = Staff_symbol_referencer::get_staff_symbol (bar_grob);
93 string glyph_string = scm_is_string (glyph) ? ly_scm2string (glyph) : "";
94 if (glyph_string.substr (0, 1) == "|"
95 || glyph_string.substr (0, 1) == ".")
97 Grob *common = bar_grob->common_refpoint (staff_sym, Y_AXIS);
98 bar_size = bar_grob->extent (common, Y_AXIS);
99 bar_size *= 1.0 / Staff_symbol_referencer::staff_space (bar_grob);
102 return bar_size;
105 Real
106 Staff_spacing::next_notes_correction (Grob *me,
107 Grob *last_grob)
109 Interval bar_size = bar_y_positions (last_grob);
110 Grob *orig = me->original () ? me->original () : me;
111 vector<Item*> note_columns = Spacing_interface::right_note_columns (orig);
113 Real max_optical = 0.0;
115 for (vsize i = 0; i < note_columns.size (); i++)
116 max_optical = max (max_optical, optical_correction (me, note_columns[i], bar_size));
118 return max_optical;
121 /* We calculate three things here: the ideal distance, the minimum distance
122 (which is the distance at which collisions will occur) and the "fixed"
123 distance, which is the distance at which things start to look really bad.
124 We arrange things so that the fixed distance will be attained when the
125 line is compressed with a force of 1.0 */
126 Spring
127 Staff_spacing::get_spacing (Grob *me, Grob *right_col)
129 Item *me_item = dynamic_cast<Item *> (me);
130 Grob *left_col = me_item->get_column ();
132 Interval last_ext;
133 Direction break_dir = me_item->break_status_dir ();
134 Grob *last_grob = Spacing_interface::extremal_break_aligned_grob (me, LEFT,
135 break_dir,
136 &last_ext);
137 if (!last_grob)
140 TODO:
142 Should insert a adjustable space here? For excercises, you might want to
143 use a staff without a clef in the beginning.
147 we used to have a warning here, but it generates a lot of
148 spurious error messages.
150 return Spring ();
153 SCM alist = last_grob->get_property ("space-alist");
154 if (!scm_list_p (alist))
155 return Spring ();
157 SCM space_def = scm_sloppy_assq (ly_symbol2scm ("first-note"), alist);
158 if (me_item->break_status_dir () == CENTER)
160 SCM nndef = scm_sloppy_assq (ly_symbol2scm ("next-note"), alist);
161 if (scm_is_pair (nndef))
162 space_def = nndef;
165 if (!scm_is_pair (space_def))
167 programming_error ("unknown prefatory spacing");
168 return Spring ();
171 space_def = scm_cdr (space_def);
172 Real distance = scm_to_double (scm_cdr (space_def));
173 SCM type = scm_car (space_def);
175 Real fixed = last_ext[RIGHT];
176 Real ideal = fixed + 1.0;
178 if (type == ly_symbol2scm ("fixed-space"))
180 fixed += distance;
181 ideal = fixed;
183 else if (type == ly_symbol2scm ("extra-space"))
184 ideal = fixed + distance;
185 else if (type == ly_symbol2scm ("semi-fixed-space"))
187 fixed += distance / 2;
188 ideal = fixed + distance / 2;
190 else if (type == ly_symbol2scm ("minimum-space"))
191 ideal = last_ext[LEFT] + max (last_ext.length (), distance);
192 else if (type == ly_symbol2scm ("minimum-fixed-space"))
194 fixed = last_ext[LEFT] + max (last_ext.length (), distance);
195 ideal = fixed;
199 Real optical_correction = next_notes_correction (me, last_grob);
200 Real min_dist = Paper_column::minimum_distance (left_col, right_col);
202 /* ensure that the "fixed" distance will leave a gap of at least 0.3 ss. */
203 Real min_dist_correction = max (0.0, 0.3 + min_dist - fixed);
204 Real correction = max (optical_correction, min_dist_correction);
206 fixed += correction;
207 ideal += correction;
209 Spring ret (ideal, min_dist);
210 ret.set_inverse_stretch_strength (max (0.0, ideal - fixed));
211 return ret;
214 ADD_INTERFACE (Staff_spacing,
215 "This object calculates spacing details from a breakable"
216 " symbol (left) to another object. For example, it takes care"
217 " of optical spacing from a bar line to a note.",
219 /* properties */
220 "stem-spacing-correction "