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> posns;
154 Drul_array<SCM> props(me->get_grob_property ("left-items"),
155 me->get_grob_property ("right-items"));
157 stem_dirs[LEFT] = stem_dirs[RIGHT] = CENTER;
163 for (SCM s = props[d]; gh_pair_p (s); s = gh_cdr (s))
165 Item * it= dynamic_cast<Item*> (unsmob_grob (gh_car(s)));
167 Grob *stem = Note_column::stem_l (it);
169 if (!stem || Stem::invisible_b (stem))
175 Direction sd = Stem::get_direction (stem);
176 if (stem_dirs[d] && stem_dirs[d] != sd)
183 Real chord_start = Stem::head_positions (stem)[sd];
184 Real stem_end = Stem::stem_end_position (stem);
186 posns[d] = Interval(chord_start<?stem_end, chord_start>? stem_end);
189 while (flip (&d) != LEFT);
191 intersect = posns[LEFT];
192 intersect.intersect(posns[RIGHT]);
193 correct = correct && !intersect.empty_b ();
194 correct = correct && (stem_dirs[LEFT] *stem_dirs[RIGHT] == -1);
203 Real correction = abs (intersect.length ());
204 correction = (correction/7) <? 1.0;
205 correction *= stem_dirs[LEFT] ;
206 correction *= gh_scm2double (me->get_grob_property ("stem-spacing-correction"));