]> git.donarmstrong.com Git - lilypond.git/blob - lily/stem.cc
release: 1.0.1
[lilypond.git] / lily / stem.cc
1 /*
2   stem.cc -- implement Stem
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1996, 1997--1998 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7
8   TODO: This is way too hairy
9 */
10
11 #include "stem.hh"
12 #include "dimension.hh"
13 #include "debug.hh"
14 #include "paper-def.hh"
15 #include "note-head.hh"
16 #include "lookup.hh"
17 #include "molecule.hh"
18 #include "p-col.hh"
19 #include "misc.hh"
20 #include "beam.hh"
21 #include "rest.hh"
22
23 IMPLEMENT_IS_TYPE_B1 (Stem,Item);
24
25
26 Stem::~Stem ()
27 {
28 }
29 Stem::Stem ()
30 {
31   /*
32     TODO: staff-size
33     */
34   beam_l_ = 0;
35   beams_left_i_ = 0;
36   beams_right_i_ = 0;
37   mult_i_ = 0;
38
39   yextent_drul_[DOWN] = yextent_drul_[UP] = 0;
40   flag_i_ = 2;
41   dir_ = CENTER;
42   beam_dir_ = CENTER;
43   dir_forced_b_ = false;
44   stem_xdir_ = LEFT;
45   staff_size_i_ = 8;
46
47   beam_gap_i_ = 0;
48 }
49
50 Interval_t<int>
51 Stem::head_positions () const
52 {
53   Interval_t<int> r;
54   for (int i =0; i < head_l_arr_.size (); i++)
55     {
56       int p = head_l_arr_[i]->position_i_;
57       r[BIGGER] = r[BIGGER] >? p;
58       r[SMALLER] = r[SMALLER] <? p;
59     }
60   return r;
61 }
62
63 void
64 Stem::do_print () const
65 {
66 #ifndef NPRINT
67   DOUT << "flag "<< flag_i_;
68   if (beam_l_)
69     DOUT << "beamed";
70 #endif
71 }
72
73 Real
74 Stem::stem_length_f () const
75 {
76   return yextent_drul_[UP]-yextent_drul_[DOWN] ;
77 }
78
79 Real
80 Stem::stem_begin_f () const
81 {
82   return yextent_drul_[Direction(-dir_)];
83 }
84
85 Real
86 Stem::chord_start_f () const
87 {
88   return head_positions()[dir_] * paper ()->internote_f ();
89 }
90
91 Real
92 Stem::stem_end_f () const
93 {
94   return yextent_drul_[dir_];
95 }
96
97 void
98 Stem::set_stemend (Real se)
99 {
100   // todo: margins
101   if (dir_ && dir_ * head_positions()[dir_] >= se*dir_)
102     warning (_ ("weird stem size; check for narrow beams"));
103
104   
105   yextent_drul_[dir_]  =  se;
106   yextent_drul_[Direction(-dir_)] = head_positions()[-dir_];
107 }
108
109 int
110 Stem::type_i () const
111 {
112   return head_l_arr_[0]->balltype_i_;
113 }
114
115 void
116 Stem::add_head (Rhythmic_head *n)
117 {
118   n->add_dependency (this);     // ?
119   if (n->is_type_b (Note_head::static_name ()))
120     {
121       head_l_arr_.push ((Note_head*)n);
122     }
123   else if (n->is_type_b (Rest::static_name ()))
124     {
125       rest_l_arr_.push ((Rest*)n);
126     }
127 }
128
129 bool
130 Stem::invisible_b () const
131 {
132   return (!head_l_arr_.size () ||
133     head_l_arr_[0]->balltype_i_ <= 0);
134 }
135
136 int
137 Stem::get_center_distance (Direction d) const
138 {
139   int staff_center = 0;
140   int distance = d*(head_positions()[d] - staff_center);
141   return distance >? 0;
142 }
143
144 Direction
145 Stem::get_default_dir () const
146 {
147   return (get_center_distance (UP) >
148           get_center_distance (DOWN)) 
149     ? DOWN 
150     : UP;
151 }
152
153 Direction
154 Stem::get_dir () const
155 {
156   return dir_;
157 }
158
159 void
160 Stem::set_default_dir ()
161 {
162   dir_ = get_default_dir ();
163 }
164
165 void
166 Stem::set_default_stemlen ()
167 {
168   /*
169    TODO
170    urg; this should be handled by Stem_info
171    */
172
173   Real length_f = paper ()->get_var ("stem_length");
174   Real shorten_f = paper ()->get_var ("forced_stem_shorten");
175
176   Real internote_f = paper ()->internote_f ();
177   length_f /= internote_f;
178   shorten_f /= internote_f;
179
180   Real len = length_f;
181   if (!dir_)
182     set_default_dir ();
183   /* 
184     stems in unnatural (forced) direction should be shortened, 
185     accoding to [Roush & Gourlay]
186    */
187   else if (dir_ != get_default_dir ())
188     len -= shorten_f / internote_f;
189
190   if (flag_i_ >= 5)
191     len += 2.0;
192   if (flag_i_ >= 6)
193     len += 1.0;
194   
195   set_stemend ((dir_ > 0) ? head_positions()[BIGGER] + len :
196                head_positions()[SMALLER] - len);
197
198   if (dir_ * stem_end_f () < 0)
199     {
200       set_stemend (0);
201     }
202 }
203 //xxx
204 void
205 Stem::set_default_extents ()
206 {
207   if (!stem_length_f ())
208     set_default_stemlen ();
209
210
211   if (dir_ == UP)
212     stem_xdir_ = RIGHT;
213   if (invisible_b ())
214     stem_xdir_ = CENTER;
215 }
216
217 /*
218   TODO
219
220   move into note_column.cc
221
222   */
223 void
224 Stem::set_noteheads ()
225 {
226   if (!head_l_arr_.size ())
227     return;
228   head_l_arr_.sort (Note_head::compare);
229   if (dir_ < 0)
230     head_l_arr_.reverse ();
231
232   head_l_arr_[0]->extremal_i_ = -1;
233   head_l_arr_.top ()->extremal_i_ = 1;
234   int parity=1;
235   int lastpos = head_l_arr_[0]->position_i_;
236   for (int i=1; i < head_l_arr_.size (); i ++)
237     {
238       int dy =abs (lastpos- head_l_arr_[i]->position_i_);
239
240       if (dy <= 1)
241         {
242           if (parity)
243             head_l_arr_[i]->x_dir_ = (stem_xdir_ == LEFT) ? LEFT : RIGHT;
244           parity = !parity;
245         }
246       else
247         parity = 1;
248       lastpos = head_l_arr_[i]->position_i_;
249     }
250 }
251
252 void
253 Stem::do_pre_processing ()
254 {
255   if (yextent_drul_[DOWN]== yextent_drul_[UP])
256     set_default_extents ();
257   set_noteheads ();
258   flag_i_ = flag_i_;
259   transparent_b_ = invisible_b ();
260   set_empty (invisible_b ());
261 }
262
263
264 Interval
265 Stem::do_width () const
266 {
267   Interval r (0, 0);
268   if (beam_l_ || abs (flag_i_) <= 2)
269     ;   // TODO!
270   else
271     {
272       r = lookup_l ()->flag (flag_i_, dir_).dim_.x ();
273       r += note_delta_f ();
274     }
275   return r;
276 }
277
278
279
280
281 const Real ANGLE = 20* (2.0*M_PI/360.0); // ugh!
282
283 Molecule*
284 Stem::brew_molecule_p () const
285 {
286   Molecule *mol_p =new Molecule;
287   Drul_array<Real> stem_y = yextent_drul_;
288   Real dy = paper ()->internote_f ();
289   
290
291   Real head_wid = 0;
292   if (head_l_arr_.size ())
293     head_wid = head_l_arr_[0]->width ().length ();
294   stem_y[Direction(-dir_)] += dir_ * head_wid * tan(ANGLE)/(2*dy);
295   
296   if (!invisible_b ())
297     {
298       Atom ss =lookup_l ()->stem (stem_y[DOWN]*dy,
299                                      stem_y[UP]*dy);
300       mol_p->add_atom (ss);
301     }
302
303   if (!beam_l_ && abs (flag_i_) > 2)
304     {
305       Atom fl = lookup_l ()->flag (flag_i_, dir_);
306       fl.translate_axis(stem_y[dir_]*dy, Y_AXIS);
307       mol_p->add_atom (fl);
308     }
309
310   if (head_l_arr_.size())
311     {
312       mol_p->translate_axis (note_delta_f (), X_AXIS);
313     }
314   return mol_p;
315 }
316
317 Real
318 Stem::note_delta_f () const
319 {
320   Real r=0;
321   if (head_l_arr_.size())
322     {
323       Interval head_wid(0,  head_l_arr_[0]->width ().length ());
324       Real rule_thick(paper ()->rule_thickness ());
325       Interval stem_wid(-rule_thick/2, rule_thick/2);
326       if (stem_xdir_ == CENTER)
327 #define EGCS_ICE
328 #ifndef EGCS_ICE
329         r = head_wid.center ();
330 #else
331         r = (head_wid.min () + head_wid.max ()) / 2;
332 #endif
333       else
334         r = head_wid[stem_xdir_] - stem_wid[stem_xdir_];
335     }
336   return r;
337 }
338
339 Real
340 Stem::hpos_f () const
341 {
342   return note_delta_f () + Item::hpos_f ();
343 }
344
345 /*
346   TODO:  head_l_arr_/rest_l_arr_ in  do_substitute_dependent ()
347  */
348 void
349  Stem::do_substitute_dependency (Score_element*o,Score_element*n)
350 {
351   Item * o_l = o->access_Item ();
352   Item * n_l = n? n->access_Item () : 0;
353   head_l_arr_.substitute ((Note_head*)o_l, (Note_head*)n_l);
354   rest_l_arr_.substitute ((Rest*)o_l, (Rest*)n_l);
355 }