]> git.donarmstrong.com Git - lilypond.git/blob - lily/stem.cc
release: 1.1.36
[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--1999 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7
8   TODO: This is way too hairy
9 */
10
11 #include "stem.hh"
12 #include "debug.hh"
13 #include "paper-def.hh"
14 #include "note-head.hh"
15 #include "lookup.hh"
16 #include "molecule.hh"
17 #include "p-col.hh"
18 #include "misc.hh"
19 #include "beam.hh"
20 #include "rest.hh"
21
22 Stem::~Stem ()
23 {
24 }
25
26 Stem::Stem ()
27 {
28   beams_i_drul_[LEFT] = beams_i_drul_[RIGHT] = -1;
29   mult_i_ = 0;
30
31   yextent_drul_[DOWN] = yextent_drul_[UP] = 0;
32   flag_i_ = 2;
33   dir_ = CENTER;
34   stem_xdir_ = LEFT;
35
36   beam_gap_i_ = 0;
37   beam_l_ = 0;
38 }
39
40 Interval_t<int>
41 Stem::head_positions () const
42 {
43   /* 
44     Mysterious FreeBSD fix by John Galbraith.  Somehow, the empty intervals 
45     trigger FP exceptions on FreeBSD.  Fix: do not return infinity 
46
47    */
48   if (!head_l_arr_.size ())
49     {
50       return Interval_t<int> (100,-100);        
51     }
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_] * staff_line_leading_f ()/2.0;
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 (Note_head *nh = dynamic_cast<Note_head *> (n))
120     {
121       head_l_arr_.push (nh);
122     }
123   else if (Rest *r = dynamic_cast<Rest *> (n))
124     {
125       rest_l_arr_.push (r);
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   Real internote_f = staff_line_leading_f ()/2.0;
169   Real length_f = paper_l ()->get_var ("stem_length0") / internote_f;
170   Real shorten_f = paper_l ()->get_var ("forced_stem_shorten0") / internote_f;
171
172   if (!dir_)
173     set_default_dir ();
174   /* 
175     stems in unnatural (forced) direction should be shortened, 
176     accoding to [Roush & Gourlay]
177    */
178   if (((int)chord_start_f ())
179       && (dir_ != get_default_dir ()))
180     length_f -= shorten_f;
181
182   if (flag_i_ >= 5)
183     length_f += 2.0;
184   if (flag_i_ >= 6)
185     length_f += 1.0;
186   
187   set_stemend ((dir_ > 0) ? head_positions()[BIGGER] + length_f:
188                head_positions()[SMALLER] - length_f);
189
190   if (dir_ * stem_end_f () < 0)
191     set_stemend (0);
192 }
193
194 //xxx
195 void
196 Stem::set_default_extents ()
197 {
198   if (!stem_length_f ())
199     set_default_stemlen ();
200
201
202   if (dir_ == UP)
203     stem_xdir_ = RIGHT;
204   if (invisible_b ())
205     stem_xdir_ = CENTER;
206 }
207
208 /*
209   TODO
210
211   move into note_column.cc
212
213   */
214 void
215 Stem::set_noteheads ()
216 {
217   if (!head_l_arr_.size ())
218     return;
219   head_l_arr_.sort (Note_head::compare);
220   if (dir_ < 0)
221     head_l_arr_.reverse ();
222
223   head_l_arr_[0]->extremal_i_ = -1;
224   head_l_arr_.top ()->extremal_i_ = 1;
225   int parity=1;
226   int lastpos = head_l_arr_[0]->position_i_;
227   for (int i=1; i < head_l_arr_.size (); i ++)
228     {
229       int dy =abs (lastpos- head_l_arr_[i]->position_i_);
230
231       if (dy <= 1)
232         {
233           if (parity)
234             head_l_arr_[i]->x_dir_ = (stem_xdir_ == LEFT) ? LEFT : RIGHT;
235           parity = !parity;
236         }
237       else
238         parity = 1;
239       lastpos = head_l_arr_[i]->position_i_;
240     }
241 }
242
243 void
244 Stem::do_pre_processing ()
245 {
246   if (yextent_drul_[DOWN]== yextent_drul_[UP])
247     set_default_extents ();
248   set_noteheads ();
249   flag_i_ = flag_i_;
250   if (invisible_b ())
251     {
252       set_elt_property (transparent_scm_sym, SCM_BOOL_T);
253     }
254   set_empty (invisible_b ());
255 }
256
257
258 Interval
259 Stem::do_width () const
260 {
261   Interval r (0, 0);
262   if (beam_l_ || abs (flag_i_) <= 2)
263     ;   // TODO!
264   else
265     {
266       r = lookup_l ()->flag (flag_i_, dir_).dim_.x ();
267       r += note_delta_f ();
268     }
269   return r;
270 }
271
272
273
274
275 const Real ANGLE = 20* (2.0*M_PI/360.0); // ugh!
276
277 Molecule*
278 Stem::do_brew_molecule_p () const
279 {
280   Molecule *mol_p =new Molecule;
281   Drul_array<Real> stem_y = yextent_drul_;
282   Real dy = staff_line_leading_f ()/2.0;
283
284   Real head_wid = 0;
285   if (head_l_arr_.size ())
286     head_wid = head_l_arr_[0]->extent (X_AXIS).length ();
287   stem_y[Direction(-dir_)] += dir_ * head_wid * tan(ANGLE)/(2*dy);
288   
289   if (!invisible_b ())
290     {
291       Molecule ss =lookup_l ()->stem (stem_y[DOWN]*dy,
292                                      stem_y[UP]*dy);
293       mol_p->add_molecule (ss);
294     }
295
296   if (!beam_l_ && abs (flag_i_) > 2)
297     {
298       Molecule fl = lookup_l ()->flag (flag_i_, dir_);
299       fl.translate_axis(stem_y[dir_]*dy, Y_AXIS);
300       mol_p->add_molecule (fl);
301     }
302
303   if (head_l_arr_.size())
304     {
305       mol_p->translate_axis (note_delta_f (), X_AXIS);
306     }
307   return mol_p;
308 }
309
310 Real
311 Stem::note_delta_f () const
312 {
313   Real r=0;
314   if (head_l_arr_.size())
315     {
316       Interval head_wid(0,  head_l_arr_[0]->extent (X_AXIS).length ());
317       Real rule_thick(paper_l ()->rule_thickness ());
318       Interval stem_wid(-rule_thick/2, rule_thick/2);
319       if (stem_xdir_ == CENTER)
320         r = head_wid.center ();
321       else
322         r = head_wid[stem_xdir_] - stem_wid[stem_xdir_];
323     }
324   return r;
325 }
326
327 Real
328 Stem::hpos_f () const
329 {
330   return note_delta_f () + Item::hpos_f ();
331 }
332
333 /*
334   TODO:  head_l_arr_/rest_l_arr_ in  
335  */
336 void
337 Stem::do_substitute_element_pointer (Score_element*o,Score_element*n)
338 {
339   if (Note_head*h=dynamic_cast<Note_head*> (o))
340   head_l_arr_.substitute (h, dynamic_cast<Note_head*>(n));
341   if (Rest *r=dynamic_cast<Rest*> (o))
342     rest_l_arr_.substitute (r, dynamic_cast<Rest*>(n));
343   if (Beam* b = dynamic_cast<Beam*> (o))
344     {
345       if (b == beam_l_) 
346         {
347           beam_l_ = dynamic_cast<Beam*> (n);
348           if (!beam_l_)
349             {
350               beams_i_drul_[LEFT] = 0;
351               beams_i_drul_[RIGHT] = 0;
352               mult_i_ = 0;
353             }
354         }
355     }
356   Staff_symbol_referencer::do_substitute_element_pointer (o,n);
357       
358 }