]> git.donarmstrong.com Git - lilypond.git/blob - lily/beam.cc
release: 0.0.39-1
[lilypond.git] / lily / beam.cc
1 #include "varray.hh"
2
3 #include "dimen.hh"
4 #include "beam.hh"
5 #include "misc.hh"
6 #include "debug.hh"
7 #include "symbol.hh"
8 #include "molecule.hh"
9 #include "leastsquares.hh"
10 #include "pcol.hh"
11 #include "stem.hh"
12 #include "paper-def.hh"
13 #include "lookup.hh"
14 #include "grouping.hh"
15
16
17
18 struct Stem_info {
19     Real x;
20     Real idealy;
21     Real miny;
22     int no_beams;
23
24     
25     Stem_info(){}
26     Stem_info(const Stem*);
27 };
28
29 Stem_info::Stem_info(const Stem*s)
30 {
31     x = s->hindex();
32     int dir = s->dir;
33     idealy  = max(dir*s->top, dir*s->bot);
34     miny = max(dir*s->minnote, dir*s-> maxnote);
35     assert(miny <= idealy);
36
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 = 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 = 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         Stem_info info(i);
90         sinfo.push(info);
91     }
92     Real leftx = sinfo[0].x;
93     Least_squares l;
94     for (int i=0; i < sinfo.size(); i++) {
95         sinfo[i].x -= leftx;
96         l.input.push(Offset(sinfo[i].x, sinfo[i].idealy));
97     }
98
99     l.minimise(slope, left_pos);
100     Real dy = 0.0;
101     for (int i=0; i < sinfo.size(); i++) {
102         Real y = sinfo[i].x * slope + left_pos;
103         Real my = sinfo[i].miny;
104
105         if (my - y > dy)
106             dy = my -y; 
107     }
108     left_pos += dy;
109     left_pos *= dir_i_;    
110     slope *= dir_i_;
111
112                                 // URG
113     Real sl = slope*paper()->internote();
114     paper()->lookup_p_->beam(sl, 20 PT);
115     slope = sl /paper()->internote();
116 }
117
118 void
119 Beam::set_stemlens()
120 {
121     iter_top(stems,s);
122     Real x0 = s->hindex();    
123     for (; s.ok() ; s++) {
124         Real x =  s->hindex()-x0;
125         s->set_stemend(left_pos + slope * x);   
126     }
127 }
128
129
130 void
131 Beam::do_post_processing()
132 {
133     solve_slope();    
134     set_stemlens();
135 }
136
137 void
138 Beam::set_grouping(Rhythmic_grouping def, Rhythmic_grouping cur)
139 {
140     def.OK();
141     cur.OK();
142     assert(cur.children.size() == stems.size());
143     
144     cur.split(def);
145
146     Array<int> b;
147     {
148         iter_top(stems,s);
149         Array<int> flags;
150         for (; s.ok(); s++) {
151             int f = intlog2(abs(s->flag))-2;
152             assert(f>0);
153             flags.push(f);
154         }
155         int fi =0;
156         b= cur.generate_beams(flags, fi);
157         b.insert(0,0);
158         b.push(0);
159         assert(stems.size() == b.size()/2);
160     }
161
162     iter_top(stems,s);
163     for (int i=0; i < b.size() && s.ok(); i+=2, s++) {
164         s->beams_left = b[i];
165         s->beams_right = b[i+1];
166     }
167 }
168
169
170 // todo.
171 Spanner *
172 Beam::do_break_at( PCol *, PCol *) const
173 {
174     Beam *beam_p= new Beam(*this);
175     
176     return beam_p;
177 }
178
179 void
180 Beam::do_pre_processing()
181 {
182     left  = (*stems.top())   ->pcol_l_;
183     right = (*stems.bottom())->pcol_l_;    
184     assert(stems.size()>1);
185     if (!dir_i_)
186         set_default_dir();
187
188 }
189
190
191 Interval
192 Beam::width() const
193 {
194     Beam * me = (Beam*) this;   // ugh
195     return Interval( (*me->stems.top()) ->hindex(),
196                      (*me->stems.bottom()) ->hindex() );
197 }
198
199 /*
200   beams to go with one stem.
201   */
202 Molecule
203 Beam::stem_beams(Stem *here, Stem *next, Stem *prev)const
204 {
205     assert( !next || next->hindex() > here->hindex()  );
206     assert( !prev || prev->hindex() < here->hindex()  );
207     Real dy=paper()->internote()*2;
208     Real stemdx = paper()->rule_thickness();
209     Real sl = slope*paper()->internote();
210     paper()->lookup_p_->beam(sl, 20 PT);
211
212     Molecule leftbeams;
213     Molecule rightbeams;
214
215     /* half beams extending to the left. */
216     if (prev) {
217         int lhalfs= lhalfs = here->beams_left - prev->beams_right ;
218         int lwholebeams= here->beams_left <? prev->beams_right ;
219         Real w = (here->hindex() - prev->hindex())/4;
220         Symbol dummy;
221         Atom a(dummy);
222         if (lhalfs)             // generates warnings if not
223             a =  paper()->lookup_p_->beam(sl, w);
224         a.translate(Offset (-w, -w * sl));
225         for (int j = 0; j  < lhalfs; j++) {
226             Atom b(a);
227             b.translate(Offset(0, -dir_i_ * dy * (lwholebeams+j)));
228             leftbeams.add( b );
229         }
230     }
231         
232     if (next){
233         int rhalfs = here->beams_right - next->beams_left;
234         int rwholebeams = here->beams_right <? next->beams_left; 
235
236         Real w = next->hindex() - here->hindex();
237         Atom a = paper()->lookup_p_->beam(sl, w + stemdx);
238         
239         int j = 0;
240         for (; j  < rwholebeams; j++) {
241             Atom b(a);
242             b.translate(Offset(0, -dir_i_ * dy * j));
243             rightbeams.add( b ); 
244         }
245
246         w /= 4;
247         if (rhalfs)
248             a = paper()->lookup_p_->beam(sl, w);
249         
250         for (; j  < rwholebeams + rhalfs; j++) {
251             Atom b(a);
252             b.translate(Offset(0, -dir_i_ * dy * j));
253             rightbeams.add(b ); 
254         }
255         
256     }
257     leftbeams.add(rightbeams);
258     return leftbeams;
259 }
260
261
262 Molecule*
263 Beam::brew_molecule_p() const return out;
264 {
265     Real inter=paper()->internote();
266     out = new Molecule;
267     Real x0 = stems.top()->hindex();
268     
269     for (iter_top(stems,i); i.ok(); i++) {
270         PCursor<Stem*> p(i-1);
271         PCursor<Stem*> n(i+1);
272         Stem * prev = p.ok() ? p.ptr() : 0;
273         Stem * next = n.ok() ? n.ptr() : 0;
274
275         Molecule sb = stem_beams(i, next, prev);
276         Real  x = i->hindex()-x0;
277         sb.translate(Offset(x, (x * slope  + left_pos)* inter));
278         out->add(sb);
279     }
280     out->translate(Offset(x0 - left->hpos,0));
281 }
282
283 void
284 Beam::do_print()const
285 {
286 #ifndef NPRINT
287     mtor << "slope " <<slope << "left ypos " << left_pos;
288     Spanner::print();
289 #endif
290 }
291
292 Beam::~Beam()
293 {
294
295 }