2 staff-spacing.cc -- implement Staff_spacing
4 source file of the GNU LilyPond music typesetter
6 (c) 2001--2008 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 occur) 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 Direction break_dir
= me_item
->break_status_dir ();
123 Grob
*last_grob
= Spacing_interface::extremal_break_aligned_grob (me
, LEFT
,
131 Should insert a adjustable space here? For excercises, you might want to
132 use a staff without a clef in the beginning.
136 we used to have a warning here, but it generates a lot of
137 spurious error messages.
142 SCM alist
= last_grob
->get_property ("space-alist");
143 if (!scm_list_p (alist
))
146 SCM space_def
= scm_sloppy_assq (ly_symbol2scm ("first-note"), alist
);
147 if (me_item
->break_status_dir () == CENTER
)
149 SCM nndef
= scm_sloppy_assq (ly_symbol2scm ("next-note"), alist
);
150 if (scm_is_pair (nndef
))
154 if (!scm_is_pair (space_def
))
156 programming_error ("unknown prefatory spacing");
160 space_def
= scm_cdr (space_def
);
161 Real distance
= scm_to_double (scm_cdr (space_def
));
162 SCM type
= scm_car (space_def
);
164 Real fixed
= last_ext
[RIGHT
];
165 Real ideal
= fixed
+ 1.0;
167 if (type
== ly_symbol2scm ("fixed-space"))
172 else if (type
== ly_symbol2scm ("extra-space"))
173 ideal
= fixed
+ distance
;
174 else if (type
== ly_symbol2scm ("semi-fixed-space"))
176 fixed
+= distance
/ 2;
177 ideal
= fixed
+ distance
/ 2;
179 else if (type
== ly_symbol2scm ("minimum-space"))
180 ideal
= last_ext
[LEFT
] + max (last_ext
.length (), distance
);
181 else if (type
== ly_symbol2scm ("minimum-fixed-space"))
183 fixed
= last_ext
[LEFT
] + max (last_ext
.length (), distance
);
188 Real optical_correction
= next_notes_correction (me
, last_grob
);
189 Real min_dist
= Paper_column::minimum_distance (left_col
, right_col
);
191 /* ensure that the "fixed" distance will leave a gap of at least 0.3 ss. */
192 Real min_dist_correction
= max (0.0, 0.3 + min_dist
- fixed
);
193 Real correction
= max (optical_correction
, min_dist_correction
);
198 Spring
ret (ideal
, min_dist
);
199 ret
.set_inverse_stretch_strength (max (0.0, ideal
- fixed
));
203 ADD_INTERFACE (Staff_spacing
,
204 "This object calculates spacing details from a breakable"
205 " symbol (left) to another object. For example, it takes care"
206 " of optical spacing from a bar line to a note.",
209 "stem-spacing-correction "