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