]> git.donarmstrong.com Git - lilypond.git/blob - lily/note-column.cc
release: 1.3.62
[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 GLUE_SCORE_ELEMENT(Note_column,after_line_breaking);
153 SCM
154 Note_column::member_after_line_breaking ()
155 {
156   if (!stem_l () || !rest_b ())
157     return SCM_UNDEFINED;
158
159   Beam * b = stem_l ()->beam_l ();
160   if (!b || !b->visible_stem_count ())
161     return SCM_UNDEFINED;
162   
163   /* ugh. Should be done by beam.
164      (what? should be done --jcn)
165     scary too?: height is calculated during post_processing
166    */
167   Real beam_dy = 0;
168   Real beam_y = 0;
169
170   SCM s = b->get_elt_property ("height");
171   if (gh_number_p (s))
172     beam_dy = gh_scm2double (s);
173   
174   s = b->get_elt_property ("y-position");
175   if (gh_number_p (s))
176     beam_y = gh_scm2double (s);
177
178   
179   Real x0 = b->first_visible_stem ()->relative_coordinate (0, X_AXIS);
180   Real dx = b->last_visible_stem ()->relative_coordinate (0, X_AXIS) - x0;
181   Real dydx = beam_dy && dx ? beam_dy/dx : 0;
182
183   Direction d = stem_l ()->get_direction ();
184   Real beamy = (stem_l ()->relative_coordinate (0, X_AXIS) - x0) * dydx + beam_y;
185
186   s = get_elt_pointer ("rests");
187   Score_element * se = unsmob_element (gh_car (s));
188   Staff_symbol_referencer_interface si (se);
189
190   Real staff_space = si.staff_space ();      
191   Real rest_dim = extent (Y_AXIS)[d]*2.0  /staff_space ;
192
193   Real minimum_dist
194     = paper_l ()->get_var ("restcollision_minimum_beamdist") ;
195   Real dist =
196     minimum_dist +  -d  * (beamy - rest_dim) >? 0;
197
198   int stafflines = si.line_count ();
199
200   // move discretely by half spaces.
201   int discrete_dist = int (ceil (dist ));
202
203   // move by whole spaces inside the staff.
204   if (discrete_dist < stafflines+1)
205     discrete_dist = int (ceil (discrete_dist / 2.0)* 2.0);
206
207   translate_rests (-d *  discrete_dist);
208
209   return SCM_UNDEFINED;
210 }
211
212
213 Interval
214 Note_column::rest_dim () const
215 {
216   Interval restdim;
217   SCM s = get_elt_pointer ("rests");
218   for (; gh_pair_p (s); s = gh_cdr (s))
219     {
220       Score_element * sc = unsmob_element ( gh_car (s));
221       restdim.unite (sc->extent (Y_AXIS));
222     }
223   
224   return restdim;
225 }
226
227 Note_head*
228 Note_column::first_head () const
229 {
230   Stem * st = stem_l ();
231   return st?  st->first_head (): 0; 
232 }