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