lilypond-1.5.8
[lilypond.git] / src / beam.cc
blob64f3e3cf775aa721316b216328443bcc8b468584
1 #include "varray.hh"
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"
18 struct Stem_info {
19 Real x;
20 Real idealy;
21 Real miny;
22 int no_beams;
25 Stem_info(){}
26 Stem_info(const Stem*);
29 Stem_info::Stem_info(const Stem*s)
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);
39 /* *************** */
41 Offset
42 Beam::center()const
44 assert(status >= POSTCALCED);
46 Real w=(paper()->note_width() + width().length())/2.0;
47 return Offset(w, (left_pos + w* slope)*paper()->internote());
51 Beam::Beam()
53 slope = 0;
54 left_pos = 0.0;
57 void
58 Beam::add(Stem*s)
60 stems.bottom().add(s);
61 s->add_dependency(this);
62 s->print_flag = false;
65 void
66 Beam::set_default_dir()
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] ++;
74 dir_i_ = (dirs[0] > dirs[1]) ? -1 : 1;
75 for (iter_top(stems,i); i.ok(); i++) {
76 i->dir = dir_i_;
81 should use minimum energy formulation (cf linespacing)
83 void
84 Beam::solve_slope()
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);
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));
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;
105 if (my - y > dy)
106 dy = my -y;
108 left_pos += dy;
109 left_pos *= dir_i_;
110 slope *= dir_i_;
112 // URG
113 Real sl = slope*paper()->internote();
114 paper()->lookup_p_->beam(sl, 20 PT);
115 slope = sl /paper()->internote();
118 void
119 Beam::set_stemlens()
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);
130 void
131 Beam::do_post_processing()
133 solve_slope();
134 set_stemlens();
137 void
138 Beam::set_grouping(Rhythmic_grouping def, Rhythmic_grouping cur)
140 def.OK();
141 cur.OK();
142 assert(cur.children.size() == stems.size());
144 cur.split(def);
146 Array<int> b;
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);
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);
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];
170 // todo.
171 Spanner *
172 Beam::do_break_at( PCol *, PCol *) const
174 Beam *beam_p= new Beam(*this);
176 return beam_p;
179 void
180 Beam::do_pre_processing()
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();
191 Interval
192 Beam::width() const
194 Beam * me = (Beam*) this; // ugh
195 return Interval( (*me->stems.top()) ->hindex(),
196 (*me->stems.bottom()) ->hindex() );
200 beams to go with one stem.
202 Molecule
203 Beam::stem_beams(Stem *here, Stem *next, Stem *prev)const
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);
212 Molecule leftbeams;
213 Molecule rightbeams;
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 );
232 if (next){
233 int rhalfs = here->beams_right - next->beams_left;
234 int rwholebeams = here->beams_right <? next->beams_left;
236 Real w = next->hindex() - here->hindex();
237 Atom a = paper()->lookup_p_->beam(sl, w + stemdx);
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 );
246 w /= 4;
247 if (rhalfs)
248 a = paper()->lookup_p_->beam(sl, w);
250 for (; j < rwholebeams + rhalfs; j++) {
251 Atom b(a);
252 b.translate(Offset(0, -dir_i_ * dy * j));
253 rightbeams.add(b );
257 leftbeams.add(rightbeams);
258 return leftbeams;
262 Molecule*
263 Beam::brew_molecule_p() const return out;
265 Real inter=paper()->internote();
266 out = new Molecule;
267 Real x0 = stems.top()->hindex();
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;
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);
280 out->translate(Offset(x0 - left->hpos,0));
283 void
284 Beam::do_print()const
286 #ifndef NPRINT
287 mtor << "slope " <<slope << "left ypos " << left_pos;
288 Spanner::print();
289 #endif
292 Beam::~Beam()