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