]> git.donarmstrong.com Git - lilypond.git/blob - lily/note-column.cc
release: 1.3.37
[lilypond.git] / lily / note-column.cc
1 /*
2   note-column.cc -- implement Note_column
3
4   source file of the GNU LilyPond music typesetter
5
6   (c)  1997--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8 #include <math.h>               // ceil
9
10 #include "axis-group-interface.hh"
11 #include "dot-column.hh"
12 #include "note-column.hh"
13 #include "beam.hh"
14 #include "note-head.hh"
15 #include "stem.hh"
16 #include "rest.hh"
17 #include "debug.hh"
18 #include "paper-def.hh"
19 #include "group-interface.hh"
20 #include "staff-symbol-referencer.hh"
21
22 bool
23 Note_column::rest_b () const
24 {
25   SCM r = get_elt_property ("rests");
26
27   return gh_pair_p (r);
28 }
29
30 int
31 Note_column::shift_compare (Note_column *const &p1, Note_column*const&p2)
32 {
33   SCM s1 = p1->get_elt_property ("horizontal-shift");
34   SCM s2 = p2->get_elt_property ("horizontal-shift");
35
36   int h1 = (gh_number_p (s1))?  gh_scm2int (s1) :0;
37   int h2 = (gh_number_p (s2)) ? gh_scm2int (s2):0;
38   return h1 - h2;
39 }
40
41 Note_column::Note_column()
42 {
43   set_elt_property ("rests", SCM_EOL);
44   set_elt_property ("note-heads", SCM_EOL);  
45   Axis_group_interface (this).set_interface ();
46   Axis_group_interface (this).set_axes (X_AXIS, Y_AXIS);
47 }
48
49 Stem *
50 Note_column::stem_l () const
51 {
52   SCM s = get_elt_property ("stem");
53   return dynamic_cast<Stem*> (unsmob_element (s));
54
55 }
56
57   
58 Slice
59 Note_column::head_positions_interval() const
60 {
61   Slice  iv;
62
63   iv.set_empty ();
64
65   SCM h = get_elt_property ("note-heads");
66   for (; gh_pair_p (h); h = gh_cdr (h))
67     {
68       Score_element *se = unsmob_element (gh_car (h));
69       Staff_symbol_referencer_interface si (se); 
70       
71       int j = int (si.position_f ());
72       iv.unite (Slice (j,j));
73     }
74   return iv;
75 }
76
77 Direction
78 Note_column::dir () const
79 {
80   if (stem_l ())
81     return stem_l ()->get_direction ();
82   else if (gh_pair_p (get_elt_property ("note-heads")))
83     return (Direction)sign (head_positions_interval().center ());
84
85   programming_error ("Note column without heads and stem!");
86   return CENTER;
87 }
88
89
90 void
91 Note_column::set_stem (Stem * stem_l)
92 {
93   set_elt_property ("stem", stem_l->self_scm_);
94
95   add_dependency (stem_l);
96   Axis_group_interface (this).add_element (stem_l);
97 }
98
99
100
101 void
102 Note_column::add_head (Rhythmic_head *h)
103 {
104   if (Rest*r=dynamic_cast<Rest *> (h))
105     {
106       Group_interface gi (this, "rests");
107       gi.add_element (h);
108     }
109   if (Note_head *nh=dynamic_cast<Note_head *> (h))
110     {
111       Group_interface gi (this, "note-heads");
112       gi.add_element (nh);
113     }
114   Axis_group_interface (this).add_element (h);
115 }
116
117 /**
118   translate the rest symbols vertically by amount DY_I.
119  */
120 void
121 Note_column::translate_rests (int dy_i)
122 {
123   SCM s = get_elt_property ("rests");
124   for (; gh_pair_p (s); s = gh_cdr (s))
125     {
126       Score_element * se = unsmob_element (gh_car (s));
127       Staff_symbol_referencer_interface si (se);
128
129       se->translate_axis (dy_i * si.staff_space ()/2.0, Y_AXIS);
130     }
131 }
132
133
134 void
135 Note_column::set_dotcol (Dot_column *d)
136 {
137   Axis_group_interface (this).add_element (d);
138 }
139
140 /*
141   [TODO]
142   handle rest under beam (do_post: beams are calculated now)
143   what about combination of collisions and rest under beam.
144
145   Should lookup
146     
147     rest -> stem -> beam -> interpolate_y_position ()
148 */
149
150 void
151 Note_column::after_line_breaking ()
152 {
153   if (!stem_l () || !rest_b ())
154     return;
155
156   Beam * b = stem_l ()->beam_l ();
157   if (!b || !b->visible_stem_count ())
158     return;
159   
160   /* ugh. Should be done by beam.
161      (what? should be done --jcn)
162     scary too?: height is calculated during post_processing
163    */
164   Real beam_dy = 0;
165   Real beam_y = 0;
166
167   SCM s = b->get_elt_property ("height");
168   if (gh_number_p (s))
169     beam_dy = gh_scm2double (s);
170   
171   s = b->get_elt_property ("y-position");
172   if (gh_number_p (s))
173     beam_y = gh_scm2double (s);
174
175   
176   Real x0 = b->first_visible_stem ()->relative_coordinate (0, X_AXIS);
177   Real dx = b->last_visible_stem ()->relative_coordinate (0, X_AXIS) - x0;
178   Real dydx = beam_dy && dx ? beam_dy/dx : 0;
179
180   Direction d = stem_l ()->get_direction ();
181   Real beamy = (stem_l ()->relative_coordinate (0, X_AXIS) - x0) * dydx + beam_y;
182
183   s = get_elt_property ("rests");
184   Score_element * se = unsmob_element (gh_car (s));
185   Staff_symbol_referencer_interface si (se);
186
187   Real staff_space = si.staff_space ();      
188   Real rest_dim = extent (Y_AXIS)[d]*2.0  /staff_space ;
189
190   Real minimum_dist
191     = paper_l ()->get_var ("restcollision_minimum_beamdist") ;
192   Real dist =
193     minimum_dist +  -d  * (beamy - rest_dim) >? 0;
194
195   int stafflines = si.line_count ();
196
197   // move discretely by half spaces.
198   int discrete_dist = int (ceil (dist ));
199
200   // move by whole spaces inside the staff.
201   if (discrete_dist < stafflines+1)
202     discrete_dist = int (ceil (discrete_dist / 2.0)* 2.0);
203
204   translate_rests (-d *  discrete_dist);
205 }
206
207
208 Interval
209 Note_column::rest_dim () const
210 {
211   Interval restdim;
212   SCM s = get_elt_property ("rests");
213   for (; gh_pair_p (s); s = gh_cdr (s))
214     {
215       Score_element * sc = unsmob_element ( gh_car (s));
216       restdim.unite (sc->extent (Y_AXIS));
217     }
218   
219   return restdim;
220 }
221
222 Note_head*
223 Note_column::first_head () const
224 {
225   Stem * st = stem_l ();
226   return st?  st->first_head (): 0; 
227 }