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