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