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