]> git.donarmstrong.com Git - lilypond.git/blob - lily/note-column.cc
release: 1.3.50
[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   Group_interface (this, "interfaces").add_thing (ly_symbol2scm ("Note_column"));
48 }
49
50 Stem *
51 Note_column::stem_l () const
52 {
53   SCM s = get_elt_property ("stem");
54   return dynamic_cast<Stem*> (unsmob_element (s));
55
56 }
57
58   
59 Slice
60 Note_column::head_positions_interval() const
61 {
62   Slice  iv;
63
64   iv.set_empty ();
65
66   SCM h = get_elt_property ("note-heads");
67   for (; gh_pair_p (h); h = gh_cdr (h))
68     {
69       Score_element *se = unsmob_element (gh_car (h));
70       Staff_symbol_referencer_interface si (se); 
71       
72       int j = int (si.position_f ());
73       iv.unite (Slice (j,j));
74     }
75   return iv;
76 }
77
78 Direction
79 Note_column::dir () const
80 {
81   if (stem_l ())
82     return stem_l ()->get_direction ();
83   else if (gh_pair_p (get_elt_property ("note-heads")))
84     return (Direction)sign (head_positions_interval().center ());
85
86   programming_error ("Note column without heads and stem!");
87   return CENTER;
88 }
89
90
91 void
92 Note_column::set_stem (Stem * stem_l)
93 {
94   set_elt_property ("stem", stem_l->self_scm_);
95
96   add_dependency (stem_l);
97   Axis_group_interface (this).add_element (stem_l);
98 }
99
100
101
102 void
103 Note_column::add_head (Rhythmic_head *h)
104 {
105   if (Rest*r=dynamic_cast<Rest *> (h))
106     {
107       Group_interface gi (this, "rests");
108       gi.add_element (h);
109     }
110   if (Note_head *nh=dynamic_cast<Note_head *> (h))
111     {
112       Group_interface gi (this, "note-heads");
113       gi.add_element (nh);
114     }
115   Axis_group_interface (this).add_element (h);
116 }
117
118 /**
119   translate the rest symbols vertically by amount DY_I.
120  */
121 void
122 Note_column::translate_rests (int dy_i)
123 {
124   SCM s = get_elt_property ("rests");
125   for (; gh_pair_p (s); s = gh_cdr (s))
126     {
127       Score_element * se = unsmob_element (gh_car (s));
128       Staff_symbol_referencer_interface si (se);
129
130       se->translate_axis (dy_i * si.staff_space ()/2.0, Y_AXIS);
131     }
132 }
133
134
135 void
136 Note_column::set_dotcol (Dot_column *d)
137 {
138   Axis_group_interface (this).add_element (d);
139 }
140
141 /*
142   [TODO]
143   handle rest under beam (do_post: beams are calculated now)
144   what about combination of collisions and rest under beam.
145
146   Should lookup
147     
148     rest -> stem -> beam -> interpolate_y_position ()
149 */
150
151 void
152 Note_column::after_line_breaking ()
153 {
154   if (!stem_l () || !rest_b ())
155     return;
156
157   Beam * b = stem_l ()->beam_l ();
158   if (!b || !b->visible_stem_count ())
159     return;
160   
161   /* ugh. Should be done by beam.
162      (what? should be done --jcn)
163     scary too?: height is calculated during post_processing
164    */
165   Real beam_dy = 0;
166   Real beam_y = 0;
167
168   SCM s = b->get_elt_property ("height");
169   if (gh_number_p (s))
170     beam_dy = gh_scm2double (s);
171   
172   s = b->get_elt_property ("y-position");
173   if (gh_number_p (s))
174     beam_y = gh_scm2double (s);
175
176   
177   Real x0 = b->first_visible_stem ()->relative_coordinate (0, X_AXIS);
178   Real dx = b->last_visible_stem ()->relative_coordinate (0, X_AXIS) - x0;
179   Real dydx = beam_dy && dx ? beam_dy/dx : 0;
180
181   Direction d = stem_l ()->get_direction ();
182   Real beamy = (stem_l ()->relative_coordinate (0, X_AXIS) - x0) * dydx + beam_y;
183
184   s = get_elt_property ("rests");
185   Score_element * se = unsmob_element (gh_car (s));
186   Staff_symbol_referencer_interface si (se);
187
188   Real staff_space = si.staff_space ();      
189   Real rest_dim = extent (Y_AXIS)[d]*2.0  /staff_space ;
190
191   Real minimum_dist
192     = paper_l ()->get_var ("restcollision_minimum_beamdist") ;
193   Real dist =
194     minimum_dist +  -d  * (beamy - rest_dim) >? 0;
195
196   int stafflines = si.line_count ();
197
198   // move discretely by half spaces.
199   int discrete_dist = int (ceil (dist ));
200
201   // move by whole spaces inside the staff.
202   if (discrete_dist < stafflines+1)
203     discrete_dist = int (ceil (discrete_dist / 2.0)* 2.0);
204
205   translate_rests (-d *  discrete_dist);
206 }
207
208
209 Interval
210 Note_column::rest_dim () const
211 {
212   Interval restdim;
213   SCM s = get_elt_property ("rests");
214   for (; gh_pair_p (s); s = gh_cdr (s))
215     {
216       Score_element * sc = unsmob_element ( gh_car (s));
217       restdim.unite (sc->extent (Y_AXIS));
218     }
219   
220   return restdim;
221 }
222
223 Note_head*
224 Note_column::first_head () const
225 {
226   Stem * st = stem_l ();
227   return st?  st->first_head (): 0; 
228 }