]> git.donarmstrong.com Git - lilypond.git/blob - lily/beam.cc
release: 0.0.68pre
[lilypond.git] / lily / beam.cc
1 /*
2   beam.cc -- implement Beam
3
4   source file of the GNU GNU LilyPond music typesetter
5
6   (c) 1997 Han-Wen Nienhuys <hanwen@stack.nl>
7
8   TODO
9
10   Less hairy code. Better slope calculations.
11   knee: ([\stem 1; c8 \stem -1; c8]
12   
13 */
14
15 #include <math.h>
16
17 #include "p-col.hh"
18 #include "varray.hh"
19 #include "proto.hh"
20 #include "dimen.hh"
21 #include "beam.hh"
22 #include "misc.hh"
23 #include "debug.hh"
24 #include "symbol.hh"
25 #include "molecule.hh"
26 #include "leastsquares.hh"
27 #include "stem.hh"
28 #include "paper-def.hh"
29 #include "lookup.hh"
30 #include "grouping.hh"
31
32
33
34 struct Stem_info {
35     Real x;
36     Real idealy;
37     Real miny;
38     int no_beams;
39
40     
41     Stem_info(){}
42     Stem_info(Stem const *);
43 };
44
45 Stem_info::Stem_info(Stem const *s)
46 {
47     x = s->hpos_f();
48     int dir = s->dir_i_;
49     idealy  = dir * s->stem_end_f();
50     miny = dir * s->stem_start_f() + 2; // ugh
51     assert(miny <= idealy);
52 }
53
54
55 /* *************** */
56
57
58
59 Offset
60 Beam::center()const
61 {
62     Real w=(paper()->note_width() + width().length())/2.0;
63     return Offset(w, (left_pos + w* slope)*paper()->internote_f());
64 }
65
66
67 Beam::Beam()
68 {
69     slope = 0;
70     left_pos = 0.0;
71 }
72
73 void
74 Beam::add(Stem*s)
75 {
76     stems.push(s);
77     s->add_dependency(this);
78     s->print_flag_b_ = false;
79 }
80
81 void
82 Beam::set_default_dir()
83 {
84     int up = 0, down = 0;
85     int up_count = 0, down_count = 0;
86
87     for (int i=0; i <stems.size(); i++) {
88         Stem *sl = stems[i];
89         int cur_down = sl->get_center_distance_from_top();
90         int cur_up = sl->get_center_distance_from_bottom();
91         if (cur_down) {
92             down += cur_down;
93             down_count++;
94         }
95         if (cur_up) {
96             up += cur_up;
97             up_count++;
98         }
99     }
100     if (!down)
101         down_count = 1;
102     if (!up)
103         up_count = 1;
104
105     // the following relation is equal to
106     //        up / up_count > down / down_count
107     dir_i_ = (up * down_count > down * up_count) ? 1 : -1;
108
109    for (int i=0; i <stems.size(); i++) {
110         Stem *sl = stems[i];
111         sl->dir_i_ = dir_i_;
112    }
113 }
114
115 /*
116   should use minimum energy formulation (cf linespacing)
117   */
118 void
119 Beam::solve_slope()
120 {
121     Array<Stem_info> sinfo;
122     for (int j=0; j <stems.size(); j++) {
123         Stem *i = stems[j];
124
125         i->set_default_extents();
126         if (i->invisible_b())
127             continue;
128         
129         Stem_info info(i);
130         sinfo.push(info);
131     }
132     Real leftx = sinfo[0].x;
133     Least_squares l;
134     for (int i=0; i < sinfo.size(); i++) {
135         sinfo[i].x -= leftx;
136         l.input.push(Offset(sinfo[i].x, sinfo[i].idealy));
137     }
138
139     l.minimise(slope, left_pos);
140     Real dy = 0.0;
141     for (int i=0; i < sinfo.size(); i++) {
142         Real y = sinfo[i].x * slope + left_pos;
143         Real my = sinfo[i].miny;
144
145         if (my - y > dy)
146             dy = my -y; 
147     }
148     left_pos += dy;
149     left_pos *= dir_i_;    
150
151     slope *= dir_i_;
152     slope = 0.6 * tanh(slope);  // damping
153
154                                 // ugh
155     Real sl = slope*paper()->internote_f();
156     paper()->lookup_l()->beam(sl, 20 PT);
157     slope = sl /paper()->internote_f();
158 }
159
160 void
161 Beam::set_stemlens()
162 {
163     Real x0 = stems[0]->hpos_f();    
164     for (int j=0; j <stems.size(); j++) {
165         Stem *s = stems[j];
166
167         Real x =  s->hpos_f()-x0;
168         s->set_stemend(left_pos + slope * x);   
169     }
170 }
171
172
173 void
174 Beam::do_post_processing()
175 {
176     solve_slope();    
177     set_stemlens();
178 }
179
180 void
181 Beam::set_grouping(Rhythmic_grouping def, Rhythmic_grouping cur)
182 {
183     def.OK();
184     cur.OK();
185     assert(cur.children.size() == stems.size());
186     
187     cur.split(def);
188
189     Array<int> b;
190     {
191         Array<int> flags;
192         for (int j=0; j <stems.size(); j++) {
193             Stem *s = stems[j];
194
195             int f = intlog2(abs(s->flag_i_))-2;
196             assert(f>0);
197             flags.push(f);
198         }
199         int fi =0;
200         b= cur.generate_beams(flags, fi);
201         b.insert(0,0);
202         b.push(0);
203         assert(stems.size() == b.size()/2);
204     }
205
206     for (int j=0, i=0; i < b.size() && j <stems.size(); i+= 2, j++) {
207         Stem *s = stems[j];
208         s->beams_left_i_ = b[i];
209         s->beams_right_i_ = b[i+1];
210     }
211 }
212
213 void
214 Beam::do_pre_processing()
215 {
216     assert(stems.size()>1);
217     if (!dir_i_)
218         set_default_dir();
219
220 }
221
222
223 Interval
224 Beam::do_width() const
225 {
226     return Interval( stems[0]->hpos_f(),
227                      stems.top()->hpos_f() );
228 }
229
230 /*
231   beams to go with one stem.
232   */
233 Molecule
234 Beam::stem_beams(Stem *here, Stem *next, Stem *prev)const
235 {
236     assert( !next || next->hpos_f() > here->hpos_f()  );
237     assert( !prev || prev->hpos_f() < here->hpos_f()  );
238     Real dy=paper()->internote_f()*2;
239     Real stemdx = paper()->rule_thickness();
240     Real sl = slope*paper()->internote_f();
241     paper()->lookup_l()->beam(sl, 20 PT);
242
243     Molecule leftbeams;
244     Molecule rightbeams;
245
246     /* half beams extending to the left. */
247     if (prev) {
248         int lhalfs= lhalfs = here->beams_left_i_ - prev->beams_right_i_ ;
249         int lwholebeams= here->beams_left_i_ <? prev->beams_right_i_ ;
250         Real w = (here->hpos_f() - prev->hpos_f())/4;
251         Symbol dummy;
252         Atom a(dummy);
253         if (lhalfs)             // generates warnings if not
254             a =  paper()->lookup_l()->beam(sl, w);
255         a.translate(Offset (-w, -w * sl));
256         for (int j = 0; j  < lhalfs; j++) {
257             Atom b(a);
258             b.translate_y( -dir_i_ * dy * (lwholebeams+j));
259             leftbeams.add( b );
260         }
261     }
262         
263     if (next){
264         int rhalfs = here->beams_right_i_ - next->beams_left_i_;
265         int rwholebeams = here->beams_right_i_ <? next->beams_left_i_; 
266
267         Real w = next->hpos_f() - here->hpos_f();
268         Atom a = paper()->lookup_l()->beam(sl, w + stemdx);
269         
270         int j = 0;
271         for (; j  < rwholebeams; j++) {
272             Atom b(a);
273             b.translate_y( -dir_i_ * dy * j);
274             rightbeams.add( b ); 
275         }
276
277         w /= 4;
278         if (rhalfs)
279             a = paper()->lookup_l()->beam(sl, w);
280         
281         for (; j  < rwholebeams + rhalfs; j++) {
282             Atom b(a);
283             b.translate_y( -dir_i_ * dy * j);
284             rightbeams.add(b ); 
285         }
286         
287     }
288     leftbeams.add(rightbeams);
289     return leftbeams;
290 }
291
292
293 Molecule*
294 Beam::brew_molecule_p() const 
295 {
296     Molecule *out=0;
297     Real inter=paper()->internote_f();
298     out = new Molecule;
299     Real x0 = stems[0]->hpos_f();
300     for (int j=0; j <stems.size(); j++) {
301         Stem *i = stems[j];
302         Stem * prev = (j > 0)? stems[j-1] : 0;
303         Stem * next = (j < stems.size()-1) ? stems[j+1] :0;
304
305         Molecule sb = stem_beams(i, next, prev);
306         Real  x = i->hpos_f()-x0;
307         sb.translate(Offset(x, (x * slope  + left_pos)* inter));
308         out->add(sb);
309     }
310     out->translate_x(x0 - left_col_l_->hpos);
311     return out;
312 }
313
314 IMPLEMENT_STATIC_NAME(Beam);
315 IMPLEMENT_IS_TYPE_B1(Beam, Spanner);
316
317 void
318 Beam::do_print()const
319 {
320 #ifndef NPRINT
321     mtor << "slope " <<slope << "left ypos " << left_pos;
322     Spanner::print();
323 #endif
324 }
325
326 void
327 Beam::do_substitute_dependency(Score_elem*o,Score_elem*n)
328 {
329     int i;
330     while ((i=stems.find_i((Stem*)o->item())) >=0) 
331            if (n) stems[i] = (Stem*) n->item();
332            else stems.del(i);
333 }