2 note-spacing.cc -- implement Note_spacing
4 source file of the GNU LilyPond music typesetter
6 (c) 2001--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
10 #include "paper-column.hh"
13 #include "note-spacing.hh"
15 #include "note-column.hh"
20 Note_spacing::has_interface (Grob* g)
22 return g && g->has_interface (ly_symbol2scm ("note-spacing-interface"));
26 Note_spacing::get_spacing (Grob *me)
28 Drul_array<SCM> props(me->get_grob_property ("left-items"),
29 me->get_grob_property ("right-items"));
31 Drul_array<Interval> extents;
34 for (SCM s = props[d]; gh_pair_p (s); s = gh_cdr (s))
36 Item * it= dynamic_cast<Item*> (unsmob_grob (gh_car(s)));
37 extents[d].unite (it->extent (it->column_l (), X_AXIS));
41 Grob * accs = Note_column::accidentals (it);
43 accs = Note_column::accidentals (it->get_parent (X_AXIS));
46 extents[d].unite (accs->extent (it->column_l (), X_AXIS));
50 if (extents[d].empty_b ())
51 extents[d] = Interval (0,0);
53 while (flip (&d) != LEFT);
57 What's sticking out at the left of the right side has less
61 Real dx= extents[LEFT][RIGHT] - 0.5 * extents[RIGHT][LEFT];
66 Note_spacing::left_column (Grob *me)
68 if (me->immutable_property_alist_ == SCM_EOL)
71 return dynamic_cast<Item*> (me)->column_l ();
75 Compute the column of the right-items. This is a big function,
76 since RIGHT-ITEMS may span more columns (eg. if a clef if inserted,
77 this will add a new columns to RIGHT-ITEMS. Here we look at the
78 columns, and return the left-most. If there are multiple columns, we
83 Note_spacing::right_column (Grob*me)
86 ugh. should have generic is_live() method?
88 if (me->immutable_property_alist_ == SCM_EOL)
91 SCM right = me->get_grob_property ("right-items");
93 int min_rank = INT_MAX;
95 for (SCM s = right ; gh_pair_p (s) ; s = gh_cdr (s))
97 Item * ri = unsmob_item (gh_car (s));
99 Item * col = ri->column_l ();
100 int rank = Paper_column::rank_i (col);
114 // I'm a lazy bum. We could do this in-place.
115 SCM newright = SCM_EOL;
116 for (SCM s = right ; gh_pair_p (s) ; s =gh_cdr (s))
118 if (unsmob_item (gh_car (s))->column_l () == mincol)
119 newright = gh_cons (gh_car (s), newright);
122 me->set_grob_property ("right-items", newright);
128 int r = Paper_column::rank_i (dynamic_cast<Item*>(me)->column_l ());
129 programming_error (_f("Spacing wish column %d has no right item.", r));
139 Correct for optical illusions. See [Wanske] p. 138. The combination
140 up-stem + down-stem should get extra space, the combination
141 down-stem + up-stem less.
143 TODO: have to check wether the stems are in the same staff.
145 TODO: also correct for bar lines in RIGHT-ITEMS. Should check if
146 the barline is the leftmost object of the break alignment.
150 Note_spacing::stem_dir_correction (Grob*me)
152 Drul_array<Direction> stem_dirs(CENTER,CENTER);
153 Drul_array<Interval> stem_posns;
154 Drul_array<Interval> head_posns;
155 Drul_array<SCM> props(me->get_grob_property ("left-items"),
156 me->get_grob_property ("right-items"));
158 stem_dirs[LEFT] = stem_dirs[RIGHT] = CENTER;
162 bool acc_right = false;
166 for (SCM s = props[d]; gh_pair_p (s); s = gh_cdr (s))
168 Item * it= dynamic_cast<Item*> (unsmob_grob (gh_car(s)));
171 acc_right = acc_right || Note_column::accidentals (it);
173 Grob *stem = Note_column::stem_l (it);
175 if (!stem || Stem::invisible_b (stem))
181 Direction sd = Stem::get_direction (stem);
182 if (stem_dirs[d] && stem_dirs[d] != sd)
189 Interval hp = Stem::head_positions (stem);
190 Real chord_start = hp[sd];
191 Real stem_end = Stem::stem_end_position (stem);
193 stem_posns[d] = Interval(chord_start<?stem_end, chord_start>? stem_end);
194 head_posns[d].unite (hp);
197 while (flip (&d) != LEFT);
201 don't correct if accidentals are sticking out of the right side.
208 if (correct && stem_dirs[LEFT] *stem_dirs[RIGHT] == -1)
210 intersect = stem_posns[LEFT];
211 intersect.intersect(stem_posns[RIGHT]);
212 correct = correct && !intersect.empty_b ();
219 Real correction = abs (intersect.length ());
220 correction = (correction/7) <? 1.0;
221 correction *= stem_dirs[LEFT] ;
222 correction *= gh_scm2double (me->get_grob_property ("stem-spacing-correction"));
228 Correct for the following situation:
237 ^ move the center one to the left.
240 this effect seems to be much more subtle than the
241 stem-direction stuff (why?), and also does not scale with the
242 difference in stem length.
247 Interval hp = head_posns[LEFT];
248 hp.intersect (head_posns[RIGHT]);
253 (head_posns[LEFT][DOWN] > head_posns[RIGHT][UP]) ? RIGHT : LEFT;
255 Real delta = head_posns[-lowest][DOWN] - head_posns[lowest][UP] ;
256 Real corr = gh_scm2double (me->get_grob_property ("stem-spacing-correction"));
257 corr = (delta <= 1) ? 0.0 : 0.25;
259 return -lowest * corr ;