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