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