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